Skip to content

feat(data-modeling): node selection and relationship editing store and actions COMPASS-9476 #7118

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

Merged
merged 10 commits into from
Jul 21, 2025

Conversation

gribnoysup
Copy link
Collaborator

@gribnoysup gribnoysup commented Jul 17, 2025

This patch adds all required item selection state and actions, including relationship editing, UI is just a rough functional version to validate that it works, this is not in scope for this this ticket and will be addressed in the followups.

Kapture.2025-07-17.at.12.09.05.mp4

I'm adding some tests, but this is ready foe review more or less, store changes are as always the most interesting part here, UI will be changed later

COMPASS-9476

@gribnoysup gribnoysup requested a review from a team as a code owner July 17, 2025 10:13
@github-actions github-actions bot added the feat label Jul 17, 2025
@@ -24,6 +27,7 @@ export type DiagramState =
next: Edit[][];
};
editErrors?: string[];
selectedItems: { type: 'collection' | 'relationship'; id: string } | null;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The root state here is what is actually being selected by the user, sidebar is just driven by this value

Comment on lines 316 to 328
if (
sidePanel.viewType === 'relationship-editing' &&
sidePanel.relationshipFormState.modified
) {
const allowSelect = await showConfirmation({
title: 'You have unsaved chages',
description:
'You are currently editing a relationship. Are you sure you want to select a different collection?',
});
if (!allowSelect) {
return;
}
}
Copy link
Collaborator Author

@gribnoysup gribnoysup Jul 17, 2025

Choose a reason for hiding this comment

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

I'm not sure this behavior is needed, but when playing around with the feature it seemed like a good idea to add it, otherwise it's easy to lose your form state by clicking around (not sure many people will do this though)

const { result: isValid, errors } = validateEdit(edit);
if (!isValid) {
dispatch({
type: DiagramActionTypes.APPLY_EDIT_FAILED,
errors,
});
return;
return isValid;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Returning the value from action so that other actions using it can adjust their behavior if needed, otherwise there's no indication that the action failed. There is currently no validation in the form and strictly speaking we are fully in control there so we can't actually fail this validation, but it might be useful in the future

@gribnoysup gribnoysup changed the title feat(data-modeling): node selection and relationship editing store and actions feat(data-modeling): node selection and relationship editing store and actions COMPASS-9476 Jul 17, 2025
@gribnoysup gribnoysup added the feature flagged PRs labeled with this label will not be included in the release notes of the next release label Jul 17, 2025
Comment on lines +348 to +358
// With threshold too low clicking sometimes gets confused with
// dragging
// @ts-expect-error expose this prop from the component
nodeDragThreshold={3}
// @ts-expect-error expose this prop from the component
onNodeClick={(_evt, node) => {
if (node.type !== 'collection') {
return;
}
onCollectionSelect(node.id);
}}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Note to self: don't forget to open tickets for those changes in diagramming package

return r.id === rId;
});

if (relationship) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add something for the other case (throw or log)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will do!

...state,
edits: {
prev: [...state.edits.prev, state.edits.current],
current: [...state.edits.current, action.edit],
current: [...state.edits.current, action.edit] as [Edit, ...Edit[]],
Copy link
Contributor

Choose a reason for hiding this comment

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

ah.. that's unfortunate that TS doesn't understand this

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah 😞 It's like obviously not empty even if edits.current would be, but alas. I decided to assert instead of adding an assertion method, but tell me if you'd prefer that

@paula-stacho
Copy link
Contributor

paula-stacho commented Jul 18, 2025

I think the selection in the diagram and side drawer should go both ways - e.g. Entering a relationship mode will highlight the relationship and the fields in the diagram (same will go for the field level later on). I think Ben had envisioned it like this as well but I can double check with him today.

@gribnoysup
Copy link
Collaborator Author

Yep, I think I have a better picture after the meeting today and will update the code accordingly, should actually make the state even a bit simpler I think?

}

it('should not render if no items are selected', function () {
renderDrawer();
Copy link
Contributor

Choose a reason for hiding this comment

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

no assertions here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Totally forgot, added something!

@gribnoysup
Copy link
Collaborator Author

@mabaasit @paula-stacho I updated PR based on the discussion we had on Friday, please take a look!

Things I'm leaving for follow-ups to allow to merge this and allow working on other things in parallel.

  • Add name to relationship schema, add name editing
  • Annotate schema types to clarify a few expectations for the field values
  • Filter out "unfinished" relationships from export (I'm actually thinking that maybe it's even okay not to do? Diagramming package handles their rendering just fine and it's probably okay to have them in export, just doesn't sound like something we need to spend much time handling)

foreignCardinality: string;
};

const FIELD_DIVIDER = '~~##$$##~~';
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There's always a chance someone will have a field like that, but that's probably rare enough?

);
}

export const selectRelationshipForCurrentModel = memoize(
Copy link
Contributor

@paula-stacho paula-stacho Jul 21, 2025

Choose a reason for hiding this comment

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

I keep seeing the same relationship in the drawer. I'm pretty sure it's because, weirdly, lodash's memoize only uses the first argument as cache key by default! https://lodash.info/doc/memoize.
We can either provide our own cache function to memoize, or maybe look into reselect instead? https://redux.js.org/usage/deriving-data-selectors#writing-memoized-selectors-with-reselect.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah, whoops, that's on me for checking on a diagram with only one relationship 😆 I'll fix and add a test, good catch

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated in fad816b, compiling a cache key there is probably pricier than just doing filtering every time, so I just dropped the memo part there

markerStart: source.cardinality === 1 ? 'one' : 'many',
markerEnd: target.cardinality === 1 ? 'one' : 'many',
selected: selectedItem === relationship.id,
Copy link
Contributor

Choose a reason for hiding this comment

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

I know the odds are slim but should we check for the type as well?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated in a2967fd

@paula-stacho
Copy link
Contributor

I still find it kinda weird that there's no option to go back, but we can add it later.

@gribnoysup
Copy link
Collaborator Author

If we ever need it, this would basically be just adding a history to the selectedItem state, so easy enough if we decided to do that, but FWIW none of the tools that have similar context sidebars (I'm mostly familiar with CAD stuff) have navigation like that in drawers

@gribnoysup gribnoysup requested a review from paula-stacho July 21, 2025 13:12
Copy link
Contributor

@paula-stacho paula-stacho left a comment

Choose a reason for hiding this comment

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

neat, thank you! 🎉

@gribnoysup gribnoysup merged commit 20cb662 into main Jul 21, 2025
55 of 57 checks passed
@gribnoysup gribnoysup deleted the COMPASS-9476 branch July 21, 2025 14:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat feature flagged PRs labeled with this label will not be included in the release notes of the next release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants