Skip to content

Commit

Permalink
fix: aco small improvements (#4470)
Browse files Browse the repository at this point in the history
  • Loading branch information
leopuleo authored Jan 9, 2025
1 parent 6bf1d8f commit 621f49c
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 86 deletions.
4 changes: 4 additions & 0 deletions packages/app-aco/src/components/FolderTree/List/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export const List = ({
newTree: NodeModel<DndFolderItemData>[],
{ dragSourceId, dropTargetId }: DropOptions
) => {
// Store the current state of the tree before the drop action
const oldTree = [...treeData];
try {
const item = folders.find(folder => folder.id === dragSourceId);

Expand All @@ -73,6 +75,8 @@ export const List = ({
{ refetchFoldersList: true }
);
} catch (error) {
// If an error occurred, revert the tree back to its previous state
setTreeData(oldTree);
return showSnackbar(error.message);
}
};
Expand Down
17 changes: 17 additions & 0 deletions packages/app-aco/src/contexts/records.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ export const SearchRecordsProvider = ({ children }: Props) => {
setRecords(prev => {
return [record, ...prev];
});
setMeta(meta => ({
...meta,
totalCount: ++meta.totalCount
}));
},
updateRecordInCache: (record: any) => {
const { id: recordId } = parseIdentifier(record.id);
Expand All @@ -179,6 +183,10 @@ export const SearchRecordsProvider = ({ children }: Props) => {
record => record.id !== id && !record.id.startsWith(`${id}#`)
);
});
setMeta(meta => ({
...meta,
totalCount: --meta.totalCount
}));
},

async listRecords(params) {
Expand Down Expand Up @@ -279,6 +287,10 @@ export const SearchRecordsProvider = ({ children }: Props) => {
setRecords(prev => {
return prev.filter(record => record.id !== recordId);
});
setMeta(meta => ({
...meta,
totalCount: --meta.totalCount
}));
return data;
}
setRecords(prev => {
Expand All @@ -293,6 +305,11 @@ export const SearchRecordsProvider = ({ children }: Props) => {
return next;
});

setMeta(meta => ({
...meta,
totalCount: ++meta.totalCount
}));

setTags(tags => {
if (!data.tags || data.tags.length === 0) {
return tags;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ export const ListItemMeta = ({
disabled={!!disabledReason}
// Should prevent first item from being autofocused, but it doesn't. 🤷‍
focusOnOpen={false}
// This is needed because the z-index value is set in `packages/app-admin/src/components/Dialogs/styled.tsx`
portalZIndex={101}
>
{TARGET_LEVELS.map(level => (
<StyledMenuItem
Expand Down
146 changes: 69 additions & 77 deletions packages/app-admin/src/components/Dialogs/DialogsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useSnackbar } from "~/hooks";
import { Dialog } from "./Dialog";
import { CustomDialog } from "./CustomDialog";
import { createProvider } from "@webiny/app";
import { generateId } from "@webiny/utils";

interface ShowDialogParams {
title: ReactNode;
Expand All @@ -30,86 +31,80 @@ interface DialogsProviderProps {
children: ReactNode;
}

interface State {
interface DialogState extends ShowDialogParams {
id: string;
open: boolean;
loading: boolean;
title: ReactNode;
content: ReactNode;
acceptLabel: ReactNode;
cancelLabel: ReactNode;
loadingLabel: ReactNode;
element?: JSX.Element;
onAccept?: (data: GenericFormData) => void;
onClose?: () => void;
}

export const initializeState = (): State => ({
title: `Confirmation`,
content: undefined,
acceptLabel: `Confirm`,
cancelLabel: `Cancel`,
loadingLabel: `Loading`,
onAccept: undefined,
onClose: undefined,
open: false,
loading: false
export const initializeState = (params: Partial<DialogState> = {}): DialogState => ({
id: `dialog-${generateId()}`,
title: params.title ?? `Confirmation`,
content: params.content,
acceptLabel: params.acceptLabel ?? `Confirm`,
cancelLabel: params.cancelLabel ?? `Cancel`,
loadingLabel: params.loadingLabel ?? `Loading`,
onAccept: params.onAccept,
onClose: params.onClose,
open: params.open ?? false,
loading: params.loading ?? false,
element: params.element
});

export const DialogsContext = React.createContext<DialogsContext | undefined>(undefined);

export const DialogsProvider = ({ children }: DialogsProviderProps) => {
const { showSnackbar } = useSnackbar();
const [dialogs, setDialogs] = useState<Map<string, DialogState>>(new Map());

const [state, setState] = useState(initializeState());

const showDialog = (params: ShowDialogParams | JSX.Element) => {
setState(state => ({
...state,
...params,
open: true
}));
const showDialog = (params: ShowDialogParams) => {
const newDialog = initializeState({ ...params, open: true });
setDialogs(dialogs => new Map(dialogs).set(newDialog.id, newDialog));
};

const showCustomDialog = ({ onSubmit, element }: ShowCustomDialogParams) => {
setState(state => ({
...state,
const newDialog = initializeState({
element,
onAccept: onSubmit,
open: true
}));
});
setDialogs(dialogs => new Map(dialogs).set(newDialog.id, newDialog));
};

const closeDialog = () => {
if (typeof state.onClose === "function") {
state.onClose();
}

setState(state => ({
...state,
open: false,
element: undefined,
content: null
}));
const closeDialog = (id: string) => {
setDialogs(dialogs => {
const newDialogs = new Map(dialogs);
newDialogs.delete(id);
return newDialogs;
});
};

const onSubmit = async (data: GenericFormData) => {
try {
if (typeof state.onAccept === "function") {
setState(state => ({
...state,
loading: true
}));
const onSubmit = async (id: string, data: GenericFormData) => {
const dialog = dialogs.get(id);
if (!dialog) {
return;
}

await state.onAccept(data);
try {
if (typeof dialog.onAccept === "function") {
setDialogs(dialogs => {
const newDialogs = new Map(dialogs);
newDialogs.set(id, { ...dialog, loading: true });
return newDialogs;
});

await dialog.onAccept(data);
}
} catch (error) {
showSnackbar(error.message);
} finally {
setState(state => ({
...state,
loading: false
}));
closeDialog();
setDialogs(dialogs => {
const newDialogs = new Map(dialogs);
newDialogs.set(id, { ...dialog, loading: false });
return newDialogs;
});
closeDialog(id);
}
};

Expand All @@ -122,39 +117,36 @@ export const DialogsProvider = ({ children }: DialogsProviderProps) => {
return (
<DialogsContext.Provider value={context}>
{children}
<>
{state.element ? (
{Array.from(dialogs.values()).map(dialog =>
dialog.element ? (
<CustomDialog
open={state.open}
loading={state.loading}
closeDialog={closeDialog}
onSubmit={onSubmit}
key={dialog.id}
open={dialog.open}
loading={dialog.loading}
closeDialog={() => closeDialog(dialog.id)}
onSubmit={data => onSubmit(dialog.id, data)}
>
{state.element}
{dialog.element}
</CustomDialog>
) : null}
{!state.element ? (
) : (
<Dialog
title={state.title}
content={state.content}
open={state.open}
acceptLabel={state.acceptLabel}
cancelLabel={state.cancelLabel}
loadingLabel={state.loadingLabel}
loading={state.loading}
closeDialog={closeDialog}
onSubmit={onSubmit}
key={dialog.id}
title={dialog.title}
content={dialog.content}
open={dialog.open}
acceptLabel={dialog.acceptLabel}
cancelLabel={dialog.cancelLabel}
loadingLabel={dialog.loadingLabel}
loading={dialog.loading}
closeDialog={() => closeDialog(dialog.id)}
onSubmit={data => onSubmit(dialog.id, data)}
/>
) : null}
</>
)
)}
</DialogsContext.Provider>
);
};

interface DialogsProviderProps {
children: React.ReactNode;
}

export const createDialogsProvider = () => {
return createProvider(Component => {
return function DialogsProviderDecorator({ children }: DialogsProviderProps) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ const SupportedFileTypes = ({
if (accept.length === 0) {
return (
<span>
{t`Showing {currentCount} out of {totalCountLabel} from all file extensions.`({
currentCount,
{t`Showing {currentCountLabel} out of {totalCountLabel} from all file extensions.`({
currentCountLabel: String(currentCount),
totalCountLabel: getLabel(totalCount)
})}
</span>
Expand All @@ -55,9 +55,9 @@ const SupportedFileTypes = ({

return (
<span>
{t`Showing {currentCount} out of {totalCountLabel} from the following file extensions: {files}.`(
{t`Showing {currentCountLabel} out of {totalCountLabel} from the following file extensions: {files}.`(
{
currentCount,
currentCountLabel: String(currentCount),
totalCountLabel: getLabel(totalCount),
files: getUniqueFilePlugins(accept).join(", ")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export interface FileManagerViewContext<TFileItem extends FileItem = FileItem> e
hasOnSelectCallback: boolean;
listTitle: string;
loadMoreFiles: () => void;
meta: ListMeta | undefined;
meta: ListMeta;
moveFileToFolder: (fileId: string, folderId: string) => Promise<void>;
multiple: boolean;
onClose: () => void;
Expand Down Expand Up @@ -111,7 +111,7 @@ export const FileManagerViewProvider = ({ children, ...props }: FileManagerViewP
const tags = useTags(modifiers);
const [state, setState] = useStateIfMounted(initializeState());

const { loading, files, meta, listFiles, setFiles, getListVariables } = useListFiles({
const { loading, files, meta, listFiles, setFiles, setMeta, getListVariables } = useListFiles({
folderId: currentFolderId,
modifiers,
state
Expand All @@ -138,7 +138,7 @@ export const FileManagerViewProvider = ({ children, ...props }: FileManagerViewP
};

const loadMoreFiles = () => {
if (meta?.cursor) {
if (meta.cursor) {
loadFiles("LIST_MORE", { after: meta.cursor });
}
};
Expand Down Expand Up @@ -181,6 +181,11 @@ export const FileManagerViewProvider = ({ children, ...props }: FileManagerViewP
if (!file) {
// No file found - must be deleted by previous operation
setFiles(files => files.filter(file => file.id !== id));
// Decrease totalCount without performing a new API call
setMeta(meta => ({
...meta,
totalCount: --meta.totalCount
}));
} else {
setFiles(prevFiles => {
const fileIndex = prevFiles.findIndex(file => file.id === id);
Expand All @@ -200,6 +205,11 @@ export const FileManagerViewProvider = ({ children, ...props }: FileManagerViewP
...prevFiles.slice(fileIndex + 1)
];
});
// Increase totalCount without performing a new API call
setMeta(meta => ({
...meta,
totalCount: ++meta.totalCount
}));
}

return file;
Expand Down Expand Up @@ -236,6 +246,11 @@ export const FileManagerViewProvider = ({ children, ...props }: FileManagerViewP
if (newFile) {
newFile.tags = removeScopePrefix(newFile.tags || []);
setFiles(files => [newFile, ...files]);
// Increase totalCount without performing a new API call
setMeta(meta => ({
...meta,
totalCount: ++meta.totalCount
}));
}
return newFile;
};
Expand Down Expand Up @@ -290,6 +305,12 @@ export const FileManagerViewProvider = ({ children, ...props }: FileManagerViewP
return files;
}

// Decrease totalCount without performing a new API call
setMeta(meta => ({
...meta,
totalCount: --meta.totalCount
}));

return [...files.slice(0, index), ...files.slice(index + 1)];
});
};
Expand All @@ -315,6 +336,11 @@ export const FileManagerViewProvider = ({ children, ...props }: FileManagerViewP
if (newFile) {
newFile.tags = removeScopePrefix(newFile.tags);
setFiles(files => [newFile, ...files]);
// Increase totalCount without performing a new API call
setMeta(meta => ({
...meta,
totalCount: ++meta.totalCount
}));
}
return newFile;
};
Expand All @@ -325,6 +351,11 @@ export const FileManagerViewProvider = ({ children, ...props }: FileManagerViewP
) => {
await updateFile(fileId, { location: { folderId } });
setFiles(files => files.filter(file => file.id !== fileId));
// Decrease totalCount without performing a new API call
setMeta(meta => ({
...meta,
totalCount: --meta.totalCount
}));
};

const addScopePrefix = (tags: string[] = []) => {
Expand Down
Loading

0 comments on commit 621f49c

Please sign in to comment.