From fea925ca66be5eabd1d7491beb0a701c0f564793 Mon Sep 17 00:00:00 2001 From: Megha-Dev-19 Date: Mon, 1 Jan 2024 13:35:59 +0530 Subject: [PATCH] decoupled state --- .../entity/addon/github/Configurator.jsx | 147 ++++++++++++------ src/devhub/page/addon.jsx | 8 +- 2 files changed, 103 insertions(+), 52 deletions(-) diff --git a/src/devhub/entity/addon/github/Configurator.jsx b/src/devhub/entity/addon/github/Configurator.jsx index 39e6f8382..8dc9c3ba0 100644 --- a/src/devhub/entity/addon/github/Configurator.jsx +++ b/src/devhub/entity/addon/github/Configurator.jsx @@ -76,12 +76,35 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { ); } - const initialFormState = Struct.typeMatch(data) ? toMigrated(data) : {}; - const [formState, setForm] = useState(initialFormState); + const initialBoardState = Struct.typeMatch(data) ? toMigrated(data) : {}; + + const getColumnData = useCallback((state) => { + if (Object.keys(state).length > 0) { + return state?.columns ?? {}; + } + return state; + }, []); + + const getNonColumnData = useCallback((state) => { + if (Object.keys(state).length > 0) { + delete state.columns; + return state; + } + return state; + }, []); + + // to improve the state update speed, decoupled columns and other configuration metadata + const [parentState, setParentState] = useState(initialBoardState); + const [metadataState, setMetadata] = useState( + getNonColumnData(initialBoardState) + ); const [showPreview, setPreview] = useState(false); + const [columnsState, setColumnsState] = useState( + getColumnData(initialBoardState) + ); const formUpdate = - ({ path, via: customFieldUpdate, ...params }) => + ({ path, via: customFieldUpdate, isColumnsUpdate, ...params }) => (fieldInput) => { const transformFn = (node) => { if (typeof customFieldUpdate === "function") { @@ -99,22 +122,30 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { } }; const updatedValues = Struct.deepFieldUpdate( - formState ?? {}, + (isColumnsUpdate ? { columns: columnsState } : metadataState) ?? {}, path, (node) => transformFn(node) ); - setForm((prevFormState) => ({ - ...prevFormState, - ...updatedValues, - })); + if (isColumnsUpdate) { + setColumnsState(updatedValues?.columns); + } else { + setMetadata((prevFormState) => ({ + ...prevFormState, + ...updatedValues, + })); + } }; const formReset = () => { - setForm(initialFormState); + setColumnsState(getColumnData(initialBoardState)); + setMetadata(getNonColumnData(initialBoardState)); + setParentState(initialBoardState); }; const newViewInit = () => { - setForm(GithubKanbanBoardDefaults); + setColumnsState(getColumnData(GithubKanbanBoardDefaults)); + setMetadata(getNonColumnData(GithubKanbanBoardDefaults)); + setParentState(GithubKanbanBoardDefaults); }; const columnsCreateNew = ({ lastKnownValue }) => @@ -140,7 +171,13 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { formReset(); }; - const onSave = () => onSubmit(formState); + const updateParentState = () => { + const updatedState = { ...metadataState, columns: columnsState }; + setParentState(updatedState); + return updatedState; + }; + + const onSave = () => onSubmit(updateParentState()); const formElement = ( <> @@ -150,22 +187,25 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { src={`${REPL_DEVHUB}/widget/devhub.components.molecule.Input`} props={{ className: "w-100", - key: `${formState.metadata.id}-repoURL`, + key: `${metadataState.metadata.id}-repoURL`, label: "Repository URL", - onChange: formUpdate({ path: ["repoURL"] }), + onChange: formUpdate({ + path: ["repoURL"], + isColumnsUpdate: false, + }), placeholder: "https://github.com/example-org/example-repo", - value: formState.repoURL, + value: metadataState.repoURL, }} /> @@ -174,11 +214,14 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { src={`${REPL_DEVHUB}/widget/devhub.components.molecule.Input`} props={{ className: "w-100", - key: `${formState.metadata.id}-description`, + key: `${metadataState.metadata.id}-description`, label: "Description", - onChange: formUpdate({ path: ["description"] }), + onChange: formUpdate({ + path: ["description"], + isColumnsUpdate: false, + }), placeholder: "Latest NEAR Enhancement Proposals by status.", - value: formState.description, + value: metadataState.description, }} /> @@ -189,11 +232,14 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { props={{ heading: "Ticket types", classNames: { root: "col-12 col-md-4 h-auto" }, - externalState: formState.dataTypesIncluded, + externalState: metadataState.dataTypesIncluded, isActive: true, isEmbedded: true, isUnlocked: permissions.can_configure, - onChange: formUpdate({ path: ["dataTypesIncluded"] }), + onChange: formUpdate({ + path: ["dataTypesIncluded"], + isColumnsUpdate: false, + }), schema: GithubKanbanBoardTicketTypesSchema, hideSubmitBtn: true, }} @@ -207,7 +253,7 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { > Ticket state @@ -215,10 +261,12 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { { props={{ heading: "Card fields", classNames: { root: "col-12 col-md-4 h-auto" }, - externalState: formState.metadata.ticket.features, + externalState: metadataState.metadata.ticket.features, isActive: true, isEmbedded: true, isUnlocked: permissions.can_configure, - onChange: formUpdate({ path: ["metadata", "ticket", "features"] }), + onChange: formUpdate({ + path: ["metadata", "ticket", "features"], + isColumnsUpdate: false, + }), schema: GithubKanbanBoardTicketFeaturesSchema, hideSubmitBtn: true, }} @@ -251,8 +302,8 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => {
- {Object.values(formState.columns ?? {}).map( - ({ id, description, labelSearchTerms, title }) => ( + {Object.values(columnsState ?? {}).map( + ({ id, description, labelSearchTerms, title }, index) => ( { src={`${REPL_DEVHUB}/widget/devhub.components.molecule.Input`} props={{ className: "flex-grow-1", - key: `${formState.metadata.id}-column-${id}-title`, + key: `${metadataState.metadata.id}-column-${id}-title`, label: "Title", - onChange: formUpdate({ path: ["columns", id, "title"] }), + onChange: formUpdate({ + path: ["columns", id, "title"], + isColumnsUpdate: true, + }), placeholder: "👀 Review", value: title, }} @@ -273,15 +327,13 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { src={`${REPL_DEVHUB}/widget/devhub.components.molecule.Input`} props={{ format: "comma-separated", - key: `${formState.metadata.id}-column-${title}-labelSearchTerms`, - + key: `${metadataState.metadata.id}-column-${title}-labelSearchTerms`, label: `Search terms for all the labels MUST be presented in included tickets`, - onChange: formUpdate({ path: ["columns", id, "labelSearchTerms"], + isColumnsUpdate: true, }), - placeholder: "WG-, draft, review, proposal, ...", value: labelSearchTerms.join(", "), }} @@ -290,16 +342,14 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { src={`${REPL_DEVHUB}/widget/devhub.components.molecule.Input`} props={{ className: "flex-grow-1", - key: `${formState.metadata.id}-column-${id}-description`, + key: `${metadataState.metadata.id}-column-${id}-description`, label: "Description", - onChange: formUpdate({ path: ["columns", id, "description"], + isColumnsUpdate: true, }), - placeholder: "NEPs that need a review by Subject Matter Experts.", - value: description, }} /> @@ -314,6 +364,7 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { onClick={formUpdate({ path: ["columns"], via: columnsDeleteById(id), + isColumnsUpdate: true, })} title="Delete column" > @@ -341,14 +392,12 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { props={{ classNames: { root: "btn btn-success" }, disabled: form.isSynced, - icon: { type: "svg_icon", variant: "floppy_drive", width: 14, height: 14, }, - isHidden: typeof onSave !== "function", label: "Save", onClick: onSave, @@ -390,7 +439,10 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { role="tab" aria-controls="preview" aria-selected="false" - onClick={() => setPreview(true)} + onClick={() => { + updateParentState(); + setPreview(true); + }} > Preview @@ -402,7 +454,7 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { src={`${REPL_DEVHUB}/widget/devhub.entity.addon.github.Viewer`} props={{ kanbanBoards: { - [formState.metadata.id]: formState, + [parentState.metadata.id]: parentState, }, }} /> @@ -415,7 +467,7 @@ const GithubViewConfigurator = ({ kanbanBoards, permissions, onSubmit }) => { GitHub board configuration
- {Object.keys(formState).length > 0 && ( + {Object.keys(parentState).length > 0 && (
{formElement} { }, label: "New column", disabled: - Object.keys(formState.columns).length >= + Object.keys(parentState.columns).length >= settings.maxColumnsNumber, icon: { type: "bootstrap_icon", variant: "bi-plus-lg" }, onClick: formUpdate({ path: ["columns"], via: columnsCreateNew, + isColumnsUpdate: true, }), }} />
)} - {!Object.keys(formState).length && ( + {!Object.keys(parentState).length && (
)} - {/* We hide in order to prevent a reload when we switch between two views */} -
+ {view === "configure" ? ( -
-
+ ) : ( -
+ )}
);