Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop currentModId as a concept #9490

Merged
merged 26 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
673db25
alphebetize keys
grahamlangford Nov 8, 2024
2d02c7e
remove need for currentModId
grahamlangford Nov 8, 2024
6897a14
further refactoring
grahamlangford Nov 8, 2024
0d47f6c
cleanup
grahamlangford Nov 11, 2024
f79ce3f
Merge branch 'main' of github.com:pixiebrix/pixiebrix-extension into …
grahamlangford Nov 11, 2024
de301d1
restore ListGroup
grahamlangford Nov 11, 2024
85468d6
favor migration over invariant checks
grahamlangford Nov 11, 2024
340052c
2.1.8 -> 2.2.0
grahamlangford Nov 11, 2024
0c29e99
merge main
grahamlangford Nov 12, 2024
44c59be
Merge branch 'main' of github.com:pixiebrix/pixiebrix-extension into …
grahamlangford Nov 12, 2024
55c28b8
currentModId -> activeModId
grahamlangford Nov 12, 2024
9d033d7
add watch command
grahamlangford Nov 12, 2024
4079cdc
fix setActiveModId import
grahamlangford Nov 12, 2024
0b5c188
fix editor state invariant when saving a new mod
grahamlangford Nov 12, 2024
b12c321
fix activeModCompnent deselection during save
grahamlangford Nov 12, 2024
7411ca9
remove console log
grahamlangford Nov 12, 2024
d94521c
fix type issues
grahamlangford Nov 12, 2024
0dd9aad
Merge branch 'main' of github.com:pixiebrix/pixiebrix-extension into …
grahamlangford Nov 12, 2024
36f02ca
fix active mod component id selection during save
grahamlangford Nov 12, 2024
db356f3
fix lint error
grahamlangford Nov 12, 2024
d883a30
merge main
grahamlangford Nov 13, 2024
d99d59e
Merge branch 'main' into refactor/drop-unnecessary-editor-state
grahamlangford Nov 13, 2024
75275aa
remove playwright command from source package.json
grahamlangford Nov 13, 2024
464ec34
Merge branch 'main' of github.com:pixiebrix/pixiebrix-extension into …
grahamlangford Nov 13, 2024
bcd9a61
merge main
grahamlangford Nov 14, 2024
3b48053
only collapse the mod on click when it's active
grahamlangford Nov 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ test("can save a new trigger mod", async ({

test("#9349: can save new mod with multiple components", async ({
page,
extensionId,
newPageEditorPage,
}) => {
await page.goto("/");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import { actions } from "@/pageEditor/store/editor/editorSlice";
import { modComponentToFormState } from "@/pageEditor/starterBricks/adapter";
import {
selectCurrentModId,
selectActiveModId,
selectGetUntouchedActivatedModComponentsForMod,
} from "@/pageEditor/store/editor/editorSelectors";
import { useDispatch, useSelector } from "react-redux";
Expand All @@ -30,13 +30,13 @@ import { useEffect } from "react";
*/
function useEnsureFormStates(): void {
const dispatch = useDispatch();
const currentModId = useSelector(selectCurrentModId);
const activeModId = useSelector(selectActiveModId);
const getUntouchedActivatedModComponentsForMod = useSelector(
selectGetUntouchedActivatedModComponentsForMod,
);

const untouchedModComponents = currentModId
? getUntouchedActivatedModComponentsForMod(currentModId)
const untouchedModComponents = activeModId
? getUntouchedActivatedModComponentsForMod(activeModId)
: null;

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { useDispatch, useSelector } from "react-redux";
import {
selectActiveModComponentFormState,
selectActiveModComponentId,
selectCurrentModId,
selectActiveModId,
selectEditorUpdateKey,
selectGetModDraftStateForModId,
} from "@/pageEditor/store/editor/editorSelectors";
Expand Down Expand Up @@ -113,7 +113,7 @@ function updateDraftModInstance() {
const state = getState();

const activeModComponentId = selectActiveModComponentId(state);
const modId = selectCurrentModId(state);
const modId = selectActiveModId(state);

if (!modId) {
// Skip if the modId has somehow become null before the microtask for this async method got scheduled
Expand Down Expand Up @@ -175,7 +175,7 @@ function updateDraftModInstance() {
*/
function useRegisterDraftModInstanceOnAllFrames(): void {
const dispatch = useDispatch<AppDispatch>();
const modId = useSelector(selectCurrentModId);
const modId = useSelector(selectActiveModId);
const editorUpdateKey = useSelector(selectEditorUpdateKey);

assertNotNullish(modId, "modId is required");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
import { useDispatch, useSelector } from "react-redux";
import cx from "classnames";
import {
selectActiveModComponentFormState,
selectActiveModComponentId,
selectActiveModId,
selectDirtyMetadataForModId,
selectExpandedModId,
Expand All @@ -47,24 +47,19 @@ const ModListItem: React.FC<
const dispatch = useDispatch();
const activeModId = useSelector(selectActiveModId);
const expandedModId = useSelector(selectExpandedModId);
const activeModComponentFormState = useSelector(
selectActiveModComponentFormState,
);
const activeModComponentId = useSelector(selectActiveModComponentId);

const { id: modId, name: savedName, version: activatedVersion } = modMetadata;

const isActive = activeModId === modId;
const isModActive = activeModId === modId;
const isModComponentActive = activeModComponentId != null;
const isExpanded = expandedModId === modId;

// TODO: Fix this so it pulls from registry, after registry single-item-api-fetch is implemented
// (See: https://github.com/pixiebrix/pixiebrix-extension/issues/7184)
const { data: modDefinition } = useGetModDefinitionQuery({ modId });
const latestModVersion = modDefinition?.metadata?.version;

// Set the alternate background if a mod component in this mod is active
const hasModBackground =
activeModComponentFormState?.modMetadata.id === modId;

const dirtyName = useSelector(selectDirtyMetadataForModId(modId))?.name;
const name = dirtyName ?? savedName ?? "Loading...";

Expand All @@ -81,17 +76,16 @@ const ModListItem: React.FC<
eventKey={modId}
as={ListGroup.Item}
className={cx(styles.root, "list-group-item-action", {
[styles.modBackground ?? ""]: hasModBackground,
// Set the alternate background if a mod component in this mod is active
[styles.modBackground ?? ""]: isModActive && isModComponentActive,
})}
tabIndex={0} // Avoid using `button` because this item includes more buttons #2343
active={isActive}
key={`mod-${modId}`}
active={isModActive && !isModComponentActive}
key={modId}
onClick={() => {
dispatch(actions.setActiveModId(modId));
// Collapse if the user clicks the mod item when it's already active/selected in the listing pane
dispatch(
actions.setExpandedModId(isExpanded && isActive ? null : modId),
);
dispatch(actions.setExpandedModId(isExpanded ? null : modId));
}}
>
<span className={styles.icon}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,25 +77,33 @@ const ModSidebarListItems: React.FunctionComponent = () => {
],
);

const listItems = filteredSidebarItems.map((sidebarItem) => {
const { modMetadata, modComponents } = sidebarItem;
const listItems = useMemo(
() =>
filteredSidebarItems.map((sidebarItem) => {
const { modMetadata, modComponents } = sidebarItem;

return (
<ModListItem key={modMetadata.id} modMetadata={modMetadata}>
{modComponents.map((modComponentSidebarItem) => (
<ModComponentListItem
key={getDraftModComponentId(modComponentSidebarItem)}
modComponentSidebarItem={modComponentSidebarItem}
availableActivatedModComponentIds={
availableActivatedModComponentIds
}
availableDraftModComponentIds={availableDraftModComponentIds}
isNested
/>
))}
</ModListItem>
);
});
return (
<ModListItem key={modMetadata.id} modMetadata={modMetadata}>
{modComponents.map((modComponentSidebarItem) => (
<ModComponentListItem
key={getDraftModComponentId(modComponentSidebarItem)}
modComponentSidebarItem={modComponentSidebarItem}
availableActivatedModComponentIds={
availableActivatedModComponentIds
}
availableDraftModComponentIds={availableDraftModComponentIds}
isNested
/>
))}
</ModListItem>
);
}),
[
availableActivatedModComponentIds,
availableDraftModComponentIds,
filteredSidebarItems,
],
);

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { useDispatch, useSelector } from "react-redux";
import {
getModalDataSelector,
selectActiveModComponentFormState,
selectCurrentModId,
selectActiveModId,
selectEditorModalVisibilities,
selectModMetadataMap,
} from "@/pageEditor/store/editor/editorSelectors";
Expand Down Expand Up @@ -138,8 +138,8 @@ const CreateModModalBody: React.FC<{ onHide: () => void }> = ({ onHide }) => {
const dispatch = useDispatch();
const isMounted = useIsMounted();

const currentModId = useSelector(selectCurrentModId);
assertNotNullish(currentModId, "Expected mod or mod component to be active");
const activeModId = useSelector(selectActiveModId);
assertNotNullish(activeModId, "Expected mod or mod component to be active");

const activeModComponentFormState = useSelector(
selectActiveModComponentFormState,
Expand All @@ -156,11 +156,11 @@ const CreateModModalBody: React.FC<{ onHide: () => void }> = ({ onHide }) => {
const { createModFromComponent } = useCreateModFromModComponent();

const { data: modDefinition, isFetching: isModDefinitionFetching } =
useOptionalModDefinition(currentModId);
useOptionalModDefinition(activeModId);

const formSchema = useFormSchema();

const initialFormState = useInitialFormState(currentModId);
const initialFormState = useInitialFormState(activeModId);

const onSubmit: OnSubmit<ModMetadataFormState> = async (values, helpers) => {
if (isModDefinitionFetching) {
Expand All @@ -185,10 +185,10 @@ const CreateModModalBody: React.FC<{ onHide: () => void }> = ({ onHide }) => {
) {
// Handle "Save As" case where the mod is unsaved or the user no longer has access to the mod definition
assertNotNullish(
currentModId,
activeModId,
"Expected mod to be selected in the editor",
);
await createModFromUnsavedMod(currentModId, values);
await createModFromUnsavedMod(activeModId, values);
} else {
await createModFromMod(modDefinition, values, modalData);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { useDispatch, useSelector } from "react-redux";
import { actions } from "@/pageEditor/store/editor/editorSlice";
import { Button, Modal } from "react-bootstrap";
import {
selectCurrentModId,
selectActiveModId,
selectEditorModalVisibilities,
} from "@/pageEditor/store/editor/editorSelectors";
import { useOptionalModDefinition } from "@/modDefinitions/modDefinitionHooks";
Expand All @@ -32,7 +32,7 @@ const SaveAsNewModModal: React.FC = () => {
selectEditorModalVisibilities,
);

const modId = useSelector(selectCurrentModId);
const modId = useSelector(selectActiveModId);
const { data: mod, isFetching } = useOptionalModDefinition(modId);
const modName = mod?.metadata?.name ?? "this mod";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@
import type { AnyAction, Dispatch, Middleware } from "@reduxjs/toolkit";
import { type EditorRootState } from "@/pageEditor/store/editor/pageEditorTypes";
import {
selectActiveModComponentId,
selectActiveModComponentFormState,
selectActiveModId,
selectAllDeletedModComponentIds,
selectCurrentModId,
selectExpandedModId,
selectModComponentFormStates,
} from "@/pageEditor/store/editor/editorSelectors";
import type { EmptyObject } from "type-fest";
import { uniqBy } from "lodash";
import { isInternalRegistryId } from "@/utils/registryUtils";

class InvariantViolationError extends Error {
override name = "InvariantViolationError";
Expand All @@ -48,17 +48,28 @@ class InvariantViolationError extends Error {
// XXX: in production, should we be attempting to auto-fix these invariants?
export function assertEditorInvariants(state: EditorRootState): void {
// Assert that a mod and mod component item cannot be selected at the same time
if (selectActiveModId(state) && selectActiveModComponentId(state)) {
const activeModId = selectActiveModId(state);
const activeModComponent = selectActiveModComponentFormState(state);

if (
activeModId &&
activeModComponent &&
activeModId !== activeModComponent?.modMetadata.id &&
// When saving, the activeModId and activeModComponent.modMetadata.id aren't updated at the same time.
!isInternalRegistryId(activeModId)
) {
// Should we dispatch(actions.setActiveModComponentId(null))
// Would need to change the behavior of the action to handle null
throw new InvariantViolationError(
"activeModId and activeModComponentId are both set",
"activeModComponent is not a part of the activeMod",
);
}

// Assert that the expanded mod must correspond to the selected mod or mod component
const expandedModId = selectExpandedModId(state);
if (expandedModId && selectCurrentModId(state) !== expandedModId) {
if (expandedModId && activeModId !== expandedModId) {
throw new InvariantViolationError(
"expandedModId does not match active mod/mod component",
"expandedModId does not match active mod",
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import type { DataPanelTabKey } from "@/pageEditor/tabs/editTab/dataPanel/dataPa
import { createSelector } from "@reduxjs/toolkit";
import type { DataPanelTabUIState } from "@/pageEditor/store/editor/uiStateTypes";
import { selectActiveBrickConfigurationUIState } from "@/pageEditor/store/editor/editorSelectors/editorPipelineSelectors";
import { selectCurrentModId } from "@/pageEditor/store/editor/editorSelectors/editorModSelectors";
import { selectActiveModId } from "@/pageEditor/store/editor/editorSelectors/editorNavigationSelectors";

export const selectIsDataPanelExpanded = ({ editor }: EditorRootState) =>
editor.isDataPanelExpanded;
Expand Down Expand Up @@ -55,9 +55,9 @@ export function selectNodeDataPanelTabState(
*/
export const selectCurrentFindInModQuery = createSelector(
({ editor }: EditorRootState) => editor.findInModQueryByModId,
selectCurrentModId,
selectActiveModId,
(findInModQueryByModId, modId) => {
assertNotNullish(modId, "Expected currentModId");
assertNotNullish(modId, "Expected activeModId");
// eslint-disable-next-line security/detect-object-injection -- registry id
return findInModQueryByModId[modId] ?? { query: "" };
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,11 @@ import { selectModInstances } from "@/store/modComponents/modInstanceSelectors";
import mapModDefinitionToModMetadata from "@/modDefinitions/util/mapModDefinitionToModMetadata";
import { normalizeModOptionsDefinition } from "@/utils/modUtils";
import {
selectActiveModComponentFormState,
selectGetModComponentFormStateByModComponentId,
selectIsModComponentDirtyById,
selectModComponentFormStates,
selectNotDeletedActivatedModComponents,
} from "@/pageEditor/store/editor/editorSelectors/editorModComponentSelectors";
import { selectActiveModId } from "@/pageEditor/store/editor/editorSelectors/editorNavigationSelectors";
import type { ModMetadata } from "@/types/modComponentTypes";
import type { UUID } from "@/types/stringTypes";
import { assertNotNullish } from "@/utils/nullishUtils";
Expand All @@ -39,19 +37,6 @@ import {
collectModVariablesDefinition,
} from "@/store/modComponents/modComponentUtils";

/**
* Select the mod id associated with the selected mod package or mod component. Should be used if the caller doesn't
* need to know if the mod item or one of its components is selected.
* @see selectActiveModId
* @see selectExpandedModId
*/
export const selectCurrentModId = createSelector(
selectActiveModId,
selectActiveModComponentFormState,
(activeModId, activeModComponentFormState) =>
activeModId ?? activeModComponentFormState?.modMetadata.id,
);

///
/// MOD METADATA
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ export const selectActiveModComponentId = ({ editor }: EditorRootState) => {
};

/**
* Select the id of the mod being edited. NOTE: is null when editing a mod component within the mod.
* Select the id of the mod being edited.
* @see selectModId
* @see selectCurrentModId
*/
export const selectActiveModId = ({ editor }: EditorRootState) =>
editor.activeModId;
Expand Down
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated, just noticed while debugging

Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ export const selectActiveNodeInfo = createSelector(
const activeModComponentNodeInfoSelector = createSelector(
selectActiveBrickPipelineUIState,
(_state: EditorRootState, instanceId: UUID) => instanceId,
(uiState: BrickPipelineUIState, instanceId: UUID) =>
(uiState, instanceId) =>
// eslint-disable-next-line security/detect-object-injection -- using a node uuid
uiState.pipelineMap[instanceId],
uiState?.pipelineMap[instanceId],
);

export const selectActiveModComponentNodeInfo =
Expand Down Expand Up @@ -103,21 +103,21 @@ export const selectActiveNodeEventData = createSelector(

export const selectPipelineMap = createSelector(
selectActiveBrickPipelineUIState,
(uiState: BrickPipelineUIState) => uiState?.pipelineMap,
(uiState) => uiState?.pipelineMap,
);

export const selectCollapsedNodes = createSelector(
selectActiveBrickPipelineUIState,
(brickPipelineUIState: BrickPipelineUIState) =>
Object.entries(brickPipelineUIState.nodeUIStates)
(brickPipelineUIState) =>
Object.entries(brickPipelineUIState?.nodeUIStates ?? {})
.map(([nodeId, { collapsed }]) => (collapsed ? nodeId : null))
.filter((nodeId) => nodeId != null),
);

const parentNodeInfoSelector = createSelector(
selectActiveBrickPipelineUIState,
(_state: EditorRootState, nodeId: UUID) => nodeId,
(brickPipelineUIState: BrickPipelineUIState, nodeId: UUID) => {
(brickPipelineUIState, nodeId) => {
if (brickPipelineUIState == null) {
return null;
}
Expand Down
Loading
Loading