From 45f9a3546feb5a8aa775a3a3efaabf3643a90d5e Mon Sep 17 00:00:00 2001 From: Misha Holtz <36575242+mnholtz@users.noreply.github.com> Date: Tue, 8 Oct 2024 17:49:26 -0700 Subject: [PATCH 01/12] remove onDeactivate prop drill --- src/pageEditor/modListingPanel/ModActionMenu.tsx | 12 ++++++++---- src/pageEditor/modListingPanel/ModComponents.tsx | 5 ----- src/pageEditor/modListingPanel/ModListItem.test.tsx | 3 --- src/pageEditor/modListingPanel/ModListItem.tsx | 4 +--- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/pageEditor/modListingPanel/ModActionMenu.tsx b/src/pageEditor/modListingPanel/ModActionMenu.tsx index 1fef83339d..d5d0ba84b1 100644 --- a/src/pageEditor/modListingPanel/ModActionMenu.tsx +++ b/src/pageEditor/modListingPanel/ModActionMenu.tsx @@ -30,14 +30,16 @@ import EllipsisMenu, { } from "@/components/ellipsisMenu/EllipsisMenu"; import { type AddNewModComponent } from "@/pageEditor/hooks/useAddNewModComponent"; import { useAvailableFormStateAdapters } from "@/pageEditor/starterBricks/adapter"; +import useDeactivateMod from "@/pageEditor/hooks/useDeactivateMod"; +import { type RegistryId } from "@/types/registryTypes"; type OptionalAction = (() => Promise) | undefined; type ActionMenuProps = { + modId: RegistryId; isDirty: boolean; isActive: boolean; labelRoot: string; - onDeactivate: () => Promise; onMakeCopy: () => Promise; onAddStarterBrick: AddNewModComponent; // Actions only defined if there are changes @@ -46,17 +48,18 @@ type ActionMenuProps = { }; const ModActionMenu: React.FC = ({ + modId, isActive, labelRoot, isDirty, onAddStarterBrick, - onDeactivate, onMakeCopy, // Convert to null because EllipsisMenuItem expects null vs. undefined onSave = null, onClearChanges = null, }) => { const modComponentFormStateAdapters = useAvailableFormStateAdapters(); + const deactivateMod = useDeactivateMod(); const menuItems: EllipsisMenuItem[] = [ { @@ -87,8 +90,9 @@ const ModActionMenu: React.FC = ({ { title: "Deactivate", icon: , - action: onDeactivate, - hide: !onDeactivate, + async action() { + await deactivateMod({ modId }); + }, }, ]; diff --git a/src/pageEditor/modListingPanel/ModComponents.tsx b/src/pageEditor/modListingPanel/ModComponents.tsx index aa58c70dbd..3bddbad7e2 100644 --- a/src/pageEditor/modListingPanel/ModComponents.tsx +++ b/src/pageEditor/modListingPanel/ModComponents.tsx @@ -36,7 +36,6 @@ import { import { useDispatch, useSelector } from "react-redux"; import useSaveMod from "@/pageEditor/hooks/useSaveMod"; import useClearModChanges from "@/pageEditor/hooks/useClearModChanges"; -import useDeactivateMod from "@/pageEditor/hooks/useDeactivateMod"; import ModComponentListItem from "./ModComponentListItem"; import { actions } from "@/pageEditor/store/editor/editorSlice"; import { useDebounce } from "use-debounce"; @@ -89,7 +88,6 @@ const ModComponents: React.FunctionComponent = () => { const saveMod = useSaveMod(); const clearModChanges = useClearModChanges(); - const deactivateMod = useDeactivateMod(); const listItems = filteredSidebarItems.map((sidebarItem) => { if (isModSidebarItem(sidebarItem)) { @@ -105,9 +103,6 @@ const ModComponents: React.FunctionComponent = () => { onClearChanges={async () => { await clearModChanges(modMetadata.id); }} - onDeactivate={async () => { - await deactivateMod({ modId: modMetadata.id }); - }} onMakeCopy={async () => { dispatch(actions.showCreateModModal({ keepLocalCopy: true })); }} diff --git a/src/pageEditor/modListingPanel/ModListItem.test.tsx b/src/pageEditor/modListingPanel/ModListItem.test.tsx index 8d8b2f66bf..f66b2b2358 100644 --- a/src/pageEditor/modListingPanel/ModListItem.test.tsx +++ b/src/pageEditor/modListingPanel/ModListItem.test.tsx @@ -42,7 +42,6 @@ describe("ModListItem", () => { modMetadata={modMetadata} onSave={jest.fn()} onClearChanges={jest.fn()} - onDeactivate={jest.fn()} onMakeCopy={jest.fn()} >
test children
@@ -73,7 +72,6 @@ describe("ModListItem", () => { modMetadata={modMetadata} onSave={jest.fn()} onClearChanges={jest.fn()} - onDeactivate={jest.fn()} onMakeCopy={jest.fn()} >
test children
@@ -113,7 +111,6 @@ describe("ModListItem", () => { modMetadata={modMetadata} onSave={jest.fn()} onClearChanges={jest.fn()} - onDeactivate={jest.fn()} onMakeCopy={jest.fn()} >
test children
diff --git a/src/pageEditor/modListingPanel/ModListItem.tsx b/src/pageEditor/modListingPanel/ModListItem.tsx index c3fa69d73c..25baff9a3f 100644 --- a/src/pageEditor/modListingPanel/ModListItem.tsx +++ b/src/pageEditor/modListingPanel/ModListItem.tsx @@ -46,7 +46,6 @@ export type ModListItemProps = PropsWithChildren<{ modMetadata: ModMetadata; onSave: () => Promise; onClearChanges: () => Promise; - onDeactivate: () => Promise; onMakeCopy: () => Promise; }>; @@ -55,7 +54,6 @@ const ModListItem: React.FC = ({ children, onSave, onClearChanges, - onDeactivate, onMakeCopy, }) => { const dispatch = useDispatch(); @@ -116,11 +114,11 @@ const ModListItem: React.FC = ({ )} Date: Tue, 8 Oct 2024 17:57:05 -0700 Subject: [PATCH 02/12] remove onSave prop drill --- .../modListingPanel/ModActionMenu.tsx | 20 +++++++++---------- .../modListingPanel/ModComponents.tsx | 5 ----- .../modListingPanel/ModListItem.test.tsx | 3 --- .../modListingPanel/ModListItem.tsx | 3 --- 4 files changed, 9 insertions(+), 22 deletions(-) diff --git a/src/pageEditor/modListingPanel/ModActionMenu.tsx b/src/pageEditor/modListingPanel/ModActionMenu.tsx index d5d0ba84b1..a581892e07 100644 --- a/src/pageEditor/modListingPanel/ModActionMenu.tsx +++ b/src/pageEditor/modListingPanel/ModActionMenu.tsx @@ -32,6 +32,7 @@ import { type AddNewModComponent } from "@/pageEditor/hooks/useAddNewModComponen import { useAvailableFormStateAdapters } from "@/pageEditor/starterBricks/adapter"; import useDeactivateMod from "@/pageEditor/hooks/useDeactivateMod"; import { type RegistryId } from "@/types/registryTypes"; +import useSaveMod from "@/pageEditor/hooks/useSaveMod"; type OptionalAction = (() => Promise) | undefined; @@ -42,8 +43,6 @@ type ActionMenuProps = { labelRoot: string; onMakeCopy: () => Promise; onAddStarterBrick: AddNewModComponent; - // Actions only defined if there are changes - onSave: OptionalAction; onClearChanges: OptionalAction; }; @@ -54,12 +53,11 @@ const ModActionMenu: React.FC = ({ isDirty, onAddStarterBrick, onMakeCopy, - // Convert to null because EllipsisMenuItem expects null vs. undefined - onSave = null, onClearChanges = null, }) => { const modComponentFormStateAdapters = useAvailableFormStateAdapters(); const deactivateMod = useDeactivateMod(); + const saveMod = useSaveMod(); const menuItems: EllipsisMenuItem[] = [ { @@ -98,13 +96,13 @@ const ModActionMenu: React.FC = ({ return (
- {onSave != null && ( - - )} + { + await saveMod(modId); + }} + disabled={!isDirty} + /> {isActive && ( { ], ); - const saveMod = useSaveMod(); const clearModChanges = useClearModChanges(); const listItems = filteredSidebarItems.map((sidebarItem) => { @@ -97,9 +95,6 @@ const ModComponents: React.FunctionComponent = () => { { - await saveMod(modMetadata.id); - }} onClearChanges={async () => { await clearModChanges(modMetadata.id); }} diff --git a/src/pageEditor/modListingPanel/ModListItem.test.tsx b/src/pageEditor/modListingPanel/ModListItem.test.tsx index f66b2b2358..2ef06eabf3 100644 --- a/src/pageEditor/modListingPanel/ModListItem.test.tsx +++ b/src/pageEditor/modListingPanel/ModListItem.test.tsx @@ -40,7 +40,6 @@ describe("ModListItem", () => { @@ -70,7 +69,6 @@ describe("ModListItem", () => { @@ -109,7 +107,6 @@ describe("ModListItem", () => { diff --git a/src/pageEditor/modListingPanel/ModListItem.tsx b/src/pageEditor/modListingPanel/ModListItem.tsx index 25baff9a3f..28afddeae4 100644 --- a/src/pageEditor/modListingPanel/ModListItem.tsx +++ b/src/pageEditor/modListingPanel/ModListItem.tsx @@ -44,7 +44,6 @@ import ModActionMenu from "@/pageEditor/modListingPanel/ModActionMenu"; export type ModListItemProps = PropsWithChildren<{ modMetadata: ModMetadata; - onSave: () => Promise; onClearChanges: () => Promise; onMakeCopy: () => Promise; }>; @@ -52,7 +51,6 @@ export type ModListItemProps = PropsWithChildren<{ const ModListItem: React.FC = ({ modMetadata, children, - onSave, onClearChanges, onMakeCopy, }) => { @@ -117,7 +115,6 @@ const ModListItem: React.FC = ({ modId={modId} isActive={isActive} labelRoot={name} - onSave={onSave} onClearChanges={isUnsavedMod ? undefined : onClearChanges} onAddStarterBrick={addNewModComponent} onMakeCopy={onMakeCopy} From 222408dfcc3c2e8fb0d2d8b7d5d057c7f2a2b09a Mon Sep 17 00:00:00 2001 From: Misha Holtz <36575242+mnholtz@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:06:17 -0700 Subject: [PATCH 03/12] remove addStarterBrick prop drill --- src/pageEditor/modListingPanel/ModActionMenu.tsx | 16 ++++++++-------- src/pageEditor/modListingPanel/ModListItem.tsx | 5 +---- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/pageEditor/modListingPanel/ModActionMenu.tsx b/src/pageEditor/modListingPanel/ModActionMenu.tsx index a581892e07..4f7ab6cc24 100644 --- a/src/pageEditor/modListingPanel/ModActionMenu.tsx +++ b/src/pageEditor/modListingPanel/ModActionMenu.tsx @@ -28,36 +28,36 @@ import styles from "./ActionMenu.module.scss"; import EllipsisMenu, { type EllipsisMenuItem, } from "@/components/ellipsisMenu/EllipsisMenu"; -import { type AddNewModComponent } from "@/pageEditor/hooks/useAddNewModComponent"; +import useAddNewModComponent from "@/pageEditor/hooks/useAddNewModComponent"; import { useAvailableFormStateAdapters } from "@/pageEditor/starterBricks/adapter"; import useDeactivateMod from "@/pageEditor/hooks/useDeactivateMod"; -import { type RegistryId } from "@/types/registryTypes"; import useSaveMod from "@/pageEditor/hooks/useSaveMod"; +import { type ModMetadata } from "@/types/modComponentTypes"; type OptionalAction = (() => Promise) | undefined; type ActionMenuProps = { - modId: RegistryId; + modMetadata: ModMetadata; isDirty: boolean; isActive: boolean; labelRoot: string; onMakeCopy: () => Promise; - onAddStarterBrick: AddNewModComponent; onClearChanges: OptionalAction; }; const ModActionMenu: React.FC = ({ - modId, + modMetadata, isActive, labelRoot, isDirty, - onAddStarterBrick, onMakeCopy, onClearChanges = null, }) => { + const { id: modId } = modMetadata; const modComponentFormStateAdapters = useAvailableFormStateAdapters(); const deactivateMod = useDeactivateMod(); const saveMod = useSaveMod(); + const addNewModComponent = useAddNewModComponent(modMetadata); const menuItems: EllipsisMenuItem[] = [ { @@ -74,11 +74,10 @@ const ModActionMenu: React.FC = ({ submenu: modComponentFormStateAdapters.map((adapter) => ({ title: adapter.label, action() { - onAddStarterBrick(adapter); + addNewModComponent(adapter); }, icon: , })), - hide: !onAddStarterBrick, }, { title: "Make a copy", @@ -96,6 +95,7 @@ const ModActionMenu: React.FC = ({ return (
+ {/* TODO: did we really want to always show SaveButton? That is the current behavior as of 2.1.5-beta.1 */} { diff --git a/src/pageEditor/modListingPanel/ModListItem.tsx b/src/pageEditor/modListingPanel/ModListItem.tsx index 28afddeae4..7fed0ccf30 100644 --- a/src/pageEditor/modListingPanel/ModListItem.tsx +++ b/src/pageEditor/modListingPanel/ModListItem.tsx @@ -37,7 +37,6 @@ import { } from "@/pageEditor/store/editor/editorSelectors"; import * as semver from "semver"; import { useGetModDefinitionQuery } from "@/data/service/api"; -import useAddNewModComponent from "@/pageEditor/hooks/useAddNewModComponent"; import { type ModMetadata } from "@/types/modComponentTypes"; import { isInnerDefinitionRegistryId } from "@/types/helpers"; import ModActionMenu from "@/pageEditor/modListingPanel/ModActionMenu"; @@ -60,7 +59,6 @@ const ModListItem: React.FC = ({ const activeModComponentFormState = useSelector( selectActiveModComponentFormState, ); - const addNewModComponent = useAddNewModComponent(modMetadata); const { id: modId, name: savedName, version: activatedVersion } = modMetadata; const isActive = activeModId === modId; @@ -112,11 +110,10 @@ const ModListItem: React.FC = ({ )} From 624ab9c448582a699f66e728a31ee39cca97f664 Mon Sep 17 00:00:00 2001 From: Misha Holtz <36575242+mnholtz@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:13:28 -0700 Subject: [PATCH 04/12] remove onClearChanges prop drill --- .../modListingPanel/ModActionMenu.tsx | 20 +++++++++++-------- .../modListingPanel/ModComponents.tsx | 6 ------ .../modListingPanel/ModListItem.test.tsx | 18 +++-------------- .../modListingPanel/ModListItem.tsx | 6 ------ 4 files changed, 15 insertions(+), 35 deletions(-) diff --git a/src/pageEditor/modListingPanel/ModActionMenu.tsx b/src/pageEditor/modListingPanel/ModActionMenu.tsx index 4f7ab6cc24..40c3deb8fd 100644 --- a/src/pageEditor/modListingPanel/ModActionMenu.tsx +++ b/src/pageEditor/modListingPanel/ModActionMenu.tsx @@ -33,8 +33,8 @@ import { useAvailableFormStateAdapters } from "@/pageEditor/starterBricks/adapte import useDeactivateMod from "@/pageEditor/hooks/useDeactivateMod"; import useSaveMod from "@/pageEditor/hooks/useSaveMod"; import { type ModMetadata } from "@/types/modComponentTypes"; - -type OptionalAction = (() => Promise) | undefined; +import useClearModChanges from "@/pageEditor/hooks/useClearModChanges"; +import { isInnerDefinitionRegistryId } from "@/types/helpers"; type ActionMenuProps = { modMetadata: ModMetadata; @@ -42,7 +42,6 @@ type ActionMenuProps = { isActive: boolean; labelRoot: string; onMakeCopy: () => Promise; - onClearChanges: OptionalAction; }; const ModActionMenu: React.FC = ({ @@ -51,22 +50,27 @@ const ModActionMenu: React.FC = ({ labelRoot, isDirty, onMakeCopy, - onClearChanges = null, }) => { const { id: modId } = modMetadata; const modComponentFormStateAdapters = useAvailableFormStateAdapters(); + const deactivateMod = useDeactivateMod(); const saveMod = useSaveMod(); + const clearModChanges = useClearModChanges(); const addNewModComponent = useAddNewModComponent(modMetadata); + const isUnsavedMod = isInnerDefinitionRegistryId(modId); + const menuItems: EllipsisMenuItem[] = [ { title: "Clear Changes", icon: , - action: onClearChanges, - // Always show Clear Changes button, even if there are no changes so the UI is more consistent / the user doesn't - // wonder why the menu item is missing - disabled: !isDirty || !onClearChanges, + async action() { + await clearModChanges(modId); + }, + // Always show Clear Changes button, even if there are no changes or the mod is an unsaved mod so the UI is more + // consistent / the user doesn't wonder why the menu item is missing + disabled: !isDirty || isUnsavedMod, }, { title: "Add Starter Brick", diff --git a/src/pageEditor/modListingPanel/ModComponents.tsx b/src/pageEditor/modListingPanel/ModComponents.tsx index 09886af17d..d6a4013e76 100644 --- a/src/pageEditor/modListingPanel/ModComponents.tsx +++ b/src/pageEditor/modListingPanel/ModComponents.tsx @@ -34,7 +34,6 @@ import { selectNotDeletedActivatedModComponents, } from "@/pageEditor/store/editor/editorSelectors"; import { useDispatch, useSelector } from "react-redux"; -import useClearModChanges from "@/pageEditor/hooks/useClearModChanges"; import ModComponentListItem from "./ModComponentListItem"; import { actions } from "@/pageEditor/store/editor/editorSlice"; import { useDebounce } from "use-debounce"; @@ -85,8 +84,6 @@ const ModComponents: React.FunctionComponent = () => { ], ); - const clearModChanges = useClearModChanges(); - const listItems = filteredSidebarItems.map((sidebarItem) => { if (isModSidebarItem(sidebarItem)) { const { modMetadata, modComponents } = sidebarItem; @@ -95,9 +92,6 @@ const ModComponents: React.FunctionComponent = () => { { - await clearModChanges(modMetadata.id); - }} onMakeCopy={async () => { dispatch(actions.showCreateModModal({ keepLocalCopy: true })); }} diff --git a/src/pageEditor/modListingPanel/ModListItem.test.tsx b/src/pageEditor/modListingPanel/ModListItem.test.tsx index 2ef06eabf3..21afcea6fd 100644 --- a/src/pageEditor/modListingPanel/ModListItem.test.tsx +++ b/src/pageEditor/modListingPanel/ModListItem.test.tsx @@ -38,11 +38,7 @@ describe("ModListItem", () => { render( - +
test children
@@ -67,11 +63,7 @@ describe("ModListItem", () => { render( - +
test children
@@ -105,11 +97,7 @@ describe("ModListItem", () => { render( - +
test children
diff --git a/src/pageEditor/modListingPanel/ModListItem.tsx b/src/pageEditor/modListingPanel/ModListItem.tsx index 7fed0ccf30..ce8cfc2d9b 100644 --- a/src/pageEditor/modListingPanel/ModListItem.tsx +++ b/src/pageEditor/modListingPanel/ModListItem.tsx @@ -38,19 +38,16 @@ import { import * as semver from "semver"; import { useGetModDefinitionQuery } from "@/data/service/api"; import { type ModMetadata } from "@/types/modComponentTypes"; -import { isInnerDefinitionRegistryId } from "@/types/helpers"; import ModActionMenu from "@/pageEditor/modListingPanel/ModActionMenu"; export type ModListItemProps = PropsWithChildren<{ modMetadata: ModMetadata; - onClearChanges: () => Promise; onMakeCopy: () => Promise; }>; const ModListItem: React.FC = ({ modMetadata, children, - onClearChanges, onMakeCopy, }) => { const dispatch = useDispatch(); @@ -76,8 +73,6 @@ const ModListItem: React.FC = ({ const name = dirtyName ?? savedName ?? "Loading..."; const isDirty = useSelector(selectModIsDirty(modId)); - const isUnsavedMod = isInnerDefinitionRegistryId(modMetadata.id); - const hasUpdate = latestModVersion != null && activatedVersion != null && @@ -113,7 +108,6 @@ const ModListItem: React.FC = ({ modMetadata={modMetadata} isActive={isActive} labelRoot={name} - onClearChanges={isUnsavedMod ? undefined : onClearChanges} onMakeCopy={onMakeCopy} isDirty={isDirty} /> From c8ce0024e2a2dbaadab7169947db61fc6fdf20d9 Mon Sep 17 00:00:00 2001 From: Misha Holtz <36575242+mnholtz@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:18:15 -0700 Subject: [PATCH 05/12] remove onMakeCopy prop drill --- src/pageEditor/modListingPanel/ModActionMenu.tsx | 9 ++++++--- src/pageEditor/modListingPanel/ModComponents.tsx | 12 ++---------- src/pageEditor/modListingPanel/ModListItem.test.tsx | 6 +++--- src/pageEditor/modListingPanel/ModListItem.tsx | 8 +------- 4 files changed, 12 insertions(+), 23 deletions(-) diff --git a/src/pageEditor/modListingPanel/ModActionMenu.tsx b/src/pageEditor/modListingPanel/ModActionMenu.tsx index 40c3deb8fd..7aaf7b867c 100644 --- a/src/pageEditor/modListingPanel/ModActionMenu.tsx +++ b/src/pageEditor/modListingPanel/ModActionMenu.tsx @@ -35,13 +35,14 @@ import useSaveMod from "@/pageEditor/hooks/useSaveMod"; import { type ModMetadata } from "@/types/modComponentTypes"; import useClearModChanges from "@/pageEditor/hooks/useClearModChanges"; import { isInnerDefinitionRegistryId } from "@/types/helpers"; +import { actions } from "@/pageEditor/store/editor/editorSlice"; +import { useDispatch } from "react-redux"; type ActionMenuProps = { modMetadata: ModMetadata; isDirty: boolean; isActive: boolean; labelRoot: string; - onMakeCopy: () => Promise; }; const ModActionMenu: React.FC = ({ @@ -49,9 +50,9 @@ const ModActionMenu: React.FC = ({ isActive, labelRoot, isDirty, - onMakeCopy, }) => { const { id: modId } = modMetadata; + const dispatch = useDispatch(); const modComponentFormStateAdapters = useAvailableFormStateAdapters(); const deactivateMod = useDeactivateMod(); @@ -86,7 +87,9 @@ const ModActionMenu: React.FC = ({ { title: "Make a copy", icon: , - action: onMakeCopy, + async action() { + dispatch(actions.showCreateModModal({ keepLocalCopy: true })); + }, }, { title: "Deactivate", diff --git a/src/pageEditor/modListingPanel/ModComponents.tsx b/src/pageEditor/modListingPanel/ModComponents.tsx index d6a4013e76..b0e650242a 100644 --- a/src/pageEditor/modListingPanel/ModComponents.tsx +++ b/src/pageEditor/modListingPanel/ModComponents.tsx @@ -33,14 +33,12 @@ import { selectNotDeletedModComponentFormStates, selectNotDeletedActivatedModComponents, } from "@/pageEditor/store/editor/editorSelectors"; -import { useDispatch, useSelector } from "react-redux"; +import { useSelector } from "react-redux"; import ModComponentListItem from "./ModComponentListItem"; -import { actions } from "@/pageEditor/store/editor/editorSlice"; import { useDebounce } from "use-debounce"; import filterSidebarItems from "@/pageEditor/modListingPanel/filterSidebarItems"; const ModComponents: React.FunctionComponent = () => { - const dispatch = useDispatch(); const activeModComponentId = useSelector(selectActiveModComponentId); const activeModId = useSelector(selectActiveModId); const expandedModId = useSelector(selectExpandedModId); @@ -89,13 +87,7 @@ const ModComponents: React.FunctionComponent = () => { const { modMetadata, modComponents } = sidebarItem; return ( - { - dispatch(actions.showCreateModModal({ keepLocalCopy: true })); - }} - > + {modComponents.map((modComponentSidebarItem) => ( { render( - +
test children
@@ -63,7 +63,7 @@ describe("ModListItem", () => { render( - +
test children
@@ -97,7 +97,7 @@ describe("ModListItem", () => { render( - +
test children
diff --git a/src/pageEditor/modListingPanel/ModListItem.tsx b/src/pageEditor/modListingPanel/ModListItem.tsx index ce8cfc2d9b..3d70568f21 100644 --- a/src/pageEditor/modListingPanel/ModListItem.tsx +++ b/src/pageEditor/modListingPanel/ModListItem.tsx @@ -42,14 +42,9 @@ import ModActionMenu from "@/pageEditor/modListingPanel/ModActionMenu"; export type ModListItemProps = PropsWithChildren<{ modMetadata: ModMetadata; - onMakeCopy: () => Promise; }>; -const ModListItem: React.FC = ({ - modMetadata, - children, - onMakeCopy, -}) => { +const ModListItem: React.FC = ({ modMetadata, children }) => { const dispatch = useDispatch(); const activeModId = useSelector(selectActiveModId); const expandedModId = useSelector(selectExpandedModId); @@ -108,7 +103,6 @@ const ModListItem: React.FC = ({ modMetadata={modMetadata} isActive={isActive} labelRoot={name} - onMakeCopy={onMakeCopy} isDirty={isDirty} /> From bf98aee80132a5b6c57788b0525d2811bce0d4ea Mon Sep 17 00:00:00 2001 From: Misha Holtz <36575242+mnholtz@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:21:01 -0700 Subject: [PATCH 06/12] move isDirty into ModActionMenu --- src/pageEditor/modListingPanel/ModActionMenu.tsx | 6 +++--- src/pageEditor/modListingPanel/ModListItem.tsx | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/pageEditor/modListingPanel/ModActionMenu.tsx b/src/pageEditor/modListingPanel/ModActionMenu.tsx index 7aaf7b867c..51c67eed6a 100644 --- a/src/pageEditor/modListingPanel/ModActionMenu.tsx +++ b/src/pageEditor/modListingPanel/ModActionMenu.tsx @@ -36,11 +36,11 @@ import { type ModMetadata } from "@/types/modComponentTypes"; import useClearModChanges from "@/pageEditor/hooks/useClearModChanges"; import { isInnerDefinitionRegistryId } from "@/types/helpers"; import { actions } from "@/pageEditor/store/editor/editorSlice"; -import { useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; +import { selectModIsDirty } from "@/pageEditor/store/editor/editorSelectors"; type ActionMenuProps = { modMetadata: ModMetadata; - isDirty: boolean; isActive: boolean; labelRoot: string; }; @@ -49,7 +49,6 @@ const ModActionMenu: React.FC = ({ modMetadata, isActive, labelRoot, - isDirty, }) => { const { id: modId } = modMetadata; const dispatch = useDispatch(); @@ -61,6 +60,7 @@ const ModActionMenu: React.FC = ({ const addNewModComponent = useAddNewModComponent(modMetadata); const isUnsavedMod = isInnerDefinitionRegistryId(modId); + const isDirty = useSelector(selectModIsDirty(modId)); const menuItems: EllipsisMenuItem[] = [ { diff --git a/src/pageEditor/modListingPanel/ModListItem.tsx b/src/pageEditor/modListingPanel/ModListItem.tsx index 3d70568f21..faaecf1ca8 100644 --- a/src/pageEditor/modListingPanel/ModListItem.tsx +++ b/src/pageEditor/modListingPanel/ModListItem.tsx @@ -33,7 +33,6 @@ import { selectActiveModId, selectDirtyMetadataForModId, selectExpandedModId, - selectModIsDirty, } from "@/pageEditor/store/editor/editorSelectors"; import * as semver from "semver"; import { useGetModDefinitionQuery } from "@/data/service/api"; @@ -66,7 +65,6 @@ const ModListItem: React.FC = ({ modMetadata, children }) => { const dirtyName = useSelector(selectDirtyMetadataForModId(modId))?.name; const name = dirtyName ?? savedName ?? "Loading..."; - const isDirty = useSelector(selectModIsDirty(modId)); const hasUpdate = latestModVersion != null && @@ -103,7 +101,6 @@ const ModListItem: React.FC = ({ modMetadata, children }) => { modMetadata={modMetadata} isActive={isActive} labelRoot={name} - isDirty={isDirty} /> From 6fd9c5b1646e150e7dff8bc504ff49661ca90530 Mon Sep 17 00:00:00 2001 From: Misha Holtz <36575242+mnholtz@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:24:12 -0700 Subject: [PATCH 07/12] remove isActive prop --- .../modListingPanel/ModActionMenu.tsx | 19 +++++++++---------- .../modListingPanel/ModListItem.tsx | 6 +----- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/pageEditor/modListingPanel/ModActionMenu.tsx b/src/pageEditor/modListingPanel/ModActionMenu.tsx index 51c67eed6a..9b1e87f4e8 100644 --- a/src/pageEditor/modListingPanel/ModActionMenu.tsx +++ b/src/pageEditor/modListingPanel/ModActionMenu.tsx @@ -37,20 +37,18 @@ import useClearModChanges from "@/pageEditor/hooks/useClearModChanges"; import { isInnerDefinitionRegistryId } from "@/types/helpers"; import { actions } from "@/pageEditor/store/editor/editorSlice"; import { useDispatch, useSelector } from "react-redux"; -import { selectModIsDirty } from "@/pageEditor/store/editor/editorSelectors"; +import { + selectActiveModId, + selectModIsDirty, +} from "@/pageEditor/store/editor/editorSelectors"; -type ActionMenuProps = { +const ModActionMenu: React.FC<{ modMetadata: ModMetadata; - isActive: boolean; labelRoot: string; -}; - -const ModActionMenu: React.FC = ({ - modMetadata, - isActive, - labelRoot, -}) => { +}> = ({ modMetadata, labelRoot }) => { const { id: modId } = modMetadata; + const activeModId = useSelector(selectActiveModId); + const dispatch = useDispatch(); const modComponentFormStateAdapters = useAvailableFormStateAdapters(); @@ -61,6 +59,7 @@ const ModActionMenu: React.FC = ({ const isUnsavedMod = isInnerDefinitionRegistryId(modId); const isDirty = useSelector(selectModIsDirty(modId)); + const isActive = activeModId === modId; const menuItems: EllipsisMenuItem[] = [ { diff --git a/src/pageEditor/modListingPanel/ModListItem.tsx b/src/pageEditor/modListingPanel/ModListItem.tsx index faaecf1ca8..b617a3885f 100644 --- a/src/pageEditor/modListingPanel/ModListItem.tsx +++ b/src/pageEditor/modListingPanel/ModListItem.tsx @@ -97,11 +97,7 @@ const ModListItem: React.FC = ({ modMetadata, children }) => { /> )} - + <>{children} From 77ef0e48eac8af8f17c91d445824a174edfcb0e3 Mon Sep 17 00:00:00 2001 From: Misha Holtz <36575242+mnholtz@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:30:38 -0700 Subject: [PATCH 08/12] remove ModListItemProps type --- src/pageEditor/modListingPanel/ModListItem.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/pageEditor/modListingPanel/ModListItem.tsx b/src/pageEditor/modListingPanel/ModListItem.tsx index b617a3885f..3256df0555 100644 --- a/src/pageEditor/modListingPanel/ModListItem.tsx +++ b/src/pageEditor/modListingPanel/ModListItem.tsx @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -import React, { type PropsWithChildren } from "react"; +import React from "react"; import styles from "./Entry.module.scss"; import { ModHasUpdateIcon } from "@/pageEditor/modListingPanel/ModComponentIcons"; import { Accordion, ListGroup } from "react-bootstrap"; @@ -39,11 +39,9 @@ import { useGetModDefinitionQuery } from "@/data/service/api"; import { type ModMetadata } from "@/types/modComponentTypes"; import ModActionMenu from "@/pageEditor/modListingPanel/ModActionMenu"; -export type ModListItemProps = PropsWithChildren<{ +const ModListItem: React.FC<{ modMetadata: ModMetadata; -}>; - -const ModListItem: React.FC = ({ modMetadata, children }) => { +}> = ({ modMetadata, children }) => { const dispatch = useDispatch(); const activeModId = useSelector(selectActiveModId); const expandedModId = useSelector(selectExpandedModId); From 48cd2ed8827852ad3b4eaa114003ed60a50d9756 Mon Sep 17 00:00:00 2001 From: Misha Holtz <36575242+mnholtz@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:40:52 -0700 Subject: [PATCH 09/12] add delete action and modal for unsaved mods --- src/pageEditor/hooks/useDeactivateMod.tsx | 9 ++++++++- .../hooks/useRemoveModComponentFromStorage.tsx | 11 +++++++++++ src/pageEditor/modListingPanel/ModActionMenu.tsx | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/pageEditor/hooks/useDeactivateMod.tsx b/src/pageEditor/hooks/useDeactivateMod.tsx index 5bd851bf2a..270c607ad7 100644 --- a/src/pageEditor/hooks/useDeactivateMod.tsx +++ b/src/pageEditor/hooks/useDeactivateMod.tsx @@ -19,6 +19,7 @@ import { useCallback } from "react"; import { type RegistryId } from "@/types/registryTypes"; import { DEACTIVATE_MOD_MODAL_PROPS, + DELETE_UNSAVED_MOD_MODAL_PROPS, useRemoveModComponentFromStorage, } from "@/pageEditor/hooks/useRemoveModComponentFromStorage"; import { useDispatch, useSelector } from "react-redux"; @@ -29,6 +30,7 @@ import { useModals } from "@/components/ConfirmationModal"; import { actions } from "@/pageEditor/store/editor/editorSlice"; import { getModComponentId, getModId } from "@/pageEditor/utils"; import { clearLog } from "@/background/messenger/api"; +import { isInnerDefinitionRegistryId } from "@/types/helpers"; type Config = { modId: RegistryId; @@ -48,7 +50,12 @@ function useDeactivateMod(): (useDeactivateConfig: Config) => Promise { return useCallback( async ({ modId, shouldShowConfirmation = true }) => { if (shouldShowConfirmation) { - const confirmed = await showConfirmation(DEACTIVATE_MOD_MODAL_PROPS); + const isUnsavedMod = isInnerDefinitionRegistryId(modId); + const confirmed = await showConfirmation( + isUnsavedMod + ? DELETE_UNSAVED_MOD_MODAL_PROPS + : DEACTIVATE_MOD_MODAL_PROPS, + ); if (!confirmed) { return; diff --git a/src/pageEditor/hooks/useRemoveModComponentFromStorage.tsx b/src/pageEditor/hooks/useRemoveModComponentFromStorage.tsx index 27f4dd2a53..b1470c0a52 100644 --- a/src/pageEditor/hooks/useRemoveModComponentFromStorage.tsx +++ b/src/pageEditor/hooks/useRemoveModComponentFromStorage.tsx @@ -59,6 +59,17 @@ export const DEACTIVATE_MOD_MODAL_PROPS: ConfirmationModalProps = { submitCaption: "Deactivate", }; +export const DELETE_UNSAVED_MOD_MODAL_PROPS: ConfirmationModalProps = { + title: "Delete Mod?", + message: ( + <> + This action cannot be undone. If you'd like to deactivate this mod + instead, save the mod first. + + ), + submitCaption: "Delete", +}; + /** * Returns a callback that removes a mod component from the Page Editor and Mod Component Storage. * diff --git a/src/pageEditor/modListingPanel/ModActionMenu.tsx b/src/pageEditor/modListingPanel/ModActionMenu.tsx index 9b1e87f4e8..053b3c151f 100644 --- a/src/pageEditor/modListingPanel/ModActionMenu.tsx +++ b/src/pageEditor/modListingPanel/ModActionMenu.tsx @@ -91,7 +91,7 @@ const ModActionMenu: React.FC<{ }, }, { - title: "Deactivate", + title: isUnsavedMod ? "Delete" : "Deactivate", icon: , async action() { await deactivateMod({ modId }); From 0fab5fffe296266d24068c3f0001fb16317124f6 Mon Sep 17 00:00:00 2001 From: Misha Holtz <36575242+mnholtz@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:42:17 -0700 Subject: [PATCH 10/12] add comment to useDeactivateMod --- src/pageEditor/hooks/useDeactivateMod.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pageEditor/hooks/useDeactivateMod.tsx b/src/pageEditor/hooks/useDeactivateMod.tsx index 270c607ad7..75ecc8d4c2 100644 --- a/src/pageEditor/hooks/useDeactivateMod.tsx +++ b/src/pageEditor/hooks/useDeactivateMod.tsx @@ -38,7 +38,8 @@ type Config = { }; /** - * This hook provides a callback function to deactivate a mod and remove it from the Page Editor + * This hook provides a callback function to deactivate a mod and remove it from the Page Editor. Note that in the case + * of unsaved mods, the mod will be deleted instead of deactivated. */ function useDeactivateMod(): (useDeactivateConfig: Config) => Promise { const dispatch = useDispatch(); From bc0e49705942d96ef2ed1515b9782303e3a7ea25 Mon Sep 17 00:00:00 2001 From: Misha Holtz <36575242+mnholtz@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:48:42 -0700 Subject: [PATCH 11/12] add faTrash icon for unsaved mods --- src/pageEditor/modListingPanel/ModActionMenu.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pageEditor/modListingPanel/ModActionMenu.tsx b/src/pageEditor/modListingPanel/ModActionMenu.tsx index 053b3c151f..02f2653cbc 100644 --- a/src/pageEditor/modListingPanel/ModActionMenu.tsx +++ b/src/pageEditor/modListingPanel/ModActionMenu.tsx @@ -22,6 +22,7 @@ import { faHistory, faPlus, faTimes, + faTrash, } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import styles from "./ActionMenu.module.scss"; @@ -92,7 +93,9 @@ const ModActionMenu: React.FC<{ }, { title: isUnsavedMod ? "Delete" : "Deactivate", - icon: , + icon: ( + + ), async action() { await deactivateMod({ modId }); }, From 0ebab6efff4628620146a4a7039162964f204b2b Mon Sep 17 00:00:00 2001 From: Misha Holtz <36575242+mnholtz@users.noreply.github.com> Date: Wed, 9 Oct 2024 09:17:59 -0700 Subject: [PATCH 12/12] remove TODO comment --- src/pageEditor/modListingPanel/ModActionMenu.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pageEditor/modListingPanel/ModActionMenu.tsx b/src/pageEditor/modListingPanel/ModActionMenu.tsx index 9b1e87f4e8..775ab7a351 100644 --- a/src/pageEditor/modListingPanel/ModActionMenu.tsx +++ b/src/pageEditor/modListingPanel/ModActionMenu.tsx @@ -101,7 +101,6 @@ const ModActionMenu: React.FC<{ return (
- {/* TODO: did we really want to always show SaveButton? That is the current behavior as of 2.1.5-beta.1 */} {