Skip to content

Commit

Permalink
fix: selector indicator for dataset scope selection
Browse files Browse the repository at this point in the history
also refactors validProjectDataset to use a cleaner lookup
into an object instead of an array.
  • Loading branch information
davidlougheed committed Dec 10, 2024
1 parent 2b25e63 commit 5f21934
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 17 deletions.
6 changes: 3 additions & 3 deletions src/js/components/BentoAppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ const ScopedRoute = () => {
const { projectId, datasetId } = useParams();
const dispatch = useAppDispatch();
const navigate = useNavigate();
const { selectedScope, projects, projectsStatus } = useMetadata();
const { selectedScope, projectsByID, projectsStatus } = useMetadata();

useEffect(() => {
if (WAITING_STATES.includes(projectsStatus)) return; // Wait for projects to load first

// Update selectedScope based on URL parameters
const valid = validProjectDataset(projects, { project: projectId, dataset: datasetId });
const valid = validProjectDataset(projectsByID, { project: projectId, dataset: datasetId });

// Don't change the scope object if the scope value is the same, otherwise it'll trigger needless re-renders.
if (scopeEqual(selectedScope.scope, valid.scope)) {
Expand Down Expand Up @@ -72,7 +72,7 @@ const ScopedRoute = () => {
}
const newPathString = '/' + newPath.join('/');
navigate(newPathString, { replace: true });
}, [projects, projectsStatus, projectId, datasetId, dispatch, navigate, selectedScope]);
}, [projectsByID, projectsStatus, projectId, datasetId, dispatch, navigate, selectedScope]);

return <Outlet />;
};
Expand Down
9 changes: 8 additions & 1 deletion src/js/components/Scope/DatasetScopePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,14 @@ const DatasetScopePicker = ({ parentProject }: DatasetScopePickerProps) => {
<List
dataSource={parentProject.datasets}
bordered
renderItem={(d) => <Dataset parentProjectID={parentProject.identifier} dataset={d} format="list-item" />}
renderItem={(d) => (
<Dataset
parentProjectID={parentProject.identifier}
dataset={d}
format="list-item"
selected={scopeObj.dataset === d.identifier}
/>
)}
/>
</Space>
);
Expand Down
8 changes: 6 additions & 2 deletions src/js/features/metadata/metadata.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ export type DiscoveryScopeSelection = {

export interface MetadataState {
projects: Project[];
projectsByID: Record<string, Project>;
projectsStatus: RequestStatus;
selectedScope: DiscoveryScopeSelection;
}

const initialState: MetadataState = {
projects: [],
projectsByID: {},
projectsStatus: RequestStatus.Idle,
selectedScope: {
scope: { project: undefined, dataset: undefined },
Expand Down Expand Up @@ -66,7 +68,7 @@ const metadata = createSlice({
// Defaults to the narrowest possible scope if there is only 1 project and only 1 dataset.
// This forces Katsu to resolve the Discovery config with fallbacks from the bottom-up:
// dataset -> project -> whole node
state.selectedScope = validProjectDataset(state.projects, payload);
state.selectedScope = validProjectDataset(state.projectsByID, payload);
},
markScopeSet: (state) => {
state.selectedScope.scopeSet = true;
Expand All @@ -77,7 +79,9 @@ const metadata = createSlice({
state.projectsStatus = RequestStatus.Pending;
});
builder.addCase(getProjects.fulfilled, (state, { payload }) => {
state.projects = payload?.results ?? [];
const projects = payload?.results ?? [];
state.projects = projects;
state.projectsByID = Object.fromEntries(projects.map((p) => [p.identifier, p]));
state.projectsStatus = RequestStatus.Fulfilled;
});
builder.addCase(getProjects.rejected, (state) => {
Expand Down
26 changes: 15 additions & 11 deletions src/js/utils/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ export const getCurrentPage = (): string => {
}
};

export const validProjectDataset = (projects: Project[], unvalidatedScope: DiscoveryScope): DiscoveryScopeSelection => {
export const validProjectDataset = (
projectsByID: Record<string, Project>,
unvalidatedScope: DiscoveryScope
): DiscoveryScopeSelection => {
const { project, dataset } = unvalidatedScope;

const valid: DiscoveryScopeSelection = {
Expand All @@ -22,29 +25,30 @@ export const validProjectDataset = (projects: Project[], unvalidatedScope: Disco
fixedDataset: false,
};

const projects = Object.values(projectsByID);

if (projects.length === 1) {
// automatic project scoping if only 1
// Automatic project scoping if only 1
// - if there is only one project, it should be auto-selected, since it contains the same set of data as the node.
const defaultProj = projects[0];
valid.scope.project = defaultProj.identifier;
valid.fixedProject = true;
if (defaultProj.datasets.length === 1) {
// TODO: only if the dataset-level permissions equal the project-level ones...
// automatic dataset scoping if only 1
valid.scope.dataset = defaultProj.datasets[0].identifier;
valid.fixedDataset = true;
// early return to ignore redundant projectId and datasetId
return valid;
}
}
if (project && projects.find(({ identifier }) => identifier === project)) {

const selectedProject: Project | undefined = project ? projectsByID[project] : undefined;

if (project && selectedProject) {
valid.scope.project = project;
if (dataset) {
if (
projects
.find(({ identifier }) => identifier === project)!
.datasets.find(({ identifier }) => identifier === dataset)
) {
valid.scope.dataset = dataset;
}
if (dataset && selectedProject.datasets.find(({ identifier }) => identifier === dataset)) {
valid.scope.dataset = dataset;
}
}
return valid;
Expand Down

0 comments on commit 5f21934

Please sign in to comment.