Skip to content

Commit

Permalink
configure: wip refactor sync system + rendering basic policy
Browse files Browse the repository at this point in the history
  • Loading branch information
oscartbeaumont committed Jul 25, 2024
1 parent 4fde89a commit a01de46
Show file tree
Hide file tree
Showing 12 changed files with 768 additions and 190 deletions.
72 changes: 72 additions & 0 deletions apps/configure/src/components/search/FilterBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import {
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
Input,
Kbd,
Popover,
PopoverContent,
PopoverTrigger,
Tooltip,
TooltipContent,
TooltipTrigger,
Expand All @@ -27,6 +31,7 @@ import {
} from "solid-js";
import { db } from "~/lib/db";
import type { createSearchPageContext } from ".";
import { entities } from "./configuration";
import type { Filter } from "./filters";

export function FilterBar(props: ReturnType<typeof createSearchPageContext>) {
Expand Down Expand Up @@ -168,10 +173,55 @@ function AppliedFilters(props: {
</Switch>
)}
</For>

{/* <DemoFilters /> */}
</div>
);
}

// TODO: Remove this
function DemoFilters() {
return (
<FilterContainer>
{/* // TODO: Dropdown and allow selecting multiple columns. Eg. search for X in name or description only */}
<StaticSection>
<IconPhEnvelope />
<FilterText>Email</FilterText>
</StaticSection>

<DropdownMenu>
<DropdownMenuTrigger
as={InteractiveSection}
class="border-l px-2 hover:bg-gray-200"
>
equals
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>equals</DropdownMenuItem>
<DropdownMenuItem>not equals</DropdownMenuItem>
<DropdownMenuItem>contains</DropdownMenuItem>
<DropdownMenuItem>starts with</DropdownMenuItem>
<DropdownMenuItem>ends with</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>

<Popover>
<PopoverTrigger
as={InteractiveSection}
class="gap-1 border-l border-gray-800/70 py-0.5 pl-1.5 pr-2 text-sm hover:bg-gray-200"
>
Testing
</PopoverTrigger>
<PopoverContent>
<Input value="Testing" />
</PopoverContent>
</Popover>

<RemoveFilter />
</FilterContainer>
);
}

