Skip to content

Commit

Permalink
feat(explorer): add existing element to attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
emile committed Jan 31, 2025
1 parent 34ccaf1 commit 7346d50
Show file tree
Hide file tree
Showing 9 changed files with 262 additions and 20 deletions.
15 changes: 6 additions & 9 deletions libs/ui/src/components/Explorer/DataView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const DataViewContainerDivStyled = styled.div`
.pagination {
flex: 0 0 auto;
justify-content: flex-end;
justify-content: center;
display: flex;
padding-top: calc(var(--general-spacing-xs) * 1px);
}
Expand Down Expand Up @@ -61,6 +61,7 @@ const StyledTable = styled(KitTable)`
interface IDataViewProps {
dataGroupedFilteredSorted: IItemData[];
itemActions: IItemAction[];
iconsOnlyItemActions: boolean;
attributesProperties: IExplorerData['attributes'];
attributesToDisplay: string[];
paginationProps?: {
Expand Down Expand Up @@ -101,9 +102,9 @@ export const DataView: FunctionComponent<IDataViewProps> = memo(
paginationProps,
itemActions,
selection: {onSelectionChange, selectedKeys, isMassSelectionAll}
iconsOnlyItemActions
}) => {
const {t} = useSharedTranslation();
const {theme} = useKitTheme();

const {containerRef, scrollHeight} = useTableScrollableHeight(!!paginationProps);
const {ref, getFieldColumnWidth, columnWidth} = useColumnWidth();
Expand All @@ -114,7 +115,6 @@ export const DataView: FunctionComponent<IDataViewProps> = memo(
): ReactNode => {
const isLessThanFourActions = actions.length < 4;

return (
<StyledActionsList ref={columnRef}>
{isLessThanFourActions ? (
<>
Expand All @@ -127,7 +127,7 @@ export const DataView: FunctionComponent<IDataViewProps> = memo(
danger={isDanger}
disabled={disabled}
>
{label}
{!iconsOnlyItemActions && !iconOnly && label}
</KitButton>
))}
</>
Expand All @@ -136,8 +136,8 @@ export const DataView: FunctionComponent<IDataViewProps> = memo(
<KitButton
type="tertiary"
icon={actions[0].icon}
onClick={actions[0].callback}
title={actions[0].label}
onClick={actions[0].callback}
danger={actions[0].isDanger}
disabled={actions[0].disabled}
/>
Expand Down Expand Up @@ -235,10 +235,7 @@ export const DataView: FunctionComponent<IDataViewProps> = memo(
// TODO: handle columns width based on attribute type/format
return (
<DataViewContainerDivStyled ref={containerRef}>
<StyledTable
borderedRows
cellsBackgroundColor={theme.utilities.light}
backgroundColor={theme.colors.primary['50']}
<KitTable
showHeader={dataGroupedFilteredSorted.length > 0}
columns={columns}
tableLayout="fixed"
Expand Down
30 changes: 25 additions & 5 deletions libs/ui/src/components/Explorer/Explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import {usePagination} from './usePagination';
import {useViewSettingsReducer} from './useViewSettingsReducer';
import {useDeactivateMassAction} from './useDeactivateMassAction';
import {MASS_SELECTION_ALL} from './_constants';
import {useAddItemAction} from './useAddItemAction';
import {concat} from '@apollo/client';

const isNotEmpty = <T extends unknown[]>(union: T): union is Exclude<T, []> => union.length > 0;

Expand All @@ -41,6 +43,7 @@ const ExplorerHeaderDivStyled = styled.div`
align-items: center;
padding-bottom: calc(var(--general-spacing-xs) * 1px);
padding-right: calc(var(--general-spacing-xxs) * 1px);
padding-top: calc(var(--general-spacing-xxs) * 1px);
`;

const ExplorerPageDivStyled = styled.div`
Expand All @@ -50,10 +53,11 @@ const ExplorerPageDivStyled = styled.div`
overflow: hidden;
`;

interface IExplorerProps {
export interface IExplorerProps {
entrypoint: Entrypoint;
noPagination?: true;
itemActions?: IItemAction[];
iconsOnlyItemActions?: boolean;
primaryActions?: IPrimaryAction[];
massActions?: IMassActions[];
title?: string;
Expand All @@ -62,6 +66,7 @@ interface IExplorerProps {
defaultPrimaryActions?: Array<'create'>;
defaultMassActions?: Array<'deactivate'>;
defaultViewSettings?: DefaultViewSettings;
panelElement?: () => HTMLElement;
}

export const Explorer: FunctionComponent<IExplorerProps> = ({
Expand All @@ -72,14 +77,19 @@ export const Explorer: FunctionComponent<IExplorerProps> = ({
massActions = [],
title,
emptyPlaceholder,
noPagination,
iconsOnlyItemActions = false,
defaultActionsForItem = ['edit', 'remove'],
defaultPrimaryActions = ['create'],
defaultMassActions = ['deactivate'],
defaultViewSettings
defaultViewSettings,
defaultMassActions = ['deactivate'],
defaultViewSettings,
panelElement
}) => {
const {t} = useSharedTranslation();

const {panelElement} = useEditSettings();
const {panelElement: settingsPanelElement} = useEditSettings();

const {loading: viewSettingsLoading, view, dispatch} = useViewSettingsReducer(entrypoint, defaultViewSettings);

Expand Down Expand Up @@ -122,6 +132,13 @@ export const Explorer: FunctionComponent<IExplorerProps> = ({

const totalCount = data?.totalCount ?? 0;
const allVisibleKeys = data?.records.map(({key}) => key) ?? [];
const {addItemAction, addItemModal} = useAddItemAction({
isEnabled: entrypoint.type === 'link',
library: view.libraryId,
entrypoint: view.entrypoint,
maxItemsLeft: null,
refetch
});

const {deactivateMassAction} = useDeactivateMassAction({
isEnabled: isNotEmpty(defaultMassActions) && defaultMassActions.includes('deactivate'),
Expand Down Expand Up @@ -150,7 +167,7 @@ export const Explorer: FunctionComponent<IExplorerProps> = ({
<ViewSettingsContext.Provider value={{view, dispatch}}>
<ExplorerPageDivStyled>
<ExplorerHeaderDivStyled>
<KitTypography.Title level="h1">
<KitTypography.Title level="h3">
{
!viewSettingsLoading && (
<ExplorerTitle library={view.libraryId} title={title} entrypoint={entrypoint} />
Expand Down Expand Up @@ -179,6 +196,7 @@ export const Explorer: FunctionComponent<IExplorerProps> = ({
dataGroupedFilteredSorted={data?.records ?? emptyArray}
attributesProperties={data?.attributes ?? emptyObject}
attributesToDisplay={['whoAmI', ...view.attributesIds]}
iconsOnlyItemActions={iconsOnlyItemActions}
paginationProps={
entrypoint.type === 'library'
? {
Expand All @@ -205,9 +223,11 @@ export const Explorer: FunctionComponent<IExplorerProps> = ({
/>
)}
</ExplorerPageDivStyled>
{panelElement && createPortal(<SidePanel />, panelElement)}
{(panelElement || settingsPanelElement) &&
createPortal(<SidePanel />, panelElement ? panelElement() : (settingsPanelElement ?? document.body))}
{editModal}
{createModal}
{addItemModal}
</ViewSettingsContext.Provider>
);
};
3 changes: 3 additions & 0 deletions libs/ui/src/components/Explorer/ExplorerToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ const ExplorerToolbarListStyled = styled.ul`
padding: calc(var(--general-spacing-xs) * 1px) calc(var(--general-spacing-xxs) * 1px)
calc(var(--general-spacing-m) * 1px) calc(var(--general-spacing-xxs) * 1px);
margin: 0;
margin-bottom: calc(var(--general-spacing-s) * 1px);
background: var(--general-colors-neutral-grey-100);
border-radius: calc(var(--general-border-radius-s) * 1px);
list-style: none;
display: flex;
overflow: auto;
Expand Down
1 change: 1 addition & 0 deletions libs/ui/src/components/Explorer/_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface IItemAction {
callback: (item: IItemData) => void;
icon: ReactElement;
label: string;
iconOnly?: boolean;
isDanger?: boolean;
disabled?: boolean;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// Copyright LEAV Solutions 2017 until 2023/11/05, Copyright Aristid from 2023/11/06
// This file is released under LGPL V3
// License text available at https://www.gnu.org/licenses/lgpl-3.0.txt
import {Modal} from 'antd';
import {FunctionComponent, useRef} from 'react';
import {KitButton, KitModal, KitSpace} from 'aristid-ds';
import styled from 'styled-components';
import {useSharedTranslation} from '_ui/hooks/useSharedTranslation';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faXmark} from '@fortawesome/free-solid-svg-icons';
import {Explorer, IExplorerProps} from '../Explorer';
import {possibleSubmitButtons} from '_ui/components/RecordEdition/_types';
import {IEntrypointLibrary, IEntrypointLink} from '../_types';
import {FaPlus} from 'react-icons/fa';
import useSaveValueBatchMutation from '_ui/components/RecordEdition/EditRecordContent/hooks/useExecuteSaveValueBatchMutation';
import {EditSettingsContextProvider} from '../manage-view-settings';

export interface IDisplayExplorerModalProps extends Omit<IExplorerProps, 'entrypoint'> {
open: boolean;
library: string;
entrypoint: IEntrypointLink;
onClose: () => void;
submitButtons?: possibleSubmitButtons;
}

const modalWidth = 1200;
const StyledModal = styled(Modal)`
&& {
.ant-modal-content {
display: flex;
flex-direction: column;
padding: 10px;
overflow: hidden;
}
.ant-modal-footer {
flex: 0 0 auto;
margin-top: 0;
}
}
`;

const ModalMainStyledDiv = styled.div`
padding: calc(var(--general-spacing-m) * 1px);
height: 100%;
position: relative;
`;

const Header = styled.div`
height: 3.5rem;
grid-area: title;
align-self: center;
font-size: 1rem;
padding: 10px 50px 10px 10px;
border-bottom: 1px solid var(--general-utilities-border);
display: flex;
justify-content: space-between;
align-items: center;
`;

const ModalFooter = styled.div`
display: flex;
justify-content: flex-end;
padding: 0.5rem 1rem;
border-top: 1px solid var(--general-utilities-border);
`;

export const DisplayExplorerModal: FunctionComponent<IDisplayExplorerModalProps> = ({
open,
library,
entrypoint,
title,
defaultViewSettings,
onClose
}) => {
const {t} = useSharedTranslation();
const explorerContainerRef = useRef<HTMLDivElement>(null);
const {saveValues} = useSaveValueBatchMutation();

const _handleClose = () => onClose();

const _closeButtonLabel = t('global.close');

const _footerButtons = [
<KitButton
aria-label={_closeButtonLabel}
key="close"
icon={<FontAwesomeIcon icon={faXmark} />}
onClick={_handleClose}
>
{_closeButtonLabel}
</KitButton>
];

const _footer = (
<ModalFooter>
<KitSpace>{_footerButtons}</KitSpace>
</ModalFooter>
);

const _internalEntrypoint: IEntrypointLibrary = {
type: 'library',
libraryId: library
};

const addItemAction = {
label: t('filters.add'),
icon: <FaPlus />,
callback: ({itemId}) =>
saveValues(
{
id: entrypoint.parentRecordId,
library: {
id: entrypoint.parentLibraryId
}
},
[
{
attribute: entrypoint.linkAttributeId,
idValue: null,
value: itemId
}
]
)
};

return (
<StyledModal
open={open}
onCancel={_handleClose}
destroyOnClose
closable={false}
cancelText={t('global.cancel')}
width="90vw"
centered
style={{maxWidth: `${modalWidth}px`}}
styles={{body: {height: 'calc(100vh - 12rem)', overflowY: 'auto'}, content: {padding: 0}}}
footer={_footer}
>
<ModalMainStyledDiv ref={explorerContainerRef}>
<EditSettingsContextProvider>
<Explorer
entrypoint={_internalEntrypoint}
primaryActions={[]}
title={title}
defaultActionsForItem={[]}
itemActions={[addItemAction]}
defaultPrimaryActions={[]}
panelElement={() => explorerContainerRef.current ?? document.body}
defaultViewSettings={defaultViewSettings}
/>
</EditSettingsContextProvider>
</ModalMainStyledDiv>
</StyledModal>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ export const useOpenViewSettings = (library: string) => {
openSettingsPanel: _openSettingsPanel,
viewSettingsButton: (
<KitButton
type="tertiary"
color="neutral"
type="secondary"
icon={<FaSlidersH />}
onClick={() => _openSettingsPanel()}
title={String(t('explorer.settings')) /* TODO: avoid transform null to 'null' */}
Expand Down
Loading

0 comments on commit 7346d50

Please sign in to comment.