Skip to content

Commit

Permalink
feat(@leav/ui): move to actions folder
Browse files Browse the repository at this point in the history
  • Loading branch information
P0ppoff committed Feb 7, 2025
1 parent b19eff0 commit 869792b
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 100 deletions.
2 changes: 1 addition & 1 deletion libs/ui/src/components/Explorer/DataView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// This file is released under LGPL V3
// License text available at https://www.gnu.org/licenses/lgpl-3.0.txt
import {cloneElement, ComponentProps, FunctionComponent, memo, ReactNode} from 'react';
import {KitButton, KitDropDown, KitPagination, KitSpace, KitTable, useKitTheme} from 'aristid-ds';
import {KitButton, KitDropDown, KitPagination, KitTable} from 'aristid-ds';
import type {KitTableColumnType} from 'aristid-ds/dist/Kit/DataDisplay/Table/types';
import {FaEllipsisH} from 'react-icons/fa';
import {Override} from '@leav/utils';
Expand Down
15 changes: 8 additions & 7 deletions libs/ui/src/components/Explorer/Explorer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {Explorer} from '_ui/index';
import {IEntrypointLibrary, IEntrypointLink, IItemAction, IPrimaryAction} from './_types';
import * as useExecuteSaveValueBatchMutation from '../RecordEdition/EditRecordContent/hooks/useExecuteSaveValueBatchMutation';
import * as useColumnWidth from './useColumnWidth';
import {AddLinkModal} from './link-item/AddLinkModal';
import {LinkModal} from './link-item/LinkModal';
import {FunctionComponent} from 'react';
import {IViewSettingsState, ViewSettingsContext, viewSettingsInitialState} from './manage-view-settings';
import {useViewSettingsReducer} from './useViewSettingsReducer';
Expand Down Expand Up @@ -1574,15 +1574,15 @@ describe('Explorer', () => {
});
});

