Skip to content

Commit

Permalink
rudimentary merges, add test
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminpkane committed Nov 25, 2024
1 parent 4d554d6 commit d058feb
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,17 @@ import {
useRecoilStateLoadable,
useRecoilValueLoadable,
} from "recoil";
import { collapseFields, getCurrentEnvironment } from "../utils";
import * as atoms from "./atoms";
import { getBrowserStorageEffectForKey } from "./customEffects";
import { collapseFields, getCurrentEnvironment } from "../../utils";
import * as atoms from "../atoms";
import { getBrowserStorageEffectForKey } from "../customEffects";
import {
active3dSlices,
active3dSlicesToSampleMap,
activeModalSidebarSample,
pinned3DSampleSlice,
} from "./groups";
import { isLargeVideo } from "./options";
import { cumulativeValues, values } from "./pathData";
} from "../groups";
import { isLargeVideo } from "../options";
import { cumulativeValues, values } from "../pathData";
import {
buildSchema,
field,
Expand All @@ -53,23 +53,23 @@ import {
filterPaths,
isOfDocumentFieldList,
pathIsShown,
} from "./schema";
import { isFieldVisibilityActive } from "./schemaSettings.atoms";
} from "../schema";
import { isFieldVisibilityActive } from "../schemaSettings.atoms";
import {
datasetName,
disableFrameFiltering,
isVideoDataset,
stateSubscription,
} from "./selectors";
import { State } from "./types";
} from "../selectors";
import { State } from "../types";
import {
fieldsMatcher,
groupFilter,
labelsMatcher,
primitivesMatcher,
unsupportedMatcher,
} from "./utils";
import * as viewAtoms from "./view";
} from "../utils";
import * as viewAtoms from "../view";

export enum EntryKind {
EMPTY = "EMPTY",
Expand Down Expand Up @@ -196,47 +196,6 @@ const DEFAULT_VIDEO_GROUPS: State.SidebarGroup[] = [

const NONE = [null, undefined];

const insertFromNeighbor = (sink: string[], source: string[], key: string) => {
if (sink.includes(key)) {
return;
}
const sourceIndex = source.indexOf(key);
const neighbor = source[sourceIndex - 1];
const neighborIndex = sink.indexOf(neighbor);

!neighbor ? sink.push(key) : sink.splice(neighborIndex + 1, 0, key);
};

const mergeGroups = (
sink: State.SidebarGroup[],
source: State.SidebarGroup[]
) => {
const mapping = Object.fromEntries(sink.map((g) => [g.name, g]));
const configMapping = Object.fromEntries(source.map((g) => [g.name, g]));
const sinkKeys = sink.map(({ name }) => name);
const sourceKeys = source.map(({ name }) => name);
for (const key of sourceKeys) {
insertFromNeighbor(sinkKeys, sourceKeys, key);
}

const resolved = sink.map((g) => mapping[g] ?? configMapping[g]);
for (const g in sink) {
const i = source.indexOf(g);

if (i < 0) {
continue;
}

const gPaths = source[i].paths;

for (const p in gPaths) {
insertFromNeighbor(mapping[g].paths, gPaths, p);
}
}

return resolved;
};

export const resolveGroups = (
sampleFields: StrictField[],
frameFields: StrictField[],
Expand Down
33 changes: 33 additions & 0 deletions app/packages/state/src/recoil/sidebar/sidebar-utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { describe, expect, it, vi } from "vitest";

vi.mock("recoil");
vi.mock("recoil-relay");

import { mergeGroups } from "./sidebar-utils";

describe("test sidebar groups resolution", () => {
it("merges current and config groups", () => {
expect(
mergeGroups(
[
{ name: "one", paths: ["one.one", "one.three"] },
{ name: "three", paths: [] },
],

[
{ name: "zero", paths: [] },
{
name: "one",
paths: ["one.zero", "one.one", "one.two"],
},
{ name: "two", paths: [] },
]
)
).toStrictEqual([
{ name: "zero", paths: [] },
{ name: "one", paths: ["one.zero", "one.one", "one.two", "one.three"] },
{ name: "two", paths: [] },
{ name: "three", paths: [] },
]);
});
});
77 changes: 77 additions & 0 deletions app/packages/state/src/recoil/sidebar/sidebar-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import type { State } from "../types";

const hasNeighbor = (sink: string[], source: string[], key: string) => {
const index = source.indexOf(key);
const before = source[index - 1];
const after = source[index + 1];

return sink.includes(before) || sink.includes(after);
};

const insertFromNeighbor = (sink: string[], source: string[], key: string) => {
if (sink.includes(key)) {
return;
}

const sourceIndex = source.indexOf(key);
const before = source[sourceIndex - 1];
const beforeIndex = sink.indexOf(before);

if (beforeIndex >= 0) {
sink.splice(beforeIndex + 1, 0, key);
return;
}

const after = source[sourceIndex + 1];
const afterIndex = sink.indexOf(after);

if (afterIndex >= 0) {
sink.splice(afterIndex, 0, key);
return;
}

sink.push(key);
return;
};

const merge = (sink: string[], source: string[]) => {
const missing = new Set(source.filter((key) => !sink.includes(key)));

while (missing.size) {
const force = ![...missing].some((name) => hasNeighbor(sink, source, name));
for (const name of missing) {
if (!force && !hasNeighbor(sink, source, name)) {
continue;
}
insertFromNeighbor(sink, source, name);
missing.delete(name);
}
}
};

export const mergeGroups = (
sink: State.SidebarGroup[],
source: State.SidebarGroup[]
) => {
const mapping = Object.fromEntries(sink.map((g) => [g.name, g]));
const configMapping = Object.fromEntries(source.map((g) => [g.name, g]));
const sinkKeys = sink.map(({ name }) => name);
const sourceKeys = source.map(({ name }) => name);

merge(sinkKeys, sourceKeys);

for (const key of sinkKeys) {
mapping[key] = mapping[key] ?? configMapping[key];
}
const resolved = sinkKeys.map((g) => mapping[g] ?? configMapping[g]);
for (const { name } of resolved) {
const i = sourceKeys.indexOf(name);
if (i < 0) {
continue;
}

merge(mapping[name].paths || [], source[i].paths);
}

return resolved;
};

0 comments on commit d058feb

Please sign in to comment.