export const FilterContainer = (props: ComponentProps<"div">) => (
<div
class={clsx(
Expand Down Expand Up @@ -347,6 +397,28 @@ function AddFilterButton(props: {
</DropdownMenuPortal>
</DropdownMenuSub>

<For
each={Object.entries(entities).flatMap(([k, e]) =>
Object.entries(e.filters || {}).map(
([kk, e]) => [k, kk, e] as const,
),
)}
>
{([entityKey, filterKey, filter]) => (
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<span class="mr-2">{filter.icon ?? null}</span>
{filter.title}
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuItem>TODO</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
)}
</For>

{/* // TODO: Query by membership in group */}

{/* // TODO: This should probs only show up when filtered to devices */}
Expand Down
84 changes: 52 additions & 32 deletions apps/configure/src/components/search/TableContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export function TableContent(
setOrderedBy(key);
};

// TODO: Make this reactive to DB changes!!!
const rawData = createAsync(async () => {
const result = (
await Promise.all(
Expand Down Expand Up @@ -186,6 +187,8 @@ export function TableContent(

let tableHeaderRowRef!: HTMLTableRowElement;

const [dragging, setDragging] = createSignal();

return (
<>
<div class="flex space-x-4">
Expand Down Expand Up @@ -222,36 +225,7 @@ export function TableContent(
</Popover>
</div>

<Table
ref={(table) => observe(table)}
// TODO: `onDrag` instead of `onDragEnd`???
onDragEnd={(e) => {
let moveAfter: string | null;
for (const child of tableHeaderRowRef.children) {
const colKey = child.getAttribute("data-col-key");
const endPosition = child.getBoundingClientRect().left;

if (e.clientX > endPosition) {
moveAfter = colKey;
}
}

console.log("MOVE AFTER", moveAfter);

setColumns((columns) => {
const newColumns = [...columns];
const [draggedColumn] = newColumns.splice(
newColumns.findIndex(([key]) => key === e.data),
1,
);
const insertIndex = newColumns.findIndex(
([key]) => key === moveAfter,
);
newColumns.splice(insertIndex, 0, draggedColumn);
return newColumns;
});
}}
>
<Table ref={(table) => observe(table)}>
<TableHeader>
{/* // TODO: We need to handle grouped columns by having multiple `TableRows`'s (for columns on 1-1 relations Eg. user name on device owner) */}
<TableRow class="flex" ref={tableHeaderRowRef}>
Expand All @@ -276,6 +250,7 @@ export function TableContent(
{([key, column]) => {
let ref!: HTMLTableCellElement;

// TODO: Move up and use other signal????
const [isDragging, setIsDragging] = createSignal(false);
createEventListener(ref, "mouseup", () => setIsDragging(false));

Expand All @@ -289,9 +264,51 @@ export function TableContent(
? { width: `${columnWidths[key]}px` }
: { flex: "1" }),
}}
draggable={isDragging()}
draggable={dragging() !== undefined}
// TODO: Keep or not
data-col-key={key}
onDragEnter={(e) => {
const draggingOverKey =
e.currentTarget.getAttribute("data-col-key");

console.log(draggingOverKey, dragging());

setColumns((columns) => {
const newColumns = [...columns];
const [draggedColumn] = newColumns.splice(
newColumns.findIndex(([key]) => key === dragging()),
1,
);
const insertIndex = newColumns.findIndex(
([key]) => key === draggingOverKey,
);
newColumns.splice(insertIndex, 0, draggedColumn);
return newColumns;
});
}}
onDragExit={(e) => {
const draggingOverKey =
e.currentTarget.getAttribute("data-col-key");

console.log(draggingOverKey, dragging());

setColumns((columns) => {
const newColumns = [...columns];
const [draggedColumn] = newColumns.splice(
newColumns.findIndex(([key]) => key === dragging()),
1,
);
const insertIndex = newColumns.findIndex(
([key]) => key === draggingOverKey,
);
newColumns.splice(insertIndex, 0, draggedColumn);
return newColumns;
});
}}
onDragEnd={() => {
setIsDragging(false);
setDragging(undefined);
}}
>
{column.header}

Expand Down Expand Up @@ -326,7 +343,10 @@ export function TableContent(
{/* // TODO: Tooltip */}
<IconPhDotsSixVerticalLight
class="ml-2 h-4 w-4 cursor-grab"
onMouseDown={() => setIsDragging(true)}
onMouseDown={() => {
setDragging(key);
setIsDragging(true);
}}
/>

<ColumnResizeBar
Expand Down
37 changes: 29 additions & 8 deletions apps/configure/src/components/search/configuration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,31 @@ export const entities = {
},
// TODO: Assign to group
},
// filters: {
// device: {
// type: "enum",
// target: "device",
// value: "Device",
// },
// }
// },
// TODO: Should filters be a global thing or scoped to the entity???
filters: {
email: {
title: "Email",
icon: IconPhEnvelope,
operations: [
// TODO: Allow the user to define `string[]` for it
{
title: "in",
apply: (data) => {},
},
{
title: "not in",
apply: (data) => {},
},
// TODO: Allow the user to define `string` using Combobox (with values from DB)
{
title: "equals",
apply: (data) => {},
},
],
// render: (data) => data.email,
},
},
// TODO: Relations
}),
devices: defineEntity({
load: async () => await (await db).getAll("devices"),
Expand Down Expand Up @@ -144,6 +161,7 @@ export const entities = {
},
// TODO: Maybe "Send notification"???
},
filters: {},
}),
groups: defineEntity({
load: async () => await (await db).getAll("groups"),
Expand Down Expand Up @@ -174,6 +192,7 @@ export const entities = {
apply: async (data) => alert("TODO: Bulk delete"),
},
},
filters: {},
}),
policies: defineEntity({
load: async () => await (await db).getAll("policies"),
Expand Down Expand Up @@ -204,6 +223,7 @@ export const entities = {
apply: async (data) => alert("TODO: Bulk delete"),
},
},
filters: {},
}),
apps: defineEntity({
load: async () => await (await db).getAll("apps"),
Expand Down Expand Up @@ -234,5 +254,6 @@ export const entities = {
apply: async (data) => alert("TODO: Bulk delete"),
},
},
filters: {},
}),
} satisfies Record<string, Entity<any>>;
14 changes: 13 additions & 1 deletion apps/configure/src/components/search/filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function defineEntity<T>(entity: Entity<T>) {
export type Entity<T> = {
load: () => Promise<T[]>;
columns: ColumnDefinitions<T>;
filters?: never[];
filters: FilterDefinitions<T>;
actions: ActionDefinitions<T>;
};

Expand Down Expand Up @@ -58,3 +58,15 @@ export type ActionDefinitions<T> = Record<
apply: (data: T[]) => Promise<void>;
}
>;

export type FilterDefinitions<T> = Record<
// Used to uniquely identify the semantic meaning of the column.
// These will be merged across entities using the first `title`/`icon` that is discovered.
string,
{
title: string;
icon?: JSX.Element;

// TODO: Define filters apply filters
}
>;
Loading

0 comments on commit a01de46

Please sign in to comment.