describe('Add link modal', () => {
test('Should be able to add existing item to atribute', async () => {
describe('Link modal', () => {
test('Should be able to link existing item to parent record and create linked attribute', async () => {
const viewInitialState = {
...viewSettingsInitialState,
entrypoint: linkEntrypoint
entrypoint: {...libraryEntrypoint, libraryId: explorerLinkAttribute.linked_library.id}
};

const fetch = jest.fn();
const selecionIdsImplementation = [
const selectionIdsImplementation = [
fetch,
{
loading: false,
Expand All @@ -1591,12 +1591,13 @@ describe('Explorer', () => {
];

jest.spyOn(gqlTypes, 'useExplorerSelectionIdsLazyQuery').mockImplementation(
() => selecionIdsImplementation as gqlTypes.ExplorerSelectionIdsLazyQueryHookResult
() => selectionIdsImplementation as gqlTypes.ExplorerSelectionIdsLazyQueryHookResult
);

// TODO: review mock/spy logic
render(
<MockViewSettingsContextProvider viewMock={viewInitialState}>
<AddLinkModal open library={explorerLinkAttribute.linked_library.id} />
<LinkModal open onClose={jest.fn()} />
</MockViewSettingsContextProvider>,
{
mocks: [ExplorerLinkAttributeQueryMock]
Expand Down
42 changes: 22 additions & 20 deletions libs/ui/src/components/Explorer/Explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import {useExplorerData} from './_queries/useExplorerData';
import {DataView} from './DataView';
import {ExplorerTitle} from './ExplorerTitle';
import {ExplorerToolbar} from './ExplorerToolbar';
import {useRemoveAction} from './useRemoveAction';
import {useEditAction} from './useEditAction';
import {usePrimaryActionsButton} from './usePrimaryActions';
import {useCreateAction} from './useCreateAction';
import {useMassActions} from './useMassActions';
import {useRemoveItemAction} from './actions-item/useRemoveItemAction';
import {useEditItemAction} from './actions-item/useEditItemAction';
import {usePrimaryActionsButton} from './actions-primary/usePrimaryActions';
import {useCreatePrimaryAction} from './actions-primary/useCreatePrimaryAction';
import {useLinkPrimaryAction} from './actions-primary/useLinkPrimaryAction';
import {useMassActions} from './actions-mass/useMassActions';
import {useDeactivateMassAction} from './actions-mass/useDeactivateMassAction';
import {
defaultPageSizeOptions,
SidePanel,
Expand All @@ -27,9 +29,7 @@ import {
import {useSearchInput} from './useSearchInput';
import {usePagination} from './usePagination';
import {useViewSettingsReducer} from './useViewSettingsReducer';
import {useDeactivateMassAction} from './useDeactivateMassAction';
import {MASS_SELECTION_ALL} from './_constants';
import {useAddItemAction} from './useAddItemAction';

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

Expand Down Expand Up @@ -114,31 +114,31 @@ export const Explorer: FunctionComponent<IExplorerProps> = ({

const isMassSelectionAll = view.massSelection === MASS_SELECTION_ALL;

const {removeAction} = useRemoveAction({
const {removeItemAction} = useRemoveItemAction({
isEnabled: isNotEmpty(defaultActionsForItem) && defaultActionsForItem.includes('remove'),
store: {view, dispatch},
entrypoint
});

const {editAction, editModal} = useEditAction({
const {editItemAction, editItemModal} = useEditItemAction({
isEnabled: isNotEmpty(defaultActionsForItem) && defaultActionsForItem.includes('edit')
});

const {createAction, createModal} = useCreateAction({
const totalCount = data?.totalCount ?? 0;

const {createPrimaryAction, createModal} = useCreatePrimaryAction({
isEnabled: isNotEmpty(defaultPrimaryActions) && defaultPrimaryActions.includes('create'),
library: view.libraryId,
libraryId: view.libraryId,
entrypoint: view.entrypoint,
itemsCount: data?.totalCount ?? 0,
totalCount,
refetch
});

const {linkItemsAction, linkItemsModal} = useAddItemAction({
const {linkPrimaryAction, linkModal} = useLinkPrimaryAction({
isEnabled: entrypoint.type === 'link',
library: view.libraryId,
maxItemsLeft: null
maxItemsLeft: null // TODO: use KitTable.row
});

const totalCount = data?.totalCount ?? 0;
const allVisibleKeys = data?.records.map(({key}) => key) ?? [];

const {deactivateMassAction} = useDeactivateMassAction({
Expand All @@ -156,7 +156,9 @@ export const Explorer: FunctionComponent<IExplorerProps> = ({
massActions: [deactivateMassAction, ...massActions].filter(Boolean)
});

const {primaryButton} = usePrimaryActionsButton([createAction, linkItemsAction, ...primaryActions].filter(Boolean));
const {primaryButton} = usePrimaryActionsButton(
[createPrimaryAction, linkPrimaryAction, ...primaryActions].filter(Boolean)
);

const {viewSettingsButton} = useOpenViewSettings(view.libraryId);

Expand Down Expand Up @@ -212,7 +214,7 @@ export const Explorer: FunctionComponent<IExplorerProps> = ({
}
: undefined
}
itemActions={[editAction, removeAction, ...itemActions].filter(Boolean).map(action => ({
itemActions={[editItemAction, removeItemAction, ...itemActions].filter(Boolean).map(action => ({
...action,
disabled: isMassSelectionAll
}))}
Expand All @@ -227,9 +229,9 @@ export const Explorer: FunctionComponent<IExplorerProps> = ({
)}
</ExplorerPageDivStyled>
{settingsPanelElement && createPortal(<SidePanel />, settingsPanelElement?.() ?? document.body)}
{editModal}
{editItemModal}
{createModal}
{linkItemsModal}
{linkModal}
</ViewSettingsContext.Provider>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {FaPen} from 'react-icons/fa';
import {useSharedTranslation} from '_ui/hooks/useSharedTranslation';
import {EditRecordModal} from '_ui/components/RecordEdition/EditRecordModal';
import {RecordFilterCondition, useExplorerLibraryDataLazyQuery} from '_ui/_gqlTypes';
import {ActionHook, IItemAction, IItemData} from './_types';
import {ActionHook, IItemAction, IItemData} from '../_types';

/**
* Hook used to get the action for `<DataView />` component.
Expand All @@ -18,14 +18,14 @@ import {ActionHook, IItemAction, IItemData} from './_types';
*
* @param isEnabled - whether the action is present
*/
export const useEditAction = ({isEnabled}: ActionHook) => {
export const useEditItemAction = ({isEnabled}: ActionHook) => {
const {t} = useSharedTranslation();

const [refreshItem] = useExplorerLibraryDataLazyQuery({fetchPolicy: 'network-only'});

const [editingItem, setEditingItem] = useState<null | IItemData>(null);

const _editAction: IItemAction = {
const _editItemAction: IItemAction = {
label: t('explorer.edit-item'),
icon: <FaPen />,
callback: item => {
Expand Down Expand Up @@ -53,8 +53,8 @@ export const useEditAction = ({isEnabled}: ActionHook) => {

const editAction = useMemo(
() => ({
editAction: isEnabled ? _editAction : null,
editModal:
editItemAction: isEnabled ? _editItemAction : null,
editItemModal:
isEnabled && editingItem !== null ? (
<EditRecordModal
open
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,9 @@ import {KitModal} from 'aristid-ds';
import {useDeactivateRecordsMutation, useDeleteValueMutation} from '_ui/_gqlTypes';
import {useSharedTranslation} from '_ui/hooks/useSharedTranslation';
import {useValuesCacheUpdate} from '_ui/hooks/useValuesCacheUpdate';
import {ActionHook, Entrypoint, IEntrypointLink, IItemAction} from './_types';
import {
IViewSettingsAction,
IViewSettingsState,
ViewSettingsActionTypes
} from '_ui/components/Explorer/manage-view-settings';
import {MASS_SELECTION_ALL} from '_ui/components/Explorer/_constants';
import {ActionHook, Entrypoint, IEntrypointLink, IItemAction} from '../_types';
import {IViewSettingsAction, IViewSettingsState, ViewSettingsActionTypes} from '../manage-view-settings';
import {MASS_SELECTION_ALL} from '../_constants';

/**
* Hook used to get the action for `<DataView />` component.
Expand All @@ -26,7 +22,7 @@ import {MASS_SELECTION_ALL} from '_ui/components/Explorer/_constants';
* @param dispatch - method to change the current view
* @param entrypoint - represent the current entrypoint
*/
export const useRemoveAction = ({
export const useRemoveItemAction = ({
isEnabled,
store: {view, dispatch},
entrypoint
Expand Down Expand Up @@ -72,7 +68,7 @@ export const useRemoveAction = ({
}
});

const _removeAction: IItemAction = useMemo(
const _removeItemAction: IItemAction = useMemo(
() => ({
label: entrypoint.type === 'library' ? t('explorer.deactivate-item') : t('explorer.delete-item'),
icon: <FaTrash />,
Expand Down Expand Up @@ -126,6 +122,6 @@ export const useRemoveAction = ({
);

return {
removeAction: isEnabled ? _removeAction : null
removeItemAction: isEnabled ? _removeItemAction : null
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import {FaTrash} from 'react-icons/fa';
import {KitModal} from 'aristid-ds';
import {useDeactivateRecordsMutation} from '_ui/_gqlTypes';
import {useSharedTranslation} from '_ui/hooks/useSharedTranslation';
import {ActionHook, IMassActions} from './_types';
import {IViewSettingsAction, IViewSettingsState, ViewSettingsActionTypes} from './manage-view-settings';
import {MASS_SELECTION_ALL} from './_constants';
import type {useExplorerData} from './_queries/useExplorerData';
import {ActionHook, IMassActions} from '../_types';
import {IViewSettingsAction, IViewSettingsState, ViewSettingsActionTypes} from '../manage-view-settings';
import {MASS_SELECTION_ALL} from '../_constants';
import type {useExplorerData} from '../_queries/useExplorerData';

/**
* Hook used to get the action for mass actions only available on selection.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import {FaChevronDown} from 'react-icons/fa';
import {RecordFilterCondition, RecordFilterOperator} from '_ui/_gqlTypes';
import {useSharedTranslation} from '_ui/hooks/useSharedTranslation';
import {interleaveElement} from '_ui/_utils/interleaveElement';
import {IMassActions} from './_types';
import {MASS_SELECTION_ALL} from './_constants';
import {IViewSettingsAction, IViewSettingsState, ViewSettingsActionTypes} from './manage-view-settings';
import {prepareFiltersForRequest} from './_queries/prepareFiltersForRequest';
import {MassSelection} from './manage-view-settings/store-view-settings/viewSettingsReducer';
import {IMassActions} from '../_types';
import {MASS_SELECTION_ALL} from '../_constants';
import {IViewSettingsAction, IViewSettingsState, ViewSettingsActionTypes} from '../manage-view-settings';
import {prepareFiltersForRequest} from '../_queries/prepareFiltersForRequest';
import {MassSelection} from '../manage-view-settings/store-view-settings/viewSettingsReducer';

/**
* Hook used to manage mass selection as the snackbar and all kind of selection (manual, all in page, all in filters)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import {useState} from 'react';
import {FaPlus} from 'react-icons/fa';
import {EditRecordModal} from '_ui/components';
import {useSharedTranslation} from '_ui/hooks/useSharedTranslation';
import {ActionHook, Entrypoint, IEntrypointLink, IPrimaryAction} from './_types';
import useSaveValueBatchMutation from '_ui/components/RecordEdition/EditRecordContent/hooks/useExecuteSaveValueBatchMutation';
import {useExplorerLinkAttributeQuery} from '_ui/_gqlTypes';
import {ActionHook, Entrypoint, IEntrypointLink, IPrimaryAction} from '../_types';

/**
* Hook used to get the action for `<DataView />` component.
Expand All @@ -17,19 +17,21 @@ import {useExplorerLinkAttributeQuery} from '_ui/_gqlTypes';
* It returns also two parts : one for the call action button - one for displayed the modal required by the action.
*
* @param isEnabled - whether the action is present
* @param library - the library's id to add new item
* @param libraryId - the library's id to add new item
* @param entrypoint - represent the current entrypoint
* @param totalCount - used for display purpose only
* @param refetch - method to call to refresh the list. New item will be visible if it matches filters and sorts
*/
export const useCreateAction = ({
export const useCreatePrimaryAction = ({
isEnabled,
library,
libraryId,
entrypoint,
itemsCount,
totalCount,
refetch
}: ActionHook<{
library: string;
libraryId: string;
entrypoint: Entrypoint;
itemsCount: number;
totalCount: number;
refetch: () => void;
}>) => {
const {t} = useSharedTranslation();
Expand All @@ -52,9 +54,9 @@ export const useCreateAction = ({
}
});

const canCreateRecord = entrypoint.type === 'library' ? true : multipleValues || itemsCount === 0;
const canCreateRecord = entrypoint.type === 'library' ? true : multipleValues || totalCount === 0;

const createAction: IPrimaryAction = {
const _createPrimaryAction: IPrimaryAction = {
callback: () => {
setRecordCreationVisible(true);
},
Expand All @@ -64,12 +66,12 @@ export const useCreateAction = ({
};

return {
createAction: isEnabled ? createAction : null,
createPrimaryAction: isEnabled ? _createPrimaryAction : null,
createModal: isRecordCreationVisible ? (
<EditRecordModal
open
record={null}
library={library}
library={libraryId}
onClose={() => {
setRecordCreationVisible(false);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import {useState} from 'react';
import {FaPlus} from 'react-icons/fa';
import {useSharedTranslation} from '_ui/hooks/useSharedTranslation';
import {ActionHook, IPrimaryAction} from './_types';
import {AddLinkModal} from './link-item/AddLinkModal';
import {ActionHook, IPrimaryAction} from '../_types';
import {LinkModal} from '../link-item/LinkModal';

/**
* Hook used to get the action for `<DataView />` component.
Expand All @@ -15,40 +15,36 @@ import {AddLinkModal} from './link-item/AddLinkModal';
* It returns also two parts : one for the call action button - one for displaying the modal required by the action.
*
* @param isEnabled - whether the action is present
* @param library - the library's id to add new item
* @param maxItemsLeft - the number of items that can be added
*/
export const useAddItemAction = ({
export const useLinkPrimaryAction = ({
isEnabled,
library,
maxItemsLeft
}: ActionHook<{
library: string;
maxItemsLeft: number | null;
}>) => {
const {t} = useSharedTranslation();

const [isLinkItemsModalVisible, setIsLinkItemsModalVisible] = useState(false);
const [isLinkModalVisible, setIsLinkModalVisible] = useState(false);

const disableAddItemAction = maxItemsLeft === 0;

const linkItemsAction: IPrimaryAction = {
const _linkPrimaryAction: IPrimaryAction = {
callback: () => {
setIsLinkItemsModalVisible(true);
setIsLinkModalVisible(true);
},
icon: <FaPlus />,
disabled: disableAddItemAction,
label: t('explorer.add-existing-item')
};

return {
linkItemsAction: isEnabled ? linkItemsAction : null,
linkItemsModal: isLinkItemsModalVisible ? (
<AddLinkModal
linkPrimaryAction: isEnabled ? _linkPrimaryAction : null,
linkModal: isLinkModalVisible ? (
<LinkModal
open
library={library}
onClose={() => {
setIsLinkItemsModalVisible(false);
setIsLinkModalVisible(false);
}}
/>
) : null
Expand Down
Loading

0 comments on commit 869792b

Please sign in to comment.