diff --git a/.yarnrc.yml b/.yarnrc.yml
index 9c65c37f..c7ebb9ad 100644
--- a/.yarnrc.yml
+++ b/.yarnrc.yml
@@ -10,6 +10,10 @@ packageExtensions:
dependencies:
supports-color: "*"
+ '@next/react-dev-overlay@*':
+ peerDependencies:
+ react: '*'
+
pnpFallbackMode: all
pnpMode: loose
diff --git a/package.json b/package.json
index cbf0cb5b..8244fe3f 100644
--- a/package.json
+++ b/package.json
@@ -56,6 +56,7 @@
"@blueprintjs/table": "^5.1.4",
"@lagunovsky/redux-react-router": "^3.2.0",
"@loadable/component": "^5.14.1",
+ "@macrostrat-web/column-builder": "workspace:*",
"@macrostrat-web/globe": "workspace:*",
"@macrostrat-web/lithology-hierarchy": "workspace:*",
"@macrostrat-web/map-utils": "workspace:*",
diff --git a/packages/column-builder/.eslintrc.json b/packages/column-builder/.eslintrc.json
new file mode 100644
index 00000000..bffb357a
--- /dev/null
+++ b/packages/column-builder/.eslintrc.json
@@ -0,0 +1,3 @@
+{
+ "extends": "next/core-web-vitals"
+}
diff --git a/packages/column-builder/.gitignore b/packages/column-builder/.gitignore
new file mode 100644
index 00000000..bb6aaf6b
--- /dev/null
+++ b/packages/column-builder/.gitignore
@@ -0,0 +1,44 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+_node_modules
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+.yarn/cache
+.yarn/install-state.gz
+.yarn/unplugged
+
+.pnp*
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# local env files
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+.env.production
+.env.development
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
diff --git a/packages/column-builder/README.md b/packages/column-builder/README.md
new file mode 100644
index 00000000..24be3143
--- /dev/null
+++ b/packages/column-builder/README.md
@@ -0,0 +1,33 @@
+This web application is based on [Next.js](https://nextjs.org/) and installed using Yarn PnP.
+
+
+## Getting Started
+
+**You should use Yarn (>v2), not NPM, to install this application.
+Everything is set up for "Plug'n'Play" modules.**
+
+1. Install modules: `yarn`
+2. Run the development server: `yarn run dev`.
+
+Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+
+You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
+
+[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
+
+The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
+
+## Learn More
+
+To learn more about Next.js, take a look at the following resources:
+
+- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
+- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+
+You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
+
+## Deploy on Vercel
+
+The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+
+Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
diff --git a/packages/column-builder/__archive/.dockerignore b/packages/column-builder/__archive/.dockerignore
new file mode 100644
index 00000000..4c7db2f3
--- /dev/null
+++ b/packages/column-builder/__archive/.dockerignore
@@ -0,0 +1,8 @@
+Dockerfile
+.dockerignore
+node_modules
+npm-debug.log
+README.md
+.next
+docker
+.git
\ No newline at end of file
diff --git a/packages/column-builder/__archive/Dockerfile b/packages/column-builder/__archive/Dockerfile
new file mode 100644
index 00000000..9a54540c
--- /dev/null
+++ b/packages/column-builder/__archive/Dockerfile
@@ -0,0 +1,14 @@
+FROM node:14.19
+
+WORKDIR /app/dacite
+
+COPY package*.json ./
+COPY deps/web-components/packages/ui-components/package.json ./deps/web-components/packages/ui-components/
+COPY deps/web-components/packages/form-components/package.json ./deps/web-components/packages/form-components/
+COPY deps/web-components/packages/data-components/package.json ./deps/web-components/packages/data-components/
+
+RUN npm install
+
+EXPOSE 1234
+
+CMD ["npm", "run", "dev"]
\ No newline at end of file
diff --git a/packages/column-builder/__archive/prod.Dockerfile b/packages/column-builder/__archive/prod.Dockerfile
new file mode 100644
index 00000000..1e4d4d78
--- /dev/null
+++ b/packages/column-builder/__archive/prod.Dockerfile
@@ -0,0 +1,30 @@
+FROM node:16-alpine AS builder
+
+WORKDIR /app/
+COPY . .
+
+RUN npm install
+
+# This will do the trick, use the corresponding env file for each environment.
+COPY ./.env.production .
+
+RUN npm run build
+
+# 3. Production image, copy all the files and run next
+FROM node:16-alpine AS runner
+WORKDIR /app/
+
+ENV NODE_ENV=production
+
+# # You only need to copy next.config.js if you are NOT using the default configuration
+COPY --from=builder /app/.env.production ./
+COPY --from=builder /app/next.config.js ./
+COPY --from=builder /app/package.json ./package.json
+COPY --from=builder /app/node_modules ./node_modules
+COPY --from=builder /app/.next ./.next
+
+EXPOSE 1234
+
+ENV PORT 1234
+
+CMD ["npm", "run", "start"]
\ No newline at end of file
diff --git a/packages/column-builder/env.example b/packages/column-builder/env.example
new file mode 100644
index 00000000..5e371937
--- /dev/null
+++ b/packages/column-builder/env.example
@@ -0,0 +1,11 @@
+## place this into an .env.development file in this directory!!
+NEXT_PUBLIC_SERVER_URL=http://localhost:3001
+NEXT_PUBLIC_CLIENT_URL=http://localhost:3001
+NEXT_PUBLIC_TOPOLOGY_URL=http://localhost:1235
+NEXT_PUBLIC_BASE_URL=
+
+## .env.production
+NEXT_PUBLIC_SERVER_URL=http://postgrest:3001
+NEXT_PUBLIC_CLIENT_URL=http://localhost:3001
+NEXT_PUBLIC_TOPOLOGY_URL=http://localhost:1235
+NEXT_PUBLIC_BASE_URL=/dacite
diff --git a/packages/column-builder/next-env.d.ts b/packages/column-builder/next-env.d.ts
new file mode 100644
index 00000000..4f11a03d
--- /dev/null
+++ b/packages/column-builder/next-env.d.ts
@@ -0,0 +1,5 @@
+///
+///
+
+// NOTE: This file should not be edited
+// see https://nextjs.org/docs/basic-features/typescript for more information.
diff --git a/packages/column-builder/next.config.js b/packages/column-builder/next.config.js
new file mode 100644
index 00000000..6a8bf86d
--- /dev/null
+++ b/packages/column-builder/next.config.js
@@ -0,0 +1,48 @@
+/** @type {import('next').NextConfig} */
+const path = require("path");
+
+const packageSrc = (name) =>
+ path.resolve(
+ __dirname,
+ "..",
+ "..",
+ "deps",
+ "web-components",
+ "packages",
+ name,
+ "src"
+ );
+
+const nextConfig = {
+ assetPrefix: process.env.NEXT_PUBLIC_BASE_URL,
+ basePath: process.env.NEXT_PUBLIC_BASE_URL,
+ typescript: {
+ ignoreBuildErrors: true,
+ },
+ reactStrictMode: true,
+ transpilePackages: [
+ "@macrostrat/form-components",
+ "@macrostrat/data-components",
+ "@macrostrat/ui-components",
+ "@macrostrat/column-components",
+ ],
+ webpack: (config, options) => {
+ return {
+ ...config,
+
+ resolve: {
+ ...config.resolve,
+ alias: {
+ ...config.resolve.alias,
+ "~": path.resolve(__dirname, "src"),
+ "@macrostrat/form-components": packageSrc("form-components"),
+ "@macrostrat/data-components": packageSrc("data-components"),
+ "@macrostrat/ui-components": packageSrc("ui-components"),
+ "@macrostrat/column-components": packageSrc("column-components"),
+ },
+ },
+ };
+ },
+};
+
+module.exports = nextConfig;
diff --git a/packages/column-builder/package.json b/packages/column-builder/package.json
new file mode 100644
index 00000000..60a296bf
--- /dev/null
+++ b/packages/column-builder/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "@macrostrat-web/column-builder",
+ "scripts": {
+ "dev": "next dev -p 1234",
+ "build": "next build",
+ "start": "next start -p 1234",
+ "lint": "next lint"
+ },
+ "module": "src/index.ts",
+ "dependencies": {
+ "@blueprintjs/core": "^5.10.5",
+ "@blueprintjs/icons": "^5.10.0",
+ "@blueprintjs/popover2": "^1.2.1",
+ "@blueprintjs/select": "^5.2.1",
+ "@macrostrat-web/settings": "workspace:*",
+ "@macrostrat/column-components": "workspace:*",
+ "@macrostrat/data-components": "workspace:*",
+ "@macrostrat/form-components": "workspace:*",
+ "@macrostrat/hyper": "^2.0.1",
+ "@macrostrat/ui-components": "workspace:*",
+ "@mapbox/mapbox-gl-draw": "^1.3.0",
+ "@supabase/postgrest-js": "^0.36.0",
+ "@types/mapbox__mapbox-gl-draw": "^1.2.3",
+ "axios": "^0.27.2",
+ "cross-fetch": "^3.1.5",
+ "mapbox-gl": "^2.8.2",
+ "react": "^18",
+ "react-beautiful-dnd": "^13.1.0",
+ "react-color": "^2.19.3"
+ },
+ "devDependencies": {
+ "@types/node": "^17.0.10",
+ "@types/react": "^17",
+ "@types/react-beautiful-dnd": "^13.1.2",
+ "eslint": "^8.7.0",
+ "eslint-config-next": "^12.0.8",
+ "typescript": "^4.5.4"
+ }
+}
diff --git a/packages/column-builder/src/components/buttons/btns.module.scss b/packages/column-builder/src/components/buttons/btns.module.scss
new file mode 100644
index 00000000..998ed479
--- /dev/null
+++ b/packages/column-builder/src/components/buttons/btns.module.scss
@@ -0,0 +1,10 @@
+.flat-btn {
+ padding: 0 10px;
+ min-height: 0;
+}
+
+.position-increment-container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
diff --git a/packages/column-builder/src/components/buttons/index.ts b/packages/column-builder/src/components/buttons/index.ts
new file mode 100644
index 00000000..b42bfb34
--- /dev/null
+++ b/packages/column-builder/src/components/buttons/index.ts
@@ -0,0 +1,128 @@
+import { hyperStyled } from "@macrostrat/hyper";
+import { useModelEditor } from "@macrostrat/ui-components";
+import { Link } from "../routing/routing-helpers";
+import { Button, ButtonGroup } from "@blueprintjs/core";
+import styles from "./btns.module.scss";
+import { ReactChild } from "react";
+
+const h = hyperStyled(styles);
+
+function EditButton({
+ href,
+ small = false,
+}: {
+ href: string;
+ small?: boolean;
+}) {
+ return h(Link, { href }, [
+ h(Button, {
+ small,
+ minimal: true,
+ intent: "success",
+ icon: "edit",
+ onClick: (e) => {
+ e.stopPropagation();
+ },
+ }),
+ ]);
+}
+
+interface CreateButtonI {
+ text: string;
+ href: string;
+ minimal?: boolean;
+}
+
+function CreateButton(props: CreateButtonI) {
+ const { text, href, minimal = true } = props;
+ return h(Link, { href }, [
+ h(
+ Button,
+ {
+ minimal,
+ intent: "success",
+ },
+ [text]
+ ),
+ ]);
+}
+
+interface CancelButtonI {
+ href: string;
+}
+
+function CancelButton(props: CancelButtonI) {
+ const { href } = props;
+ return h(Link, { href }, [
+ h(
+ Button,
+ {
+ intent: "danger",
+ },
+ ["Cancel"]
+ ),
+ ]);
+}
+
+function SubmitButton(props: { disabled?: boolean }) {
+ const { hasChanges, actions } = useModelEditor();
+
+ return h(
+ Button,
+ {
+ disabled: props.disabled || !hasChanges(),
+ intent: "success",
+ onClick: () => actions.persistChanges(),
+ },
+ ["Submit"]
+ );
+}
+
+function AddButton(props: {
+ onClick: () => void;
+ minimal?: boolean;
+ children: ReactChild;
+}) {
+ const { onClick, minimal = true, children } = props;
+
+ return h(
+ Button,
+ { minimal: minimal, onClick, fill: true, intent: "success" },
+ ["+ ", children]
+ );
+}
+
+function PositionIncrementBtns(props: {
+ onClickUp: () => void;
+ onClickDown: () => void;
+ position_bottom: number;
+ isFirst?: boolean;
+ isLast?: boolean;
+}) {
+ return h("div.position-increment-container", [
+ props.position_bottom,
+ h(ButtonGroup, { vertical: true, minimal: true }, [
+ h(Button, {
+ icon: "chevron-up",
+ className: styles["flat-btn"],
+ disabled: props.isFirst,
+ onClick: props.onClickUp,
+ }),
+ h(Button, {
+ icon: "chevron-down",
+ className: styles["flat-btn"],
+ disabled: props.isLast,
+ onClick: props.onClickDown,
+ }),
+ ]),
+ ]);
+}
+
+export {
+ CreateButton,
+ EditButton,
+ SubmitButton,
+ CancelButton,
+ AddButton,
+ PositionIncrementBtns,
+};
diff --git a/packages/column-builder/src/components/column-group/column-group-editor.ts b/packages/column-builder/src/components/column-group/column-group-editor.ts
new file mode 100644
index 00000000..f618ea47
--- /dev/null
+++ b/packages/column-builder/src/components/column-group/column-group-editor.ts
@@ -0,0 +1,99 @@
+import { hyperStyled } from "@macrostrat/hyper";
+import { ColumnGroupI } from "../../types";
+import { FormGroup, InputGroup } from "@blueprintjs/core";
+import {
+ ModelEditor,
+ useModelEditor,
+ ModelEditButton,
+ //@ts-ignore
+} from "@macrostrat/ui-components";
+import styles from "../comp.module.sass";
+import { SubmitButton } from "..";
+
+const h = hyperStyled(styles);
+
+function ColumnGroupEdit() {
+ const {
+ model,
+ actions,
+ isEditing,
+ hasChanges,
+ }: {
+ model: ColumnGroupI;
+ actions: any;
+ isEditing: boolean;
+ hasChanges: () => boolean;
+ } = useModelEditor();
+
+ // two text editors, name and description
+ // could have a suggest for the timescale
+
+ const defaultColGroupShort =
+ model.col_group.length > 0 ? model.col_group : undefined;
+ const defaultColGroupLong =
+ model.col_group_long.length > 2 ? model.col_group_long : undefined;
+
+ const updateProject = (field: string, e: any) => {
+ actions.updateState({ model: { [field]: { $set: e } } });
+ };
+
+ return h("div", [
+ h(
+ FormGroup,
+ {
+ helperText: "Add a short column group name",
+ label: "Column Group Name (short)",
+ labelFor: "project-input",
+ labelInfo: "(required)",
+ },
+ [
+ h(InputGroup, {
+ style: { width: "200px" },
+ defaultValue: defaultColGroupShort,
+ onChange: (e) => updateProject("col_group", e.target.value),
+ }),
+ ]
+ ),
+ h(
+ FormGroup,
+ {
+ helperText: "Add a long column group name",
+ label: "Column Group Name (long)",
+ labelFor: "descrip-input",
+ labelInfo: "(recommended)",
+ },
+ [
+ h(InputGroup, {
+ style: { width: "300px" },
+ defaultValue: defaultColGroupLong,
+ onChange: (e) => updateProject("col_group_long", e.target.value),
+ }),
+ ]
+ ),
+ h(SubmitButton),
+ ]);
+}
+
+interface ColumnGroupEditorProps {
+ model: ColumnGroupI | {};
+ persistChanges: (
+ e: Partial,
+ c: Partial
+ ) => ColumnGroupI;
+}
+
+function ColumnGroupEditor(props: ColumnGroupEditorProps) {
+ return h(
+ ModelEditor,
+ {
+ model: props.model,
+ //@ts-ignore
+ persistChanges: props.persistChanges,
+ canEdit: true,
+ isEditing: true,
+ },
+ [h(ColumnGroupEdit)]
+ );
+}
+
+export { ColumnGroupEditor };
diff --git a/packages/column-builder/src/components/column/column-editor.ts b/packages/column-builder/src/components/column/column-editor.ts
new file mode 100644
index 00000000..5c16855f
--- /dev/null
+++ b/packages/column-builder/src/components/column/column-editor.ts
@@ -0,0 +1,193 @@
+import { hyperStyled } from "@macrostrat/hyper";
+import {
+ NumericInput,
+ InputGroup,
+ TextArea,
+ FormGroup,
+ Card,
+ Callout,
+} from "@blueprintjs/core";
+import styles from "../comp.module.sass";
+import { ColumnForm, ColumnGroupI } from "~/types";
+
+import { SubmitButton } from "..";
+import { LngLatMap } from "./map";
+import { Point } from "@macrostrat/form-components";
+import { ModelEditor, useModelEditor } from "@macrostrat/ui-components";
+import { ColumnRef } from "./column-ref";
+
+const h = hyperStyled(styles);
+
+export interface Model {
+ model: ColumnForm;
+ actions: any;
+ hasChanges: () => boolean;
+}
+
+interface ModelComponentBaseProps {
+ updateColumn: (field: string, e: any) => void;
+}
+function ColumnNotes(props: ModelComponentBaseProps) {
+ const { model, actions, hasChanges }: Model = useModelEditor();
+
+ return h("div", [
+ h("h4", { style: { marginBottom: 0 } }, ["Notes"]),
+ h(TextArea, {
+ style: { width: "400px", height: "150px" },
+ value: model.notes ?? "",
+ onChange: (e) => props.updateColumn("notes", e.target.value),
+ }),
+ ]);
+}
+
+function ColumnName(props: ModelComponentBaseProps) {
+ const { model, actions, hasChanges }: Model = useModelEditor();
+
+ return h("div", [
+ h(
+ FormGroup,
+ { label: h("h4", { style: { margin: 0 } }, ["Column Name"]) },
+ [
+ h(InputGroup, {
+ style: { width: "200px" },
+ defaultValue: model.col_name || undefined,
+ onChange: (e) => props.updateColumn("col_name", e.target.value),
+ }),
+ ]
+ ),
+ ]);
+}
+
+function ColumnNumber(props: ModelComponentBaseProps) {
+ const { model, actions, hasChanges }: Model = useModelEditor();
+ return h(
+ FormGroup,
+ { label: h("h4", { style: { margin: 0 } }, ["Column Number"]) },
+ [
+ h(NumericInput, {
+ style: { width: "200px" },
+ defaultValue: model.col || undefined,
+ onValueChange: (e: number) => props.updateColumn("col", e),
+ }),
+ ]
+ );
+}
+
+function ColumnRef_() {
+ const { model, actions, hasChanges }: Model = useModelEditor();
+
+ return h(
+ Callout,
+ {
+ style: {
+ width: "400px",
+ marginTop: "10px",
+ marginBottom: "10px",
+ },
+ title: "Reference",
+ },
+ [
+ h("div.ref", [model.refs[0]?.ref]),
+ h("div.ref-author", [
+ model.refs[0]?.author,
+ "(",
+ model.refs[0]?.pub_year,
+ ")",
+ ]),
+ h("div.doi", [
+ h("a", { href: model.refs[0]?.url, target: "_blank" }, [
+ model.refs[0]?.doi,
+ ]),
+ ]),
+ h(ColumnRef),
+ ]
+ );
+}
+
+function isDisabled(model: ColumnForm) {
+ if (typeof model.col_name == "undefined") return true;
+ if (typeof model.lat == "undefined" || typeof model.lng == "undefined")
+ return true;
+ if (typeof model.refs == "undefined") return true;
+ return false;
+}
+
+function ColumnEdit({ curColGroup }: { curColGroup: Partial }) {
+ const { model, actions, hasChanges }: Model = useModelEditor();
+
+ const updateColumn = (field: string, e: any) => {
+ actions.updateState({ model: { [field]: { $set: e } } });
+ };
+
+ const setCoords = (p: Point) => {
+ const [long, lat] = p.geometry.coordinates;
+ actions.updateState({
+ model: { lng: { $set: long }, lat: { $set: lat } },
+ });
+ };
+
+ return h(Card, [
+ h("div.col-editor-container", [
+ h("div.left", [
+ h("h4", ["Column Group: ", curColGroup.col_group]),
+ h(ColumnName, { updateColumn }),
+ h(ColumnNumber, { updateColumn }),
+ h("div", [h("td", [h(ColumnNotes, { updateColumn }), h(ColumnRef_)])]),
+ ]),
+ h("div.right", [
+ h(Card, { style: { minWidth: "600px" }, elevation: 1 }, [
+ h(LngLatMap, {
+ disabled: model.poly_geom != null,
+ longitude: model.lng ?? 0,
+ latitude: model.lat ?? 0,
+ onChange: (p: Point) => setCoords(p),
+ }),
+ h.if(model.poly_geom != null)(
+ Callout,
+ {
+ intent: "warning",
+ title: "No editing location",
+ style: { width: "600px" },
+ },
+ [
+ "This column has an associated footprint geometry.",
+ " All editing must take place in ",
+ h(
+ "a",
+ {
+ href: process.env.NEXT_PUBLIC_TOPOLOGY_URL,
+ target: "_blank",
+ },
+ ["Column-Topology-Editor."]
+ ),
+ ]
+ ),
+ ]),
+ ]),
+ ]),
+ h(SubmitButton, { disabled: isDisabled(model) }),
+ ]);
+}
+
+interface ColumnEditorProps {
+ model: ColumnForm | {};
+ curColGroup: Partial;
+ persistChanges: (e: ColumnForm, c: Partial) => ColumnForm;
+}
+
+export function ColumnEditor(props: ColumnEditorProps) {
+ return h(
+ ModelEditor,
+ {
+ model: props.model,
+ persistChanges: props.persistChanges,
+ isEditing: true,
+ canEdit: true,
+ },
+ [
+ h(ColumnEdit, {
+ curColGroup: props.curColGroup,
+ }),
+ ]
+ );
+}
diff --git a/packages/column-builder/src/components/column/column-ref.ts b/packages/column-builder/src/components/column/column-ref.ts
new file mode 100644
index 00000000..9f8eecde
--- /dev/null
+++ b/packages/column-builder/src/components/column/column-ref.ts
@@ -0,0 +1,171 @@
+import { Ref, useState } from "react";
+import { hyperStyled } from "@macrostrat/hyper";
+import {
+ Button,
+ NumericInput,
+ InputGroup,
+ TextArea,
+ Spinner,
+ FormGroup,
+ Card,
+ MenuItem,
+ Drawer,
+ Collapse,
+ Callout,
+} from "@blueprintjs/core";
+import styles from "../comp.module.sass";
+import { ColumnForm, ColumnGroupI } from "~/types";
+import { DataI, ItemSuggest } from "../suggest";
+import { RefI } from "~/types";
+import pg, { usePostgrest } from "../../db";
+import { RefEditor } from "../ref/ref-editor";
+import { SubmitButton } from "..";
+import { LngLatMap } from "./map";
+import { Point, Pub, PublicationFinder } from "@macrostrat/form-components";
+import { ModelEditor, useModelEditor } from "@macrostrat/ui-components";
+import { ItemRenderer } from "@blueprintjs/select";
+import { Model } from "./column-editor";
+
+const h = hyperStyled(styles);
+
+interface RefDataI {
+ value: string;
+ data: RefI;
+}
+
+function formPubSelectText(ref: RefI) {
+ const title = ref.ref?.length > 50 ? ref.ref.slice(0, 50) + "..." : ref.ref;
+
+ return `${ref?.author}(${ref?.pub_year})-${title}`;
+}
+
+const ColumnRefItemRenderer: ItemRenderer> = (
+ item: DataI,
+ { handleClick, modifiers, index }
+) => {
+ const { value, data } = item;
+ return h(MenuItem, {
+ key: index,
+ text: h(Callout, [
+ h("div", [data.ref]),
+ h("div.ref-author", [data.author, "(", data.pub_year, ")"]),
+ h("div.doi", [data.doi]),
+ ]),
+ onClick: handleClick,
+ active: modifiers.active,
+ });
+};
+
+function ColumnRef() {
+ const [open, setOpen] = useState(false);
+ const [newRefOpen, setNewRefOpen] = useState(false);
+
+ const { model, actions }: Model = useModelEditor();
+ const refs: RefI[] = usePostgrest(
+ pg.from("refs").select("id, pub_year, author, ref, doi, url")
+ );
+
+ if (!refs) return h(Spinner);
+
+ const onClick = () => {
+ setOpen(!open);
+ };
+
+ const onChange = (item: RefDataI) => {
+ actions.updateState({ model: { refs: { $set: [item.data] } } });
+ };
+
+ const onPubFinderClick = async (e: Pub) => {
+ const newRef: RefI = {
+ ref: e.title,
+ pub_year: e.year,
+ author: e.author,
+ doi: e.doi,
+ url: e.link,
+ };
+ const { data, error } = await pg.from("refs").insert([newRef]);
+ if (!error) {
+ actions.updateState({ model: { refs: { $set: [data[0]] } } });
+ }
+ setOpen(false);
+ setNewRefOpen(false);
+ };
+
+ // have the ref suggest as well as option to create new ref.
+ return h("div", [
+ h(ItemSuggest, {
+ items: refs.map((ref) => {
+ return { value: formPubSelectText(ref), data: ref };
+ }),
+ itemRenderer: ColumnRefItemRenderer,
+ initialSelected: {
+ value: model.refs[0] ? formPubSelectText(model.refs[0]) : "",
+ data: model.refs[0] || {},
+ },
+ onChange,
+ }),
+ h(Button, { onClick, icon: "plus" }),
+ h(
+ Drawer,
+ {
+ usePortal: true,
+ isOpen: open,
+ onClose: () => setOpen(false),
+ title: "Add a new reference",
+ },
+ [
+ h(
+ "div",
+ {
+ style: {
+ padding: "5px",
+ display: "flex",
+ flexDirection: "column",
+ },
+ },
+ [
+ h("div", [
+ h("h3", { style: { marginBottom: 0 } }, [
+ "Search for a Publication",
+ ]),
+ h(PublicationFinder, {
+ onClick: onPubFinderClick,
+ }),
+ ]),
+ h("div", [
+ h(
+ Button,
+ {
+ minimal: true,
+ fill: true,
+ onClick: () => setNewRefOpen(!newRefOpen),
+ },
+ ["+ Can't find the paper, add it's details +"]
+ ),
+ h(Collapse, { isOpen: newRefOpen }, [h(NewRef)]),
+ ]),
+ ]
+ ),
+ ]
+ ),
+ ]);
+}
+
+function NewRef() {
+ const { model, actions, hasChanges }: Model = useModelEditor();
+
+ const persistChanges = async (e: RefI, c: Partial) => {
+ console.log("persistChanges!!");
+ // would need to post ref to back as new ref first
+ const { data, error } = await pg.from("refs").insert([e]);
+ if (!error) {
+ actions.updateState({ model: { refs: { $set: [data[0]] } } });
+ }
+
+ return e;
+ };
+ //@ts-ignore
+ return h(RefEditor, { model: model.ref || {}, persistChanges });
+}
+
+export { ColumnRef };
diff --git a/packages/column-builder/src/components/column/index.ts b/packages/column-builder/src/components/column/index.ts
new file mode 100644
index 00000000..98032cbc
--- /dev/null
+++ b/packages/column-builder/src/components/column/index.ts
@@ -0,0 +1,2 @@
+export * from "../unit-section-table/reducer";
+export * from "./map";
diff --git a/packages/column-builder/src/components/column/map.ts b/packages/column-builder/src/components/column/map.ts
new file mode 100644
index 00000000..976f1df6
--- /dev/null
+++ b/packages/column-builder/src/components/column/map.ts
@@ -0,0 +1,61 @@
+import { hyperStyled } from "@macrostrat/hyper";
+import mapboxgl from "mapbox-gl";
+import "@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css";
+import { useEffect, useState } from "react";
+import "mapbox-gl/dist/mapbox-gl.css";
+import styles from "../comp.module.sass";
+import {
+ LngLatMap as LngLatMap_,
+ LngLatInputs,
+ Point,
+} from "@macrostrat/form-components";
+const h = hyperStyled(styles);
+
+mapboxgl.accessToken =
+ "pk.eyJ1IjoidGhlZmFsbGluZ2R1Y2siLCJhIjoiY2tsOHAzeDZ6MWtsaTJ2cXhpMDAxc3k5biJ9.FUMK57K0UP7PSrTUi3DiFQ";
+
+function roundCoordinates(p: Point) {
+ let [long, lat] = p.geometry.coordinates;
+ p.geometry.coordinates = [
+ parseFloat(long.toPrecision(7)),
+ parseFloat(lat.toPrecision(7)),
+ ];
+}
+
+/* break state out and share it */
+function LngLatMap(props: {
+ longitude: number;
+ latitude: number;
+ onChange: (p: Point) => void;
+ disabled: boolean;
+}) {
+ const [point, setPoint] = useState({
+ geometry: { coordinates: [props.longitude, props.latitude], type: "Point" },
+ id: "",
+ properties: {},
+ type: "Feature",
+ });
+
+ const setPoint_ = (p: Point) => {
+ roundCoordinates(p);
+ setPoint(p);
+ };
+
+ useEffect(() => {
+ props.onChange(point);
+ }, [point]);
+
+ return h("div", [
+ h("h4", { style: { marginTop: 0 } }, ["Set a location"]),
+ h(LngLatMap_, { point, setPoint: setPoint_, disabled: props.disabled }),
+ h("div.lng-lat-inputs", [
+ h(LngLatInputs, {
+ point,
+ setPoint: setPoint_,
+ disabled: props.disabled,
+ }),
+ ]),
+ ]);
+}
+
+export { LngLatMap };
diff --git a/packages/column-builder/src/components/comp.module.sass b/packages/column-builder/src/components/comp.module.sass
new file mode 100644
index 00000000..c8aaf326
--- /dev/null
+++ b/packages/column-builder/src/components/comp.module.sass
@@ -0,0 +1,183 @@
+.column-builder :global
+ a
+ color: inherit
+ text-decoration: none
+ *
+ box-sizing: border-box
+ .table-container
+ margin: 10px
+ height: 100%
+ padding: 0px
+ border-radius: 3px
+ .col-group-name
+ display: flex
+ justify-content: center
+ align-items: center
+ .bp5-menu
+ max-height: 400px
+ max-width: 400px
+ overflow: auto
+.mySuggest
+ overflow: scroll
+ max-height: 200px
+.itemSelectPopover
+ padding: 5px
+ background-color: var(--panel-background-color)
+ -ms-overflow-style: none
+ /* Internet Explorer 10+ */
+ scrollbar-width: none
+ /* Firefox */
+ ::-webkit-scrollbar
+ display: none
+ /* Safari and Chrome */
+.interval-row
+ display: flex
+ justify-content: space-between
+.row
+ display: flex
+ align-items: baseline
+.color-block
+ border-style: solid
+ //border-color: black
+ border-width: 0.5px
+ height: 30px
+ width: 30px
+.page
+ margin: 10px
+.bread-crumbs
+ display: flex
+.strat-name-con
+ display: flex
+ align-items: baseline
+.strat-name
+ margin: 0
+.tag-container,
+.tag-popover
+ flex-wrap: wrap
+ display: flex
+ align-items: baseline
+.tag-popover
+ padding: 10px
+ height: 300px
+ width: 900px
+ overflow-y: scroll
+.tag
+ margin: 1px
+.interval-cell-min-editor
+ display: flex
+ flex-direction: column
+ height: 8em
+ justify-content: space-between
+.nomargin
+ margin-bottom: 0px
+.margin-bottom-spacing
+ margin-bottom: 20px
+.map-container
+ height: 200px
+ width: 100%
+.header,
+.header-drag
+ min-height: 15px
+ padding: 5px
+ padding-left: 10px
+ text-transform: capitalize
+ font-size: 15px
+ //background: rgb(211, 216, 222)
+ font-weight: bold
+.header-drag
+ cursor: grab
+ &:active
+ cursor: grabbing
+.lng-lat-inputs
+ margin: 5px
+ display: flex
+ justify-content: space-around
+.col-editor-container
+ display: flex
+ justify-content: space-between
+.unit-section-tables
+ width: 75%
+.unit-section-container
+ display: flex
+ justify-content: center
+ margin-top: 10px
+.unit-moved
+ box-shadow: -6px 0px 0px 0px #10b146
+.btwn-row-btn
+ height: 10px
+ width: 100%
+ margin: -10px 0%
+ padding-top: 5px
+ &:hover
+ cursor: pointer
+.base-table
+ border: solid 1px
+ //border-color: #c5cbd3
+ margin: 10px
+ //background-color: white
+ border-radius: 5px
+.full-width
+ width: 100%
+ table-layout: fixed
+.ellipse
+ text-overflow: ellipsis
+ overflow: hidden
+ max-width: 80px
+ white-space: nowrap
+.strat-name-tooltip
+ h4
+ margin: 0
+ .underline
+ text-decoration: underline
+ i
+ color: rgb(166, 170, 174)
+ a
+ text-decoration: underline
+ color: rgb(108, 138, 175)
+
+.no-strat-meta
+ h4::before
+ color: rgb(243, 170, 33)
+ content: "Warning: "
+///////////////////////// strat modal ///////////////
+.concept-card
+ h4
+ margin: 0
+ font-size: 15px
+ .geologic-age
+ font-style: italic
+ //color: #7b7b7b
+ p
+ margin: 0
+ a
+ text-decoration: underline
+
+.strat-title
+ h3
+ margin: 0
+ display: flex
+ justify-content: space-between
+.related-strat-card
+ h3
+ margin: 0
+.strat-name-dialog-container
+ display: flex
+ padding: 10px
+ .left,
+ .right
+ margin: 5px
+.strat-dialog-bottom
+ margin: 10px
+/////////////// ref list item //////////////////
+.ref-author
+ font-style: italic
+ &::before
+ content: "-"
+.doi
+ &::before
+ content: "DOI: "
+ color: rgb(86, 109, 138)
+
+.table-header-row
+ background-color: var(--panel-secondary-background-color)
+ border-bottom: 1px solid var(--panel-rule-color)
diff --git a/packages/column-builder/src/components/draggable-overlay.ts b/packages/column-builder/src/components/draggable-overlay.ts
new file mode 100644
index 00000000..256a84b8
--- /dev/null
+++ b/packages/column-builder/src/components/draggable-overlay.ts
@@ -0,0 +1,92 @@
+import { hyperStyled } from "@macrostrat/hyper";
+import { useState, useEffect, ReactChild } from "react";
+import { Overlay, Card } from "@blueprintjs/core";
+import styles from "./comp.module.sass";
+
+const h = hyperStyled(styles);
+interface DraggableOverlayPropsI {
+ open: boolean;
+ children: ReactChild;
+ title?: string;
+ cardStyles?: object;
+ top?: number;
+ left?: number;
+}
+
+function DraggableOverlay(props: DraggableOverlayPropsI) {
+ const { open, children, cardStyles = {}, top = 0, left = 0 } = props;
+
+ const [state, setState] = useState({ top, left });
+ const [offset, setOffset] = useState({ rel_x: 0, rel_y: 0 });
+ const [dragging, setDragging] = useState(false);
+
+ useEffect(() => {
+ //setup event listeners
+ if (!dragging) return;
+ document.addEventListener("mousemove", onMouseMove, true);
+ document.addEventListener("mouseup", onMouseUp, true);
+ return () => {
+ document.removeEventListener("mouseup", onMouseUp, true);
+ document.removeEventListener("mousemove", onMouseMove, true);
+ };
+ }, [dragging]);
+
+ const onMouseDown = (e: any) => {
+ if (e.button !== 0) return;
+ setDragging(true);
+ setOffset(getOffest(e));
+ };
+
+ const onMouseUp = (e: any) => {
+ setDragging(false);
+ e.stopPropagation();
+ e.preventDefault();
+ };
+
+ const getOffest = (e: any) => {
+ const rel_x = e.pageX - state.left;
+ const rel_y = e.pageY - state.top;
+ return { rel_x, rel_y };
+ };
+
+ const onMouseMove = (e: any) => {
+ if (dragging) {
+ const { rel_x, rel_y } = offset;
+ const left_ = e.pageX - rel_x;
+ const top_ = e.pageY - rel_y;
+ setState({ top: top_, left: left_ });
+ const portals = Array.from(
+ document.getElementsByClassName(
+ "bp5-portal"
+ ) as HTMLCollectionOf
+ );
+ portals.map((portal) => {
+ portal.style.top = `${top_}px`;
+ portal.style.left = `${left_}px`;
+ });
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ };
+
+ const overlayProperties = {
+ autoFocus: true,
+ canEscapeKeyClose: true,
+ canOutsideClickClose: true,
+ enforceFocus: false,
+ hasBackdrop: false,
+ usePortal: true,
+ useTallContent: false,
+ };
+
+ return h(Overlay, { isOpen: open, ...overlayProperties }, [
+ h("div", {}, [
+ h(Card, { style: { padding: 0, paddingBottom: "5px" }, elevation: 4 }, [
+ h("div.header-drag", { onMouseDown: onMouseDown }, [props.title]),
+ children,
+ ]),
+ ]),
+ ]);
+}
+
+export { DraggableOverlay };
diff --git a/packages/column-builder/src/components/helpers.ts b/packages/column-builder/src/components/helpers.ts
new file mode 100644
index 00000000..45e21c04
--- /dev/null
+++ b/packages/column-builder/src/components/helpers.ts
@@ -0,0 +1,95 @@
+import { QueryI } from ".";
+import { EnvironUnit, LithUnit, StratNameI } from "..";
+
+/*
+returns a list of number ids for the envs or liths to be deleted or
+added from a unit.
+
+Otherwise it's impossible to detect if a user has removed envs or liths
+*/
+const detectDeletionsAndAdditions = (
+ og: EnvironUnit[] | LithUnit[] | StratNameI[],
+ changes: EnvironUnit[] | LithUnit[] | StratNameI[]
+) => {
+ let deletions = new Set();
+ let additions = new Set();
+
+ const present_og: any = {};
+
+ og.map((o) => {
+ Object.assign(present_og, { [o.id]: true });
+ });
+
+ changes.map((c) => {
+ let key = c.id;
+ if (present_og[key]) {
+ delete present_og[key];
+ } else {
+ additions.add(c.id);
+ }
+ });
+ Object.keys(present_og).map((i) => deletions.add(parseInt(i)));
+ return { deletions, additions };
+};
+
+/*
+Returns a string url for a next link that creates the query string from
+the passed 'query' object
+*/
+const createLink = (base: string, query: QueryI) => {
+ let queryString = "?";
+ Object.entries(query).map(([key, value], i) => {
+ if (queryString == "?") {
+ queryString = queryString + `${key}=${value}`;
+ } else {
+ queryString = queryString + `&${key}=${value}`;
+ }
+ });
+ return base + queryString;
+};
+
+const filterOrAddIds = (id: number, mergeIds: number[]): [] | number[] => {
+ if (mergeIds.length == 0) {
+ return [id];
+ } else if (mergeIds.includes(id)) {
+ return mergeIds.filter((i) => i != id);
+ }
+ return [id, ...mergeIds];
+};
+
+/* mapping color names from macrostrat to hex codes */
+const colorMap: { [name: string]: string } = {
+ blue: "#0000FF",
+ [`blue dark`]: "#00008B",
+ [`blue green`]: "#008B8B",
+ black: "#000000",
+ yellow: "#FFFF00",
+ orange: "#FFA500",
+ [`brown dark`]: "#A52A2A",
+ [`brown light`]: "#DEB887",
+ tan: "#D2B48C",
+ [`green dark`]: "#006400",
+ [`green light`]: "#90EE90",
+ [`gray dark`]: "#A9A9A9",
+ [`gray light`]: "#D3D3D3",
+ pink: "#FFC0CB",
+ purple: "#800080",
+ red: "#FF0000",
+ gray: "#808080",
+ green: "#008000",
+ brown: "#D2691E",
+ [`steel blue`]: "#B0C4DE",
+ white: "#FFFFFF",
+};
+
+const convertColorNameToHex = (name: string): string => {
+ if (name[0] === "#") return name;
+ return colorMap[name] ?? "#ffffff";
+};
+
+export {
+ detectDeletionsAndAdditions,
+ createLink,
+ filterOrAddIds,
+ convertColorNameToHex,
+};
diff --git a/packages/column-builder/src/components/index.ts b/packages/column-builder/src/components/index.ts
new file mode 100644
index 00000000..6b5e7103
--- /dev/null
+++ b/packages/column-builder/src/components/index.ts
@@ -0,0 +1,18 @@
+export * from "./table";
+export * from "./unit/interval-suggest";
+export * from "./routing/base-page";
+export * from "./routing/routing-helpers";
+export * from "./tag";
+export * from "./unit/color";
+export * from "./unit/unit-editor";
+export * from "./project/project-editor";
+export * from "./column-group/column-group-editor";
+export * from "./column/column-editor";
+export * from "./column";
+export * from "./strat-name";
+export * from "./buttons";
+export * from "./helpers";
+export * from "./unit";
+export * from "./section";
+export * from "./ssr-data-helpers";
+export * from "./unit-section-table";
diff --git a/packages/column-builder/src/components/lith/dialog.ts b/packages/column-builder/src/components/lith/dialog.ts
new file mode 100644
index 00000000..bee0397c
--- /dev/null
+++ b/packages/column-builder/src/components/lith/dialog.ts
@@ -0,0 +1,134 @@
+import { useState } from "react";
+import { hyperStyled } from "@macrostrat/hyper";
+import { Lith, LithUnit } from "~/types";
+import { LithSegment, LithSegmentContainer } from "./renderer";
+import { Dialog, Switch, Button, Intent, Divider } from "@blueprintjs/core";
+import styles from "./lith.module.scss";
+import { LithSelect } from "./query-list";
+
+const h = hyperStyled(styles);
+
+interface LithDialogProps {
+ liths?: LithUnit[];
+ onRemove?: (l: LithUnit) => void;
+ onClose: () => void;
+ onSwitchChange: (i: number) => void;
+ onAdd: (l: Lith) => void;
+ isOpen: boolean;
+}
+function LithDialog(props: LithDialogProps) {
+ const {
+ liths = [],
+ isOpen,
+ onRemove = (l) => console.log(l),
+ onClose,
+ onSwitchChange,
+ onAdd,
+ } = props;
+
+ const title = "Manage lithologies";
+
+ const onChange = (id: number) => {
+ onSwitchChange(id);
+ };
+
+ return h(
+ Dialog,
+ {
+ isOpen,
+ onClose,
+ title,
+ isCloseButtonShown: true,
+ },
+ [
+ h("div.lith-dialog", [
+ h(LithSegmentContainer, { liths, onClick: () => {}, large: false }),
+ h("div.lith-switches", [
+ liths.map((lith, i) => {
+ return h(LithSwitch, {
+ key: lith.id,
+ lith,
+ index: i,
+ onChange,
+ onRemove,
+ });
+ }),
+ ]),
+ h(Divider),
+ h("div.lith-select", [h(LithSelect, { onItemSelect: onAdd })]),
+ ]),
+ ]
+ );
+}
+
+interface LithSwitchProps {
+ lith: LithUnit;
+ onChange: (id: number) => void;
+ onRemove?: (l: LithUnit) => void;
+}
+function LithSwitch(props: LithSwitchProps) {
+ const { lith, onRemove } = props;
+ return h("div.row", [
+ h("div.lith-item", [
+ h(LithSegment, {
+ lith,
+ large: true,
+ onRemove,
+ widthInherit: false,
+ }),
+ ]),
+ // switch between dom and sub
+ h("div.switch", [
+ h(Switch, {
+ innerLabel: "Sub",
+ innerLabelChecked: "Dom",
+ checked: lith.dom == "dom",
+ onChange: () => props.onChange(lith.id),
+ }),
+ ]),
+ ]);
+}
+
+interface LithContainerProps {
+ liths: LithUnit[];
+ large: boolean;
+ onRemove?: (l: LithUnit) => void;
+ onAdd: (l: Lith) => void;
+ onSwitchProp: (id: number, prop: "dom" | "sub") => void;
+ isEditing: boolean;
+}
+function LithContainer(props: LithContainerProps) {
+ const [isOpen, setIsOpen] = useState(false);
+
+ const onClickOpen = () => {
+ if (!props.isEditing) return;
+ setIsOpen(true);
+ };
+
+ return h("div", [
+ h(LithDialog, {
+ isOpen,
+ onClose: () => setIsOpen(false),
+ onAdd: props.onAdd,
+ onSwitchChange: props.onSwitchProp,
+ liths: props.liths,
+ onRemove: props.onRemove,
+ }),
+ h("div.row", [
+ h(LithSegmentContainer, {
+ liths: props.liths,
+ onRemove: props.onRemove,
+ onClick: onClickOpen,
+ large: props.large,
+ }),
+ h.if(props.isEditing)(Button, {
+ intent: Intent.SUCCESS,
+ icon: "plus",
+ onClick: onClickOpen,
+ minimal: true,
+ }),
+ ]),
+ ]);
+}
+
+export { LithDialog, LithContainer };
diff --git a/packages/column-builder/src/components/lith/index.ts b/packages/column-builder/src/components/lith/index.ts
new file mode 100644
index 00000000..d5b729b3
--- /dev/null
+++ b/packages/column-builder/src/components/lith/index.ts
@@ -0,0 +1,2 @@
+export * from "./renderer";
+export * from "./dialog";
diff --git a/packages/column-builder/src/components/lith/lith.module.scss b/packages/column-builder/src/components/lith/lith.module.scss
new file mode 100644
index 00000000..8474192b
--- /dev/null
+++ b/packages/column-builder/src/components/lith/lith.module.scss
@@ -0,0 +1,65 @@
+.lith-segment-container {
+ display: flex;
+ width: 100%;
+ min-width: 100px;
+ max-width: 600px;
+ &:hover {
+ cursor: pointer;
+ }
+}
+
+.segment-tooltip {
+ display: flex;
+ flex-direction: column;
+ b {
+ text-transform: capitalize;
+ }
+ i {
+ color: #d3d8de;
+ }
+}
+
+.lith-segment {
+ margin-right: 1px;
+ text-transform: uppercase;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ p {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ margin-bottom: 0;
+ color: black;
+ font-size: 13px;
+ }
+
+ .small {
+ font-size: 11px !important;
+ }
+}
+
+.lith-dialog {
+ padding: 10px;
+ min-height: 400px;
+}
+.row {
+ display: flex;
+}
+.lith-switches {
+ list-style: none;
+ .row {
+ display: flex;
+ justify-content: space-around;
+ align-items: baseline;
+ margin: 10px;
+ .lith-item {
+ flex-grow: 1;
+ max-width: 100px;
+ }
+ .switch {
+ flex-grow: 0;
+ display: flex;
+ }
+ }
+}
diff --git a/packages/column-builder/src/components/lith/query-list.ts b/packages/column-builder/src/components/lith/query-list.ts
new file mode 100644
index 00000000..cb78469c
--- /dev/null
+++ b/packages/column-builder/src/components/lith/query-list.ts
@@ -0,0 +1,74 @@
+import { hyperStyled } from "@macrostrat/hyper";
+import { Lith } from "../../types";
+import { LithMenuItem } from "../tag";
+import styles from "./lith.module.scss";
+import {
+ QueryList,
+ ItemRenderer,
+ IQueryListRendererProps,
+ ItemPredicate,
+} from "@blueprintjs/select";
+import pg, { usePostgrest } from "../../db";
+import { InputGroup } from "@blueprintjs/core";
+
+const h = hyperStyled(styles);
+
+const LithQueryList = QueryList.ofType();
+
+const itemPredicate: ItemPredicate = (query, item, index) => {
+ const { lith } = item;
+
+ return lith?.toLowerCase().indexOf(query.toLowerCase()) >= 0;
+};
+
+const LithItemRenderer: ItemRenderer = (
+ item: Lith,
+ { handleClick, index, modifiers }
+) => {
+ return h(LithMenuItem, {
+ key: index,
+ data: { name: item.lith, color: item.lith_color },
+ modifiers,
+ handleClick,
+ });
+};
+
+const LithQueryListRenderer = (props: IQueryListRendererProps) => {
+ const { itemList, handleKeyDown, handleKeyUp, ...listProps } = props;
+
+ return h(
+ "div.lith-query-list-renderer",
+ { onKeyDown: handleKeyDown, onKeyUp: handleKeyUp },
+ [
+ h(InputGroup, {
+ ["aria-autocomplete"]: "list",
+ leftIcon: "search",
+ placeholder: "Add a lithology...",
+ onChange: listProps.handleQueryChange,
+ value: listProps.query,
+ }),
+ itemList,
+ ]
+ );
+};
+
+interface LithSelectProps {
+ onItemSelect: (l: Lith) => void;
+}
+
+function LithSelect(props: LithSelectProps) {
+ const liths: Lith[] = usePostgrest(pg.from("liths"));
+ if (!liths) return null;
+
+ return h(LithQueryList, {
+ itemRenderer: LithItemRenderer,
+ itemPredicate,
+ onItemSelect: props.onItemSelect,
+ items: liths,
+ renderer: LithQueryListRenderer,
+ resetOnSelect: true,
+ menuProps: { style: { maxWidth: "100%", margin: "0 10px" } },
+ });
+}
+
+export { LithSelect };
diff --git a/packages/column-builder/src/components/lith/renderer.ts b/packages/column-builder/src/components/lith/renderer.ts
new file mode 100644
index 00000000..44d67953
--- /dev/null
+++ b/packages/column-builder/src/components/lith/renderer.ts
@@ -0,0 +1,109 @@
+import { hyperStyled } from "@macrostrat/hyper";
+import { Lith, LithUnit } from "~/types";
+import { mergeRefs, Tag, Dialog } from "@blueprintjs/core";
+import { Tooltip2, Popover2 } from "@blueprintjs/popover2";
+import styles from "./lith.module.scss";
+
+const h = hyperStyled(styles);
+
+const getLithProportions = (liths: LithUnit[]) => {
+ if (liths.length == 0) return [1, 1];
+
+ let dom_count = 0;
+ let sub_count = 0;
+
+ liths.map((lith) => {
+ if (lith.dom == "dom") dom_count++;
+ else sub_count++;
+ });
+
+ const dom_prop = 5 / (sub_count + dom_count * 5);
+ const sub_prop = 1 / (sub_count + dom_count * 5);
+
+ return [dom_prop, sub_prop];
+};
+
+interface LithContainerProps {
+ liths?: LithUnit[];
+ onRemove?: (l: LithUnit) => void;
+ large: boolean;
+ onClick: () => void;
+}
+
+function LithSegmentContainer(props: LithContainerProps) {
+ const { liths = [] } = props;
+
+ const [dom_prop, sub_prop] = getLithProportions(liths);
+ return h("div.lith-segment-container", { onClick: props.onClick }, [
+ liths.map((lith, i) => {
+ return h(LithSegment, {
+ key: i,
+ lith,
+ onRemove: props.onRemove,
+ large: props.large,
+ width: lith.dom == "dom" ? dom_prop * 100 : sub_prop * 100,
+ });
+ }),
+ ]);
+}
+
+function LithSegmentToolTipContent(props: { lith: LithUnit | Lith }) {
+ return h("div.segment-tooltip", [
+ h("span", [
+ h("b", [props.lith.lith]),
+ " ",
+ h("i", ["(", props.lith.dom, ")"]),
+ ]),
+ h.if(
+ typeof props.lith.lith_group !== "undefined" &&
+ props.lith.lith_group != null
+ )("span", ["Group: ", h("i", [props.lith.lith_group])]),
+ h("span", [props.lith.lith_class, ", ", props.lith.lith_type]),
+ ]);
+}
+
+function LithSegment(props: {
+ lith: LithUnit | Lith;
+ onRemove?: (l: LithUnit) => void;
+ large: boolean;
+ width: number;
+}) {
+ const { width = 0 } = props;
+ const style = {
+ backgroundColor: props.lith.lith_color + "70",
+ width: width > 0 ? `${width}%` : "100%",
+ };
+
+ return h(Tooltip2, {
+ position: "top",
+ content: h(LithSegmentToolTipContent, { lith: props.lith }),
+ renderTarget: ({ isOpen, ref, ...tooltipProps }) =>
+ h(
+ Tag,
+ {
+ style: {
+ ...style,
+ padding: props.large ? "5px 7px" : "2px 6px",
+ display: "flex",
+ justifyContent: "space-around",
+ marginRight: "1px",
+ borderRadius: 0,
+ },
+ onRemove:
+ typeof props.onRemove !== "undefined"
+ ? //@ts-ignore
+ () => props.onRemove(props.lith)
+ : undefined,
+ elementRef: mergeRefs(ref),
+ ...tooltipProps,
+ },
+ [
+ h(`div.lith-segment ${!props.large ? ".small" : ""}`, [
+ h("p", [props.lith.lith]),
+ ]),
+ ]
+ ),
+ });
+}
+
+export { LithSegmentContainer, LithSegment };
diff --git a/packages/column-builder/src/components/project/project-editor.ts b/packages/column-builder/src/components/project/project-editor.ts
new file mode 100644
index 00000000..e4f38bf8
--- /dev/null
+++ b/packages/column-builder/src/components/project/project-editor.ts
@@ -0,0 +1,135 @@
+import { hyperStyled } from "@macrostrat/hyper";
+import { Project, TimeScale } from "../../types";
+import { FormGroup, InputGroup, Spinner, TextArea } from "@blueprintjs/core";
+import {
+ ModelEditor,
+ useModelEditor,
+ ModelEditButton,
+ ModelEditorContext,
+} from "@macrostrat/ui-components";
+import styles from "../comp.module.sass";
+import pg, { usePostgrest } from "../..";
+import { CancelButton, SubmitButton } from "..";
+import { ItemSuggest } from "../suggest";
+
+const h = hyperStyled(styles);
+
+interface TimeScaleSuggest {
+ value: string;
+ data: TimeScale;
+}
+
+interface TimeScaleSuggestProps {
+ onChange: (e: TimeScaleSuggest) => void;
+ initialSelected?: number;
+ onQueryChange?: (e: string) => void;
+ timescales: TimeScale[];
+}
+
+function TimeScaleSuggest(props: TimeScaleSuggestProps) {
+ const timescales_ = props.timescales.map((t) => {
+ return { value: t.timescale, data: t };
+ });
+
+ const init = timescales_.filter((t) => t.data.id == props.initialSelected)[0];
+
+ return h(ItemSuggest, {
+ items: timescales_,
+ initialSelected: init,
+ onChange: props.onChange,
+ onQueryChange: props.onQueryChange,
+ });
+}
+
+function ProjectEdit() {
+ const {
+ model,
+ actions,
+ }: {
+ model: Project;
+ actions: any;
+ } = useModelEditor();
+
+ const timescales: TimeScale[] = usePostgrest(pg.from("timescales"));
+
+ const defaultProjectName =
+ model.project.length > 2 ? model.project : undefined;
+ const defaultProjectDescrip =
+ model.descrip.length > 2 ? model.descrip : undefined;
+
+ const updateProject = (field: string, e: any) => {
+ actions.updateState({ model: { [field]: { $set: e } } });
+ };
+
+ return h("div", [
+ h(
+ FormGroup,
+ {
+ helperText: "Add a name to your project",
+ label: "Project Name",
+ labelInfo: "(required)",
+ },
+ [
+ h(InputGroup, {
+ style: { width: "200px" },
+ defaultValue: defaultProjectName,
+ onChange: (e) => updateProject("project", e.target.value),
+ }),
+ ]
+ ),
+ h(
+ FormGroup,
+ {
+ helperText: "Add a description to your project",
+ label: "Project Description",
+ labelInfo: "(recommended)",
+ },
+ [
+ h(TextArea, {
+ style: { minHeight: "170px", minWidth: "500px" },
+ defaultValue: defaultProjectDescrip,
+ onChange: (e) => updateProject("descrip", e.target.value),
+ }),
+ ]
+ ),
+ h(
+ FormGroup,
+ {
+ helperText: "Most projects use International Ages",
+ label: "Project Timescale",
+ labelInfo: "(required)",
+ },
+ [
+ h.if(timescales == undefined)(Spinner),
+ h.if(timescales != undefined)(TimeScaleSuggest, {
+ initialSelected: model.timescale_id,
+ timescales,
+ onChange: (e: TimeScaleSuggest) =>
+ updateProject("timescale_id", e.data.id),
+ }),
+ ]
+ ),
+ h(SubmitButton),
+ ]);
+}
+
+interface ProjectEditorProps {
+ project: Project | {};
+ persistChanges: (e: Partial, c: Partial) => Project;
+}
+
+function ProjectEditor(props: ProjectEditorProps) {
+ return h(
+ ModelEditor,
+ {
+ model: props.project,
+ //@ts-ignore
+ persistChanges: props.persistChanges,
+ canEdit: true,
+ isEditing: true,
+ },
+ [h(ProjectEdit)]
+ );
+}
+
+export { ProjectEditor };
diff --git a/packages/column-builder/src/components/ref/ref-editor.ts b/packages/column-builder/src/components/ref/ref-editor.ts
new file mode 100644
index 00000000..5b2af809
--- /dev/null
+++ b/packages/column-builder/src/components/ref/ref-editor.ts
@@ -0,0 +1,90 @@
+import { hyperStyled } from "@macrostrat/hyper";
+import { Table } from "../../index";
+import { NumericInput, TextArea, InputGroup } from "@blueprintjs/core";
+import {
+ ModelEditor,
+ useModelEditor,
+ ModelEditButton,
+} from "@macrostrat/ui-components";
+import styles from "../comp.module.sass";
+import { RefI } from "~/types";
+import { SubmitButton } from "..";
+import { FeatureCell } from "../table";
+
+const h = hyperStyled(styles);
+
+interface Model {
+ model: RefI;
+ actions: any;
+ hasChanges: () => boolean;
+}
+
+function RefEdit() {
+ const { model, actions, hasChanges }: Model = useModelEditor();
+ //author: text, year: numeric (validation), ref:textArea, doi:text, url:text
+
+ const updateRef = (field: string, e: any) => {
+ actions.updateState({ model: { [field]: { $set: e } } });
+ };
+
+ return h("div", [
+ h(Table, { interactive: false }, [
+ h("tr", [
+ h(FeatureCell, { text: "Author" }, [
+ h(InputGroup, {
+ style: { width: "200px" },
+ defaultValue: model.author || undefined,
+ onChange: (e) => updateRef("author", e.target.value),
+ }),
+ ]),
+ h(FeatureCell, { text: "Pub Year" }, [
+ h(NumericInput, {
+ style: { width: "200px" },
+ defaultValue: model.pub_year || undefined,
+ onValueChange: (e) => updateRef("pub_year", e),
+ }),
+ ]),
+ ]),
+ h("tr", [
+ h(FeatureCell, { text: "Ref", colSpan: 3 }, [
+ h(TextArea, { onChange: (e) => updateRef("ref", e.target.value) }),
+ ]),
+ ]),
+ h("tr", [
+ h(FeatureCell, { text: "DOI" }, [
+ h(InputGroup, {
+ style: { width: "200px" },
+ defaultValue: model.doi || undefined,
+ onChange: (e) => updateRef("doi", e.target.value),
+ }),
+ ]),
+ h(FeatureCell, { text: "URL" }, [
+ h(InputGroup, {
+ style: { width: "200px" },
+ defaultValue: model.url || undefined,
+ onChange: (e) => updateRef("url", e.target.value),
+ }),
+ ]),
+ ]),
+ ]),
+ h(SubmitButton),
+ ]);
+}
+
+interface RefEditorProps {
+ model: RefI | {};
+ persistChanges: (e: RefI, c: Partial) => RefI;
+}
+
+export function RefEditor(props: RefEditorProps) {
+ return h(
+ ModelEditor,
+ {
+ model: props.model,
+ persistChanges: props.persistChanges,
+ isEditing: true,
+ canEdit: true,
+ },
+ [h(RefEdit)]
+ );
+}
diff --git a/packages/column-builder/src/components/routing/base-page.ts b/packages/column-builder/src/components/routing/base-page.ts
new file mode 100644
index 00000000..2e83ad03
--- /dev/null
+++ b/packages/column-builder/src/components/routing/base-page.ts
@@ -0,0 +1,45 @@
+import React from "react";
+import { hyperStyled } from "@macrostrat/hyper";
+import styles from "../comp.module.sass";
+import { BreadcrumbProps } from "@blueprintjs/core";
+import { ReactChild } from "react";
+import { ErrorDialog } from "./error-boundary";
+import { PostgrestError } from "@supabase/postgrest-js";
+const h = hyperStyled(styles);
+
+export interface QueryI {
+ project_id?: number;
+ col_id?: number;
+ section_id?: number;
+ unit_id?: number;
+ col_group_id?: number;
+ strat_name_id?: number;
+ name?: string;
+}
+
+export interface BasePageProps {
+ query: QueryI;
+ errors: PostgrestError[];
+ children: ReactChild;
+}
+
+export interface CrumbsI extends BreadcrumbProps {
+ predicate: string;
+}
+
+/*
+Creates the breadcrumbs at the top of each page based on the router query
+*/
+export function BasePage(props: BasePageProps) {
+ //const router = useRouter();
+ const { query, errors = [] } = props;
+
+ // This should really be moved out to a hook.
+ //const breadCrumbs: CrumbsI[] = useBreadCrumbs({ router, query });
+
+ return h("div.page", [
+ //h("div.bread-crumbs", [h(Breadcrumbs, { items: breadCrumbs })]),
+ h.if(errors.length > 0)(ErrorDialog, { errors }),
+ h.if(errors.length == 0)(React.Fragment, [props.children]),
+ ]);
+}
diff --git a/packages/column-builder/src/components/routing/error-boundary.ts b/packages/column-builder/src/components/routing/error-boundary.ts
new file mode 100644
index 00000000..239138a2
--- /dev/null
+++ b/packages/column-builder/src/components/routing/error-boundary.ts
@@ -0,0 +1,30 @@
+import React from "react";
+import { hyperStyled } from "@macrostrat/hyper";
+import { Intent, Dialog, Callout, Divider } from "@blueprintjs/core";
+
+import styles from "../comp.module.sass";
+import { PostgrestError } from "@supabase/postgrest-js";
+const h = hyperStyled(styles);
+
+function ErrorDialog(props: { errors: PostgrestError[] }) {
+ return h(Dialog, { isOpen: true, style: { paddingBottom: "0" } }, [
+ h(
+ Callout,
+ { intent: Intent.DANGER, title: "Error has occured", icon: "error" },
+ [
+ props.errors.map((error, i) => {
+ return h(React.Fragment, [
+ h.if(error.message != null)("p", { key: i }, [
+ "Message: ",
+ error.message,
+ ]),
+ h.if(error.hint != null)("p", { key: i }, ["Hint: ", error.hint]),
+ h(Divider),
+ ]);
+ }),
+ ]
+ ),
+ ]);
+}
+
+export { ErrorDialog };
diff --git a/packages/column-builder/src/components/routing/routing-helpers.ts b/packages/column-builder/src/components/routing/routing-helpers.ts
new file mode 100644
index 00000000..8772f850
--- /dev/null
+++ b/packages/column-builder/src/components/routing/routing-helpers.ts
@@ -0,0 +1,200 @@
+import pg from "../../db";
+import { ReactChild, useCallback } from "react";
+import h from "@macrostrat/hyper";
+import { usePageContext } from "vike-react/usePageContext";
+import { navigate as vikeNavigate } from "vike/client/router";
+
+const routePrefix = "/dev/column-editor";
+
+export function Link(props: { href: string; children: ReactChild }) {
+ const ctx = usePageContext();
+ return h("a", { href: buildHref(props.href, ctx.urlPathname) }, [
+ props.children,
+ ]);
+}
+
+export function useNavigate() {
+ const ctx = usePageContext();
+ return useCallback(
+ (href: string, opts: any) => {
+ vikeNavigate(buildHref(href, ctx.urlPathname), opts);
+ },
+ [ctx.urlPathname]
+ );
+}
+
+function buildHref(href: string, currentRoute: string) {
+ console.log(currentRoute, href);
+ if (href.startsWith("/")) {
+ return joinPaths(routePrefix, href.slice(1));
+ } else {
+ // A relative path
+ return joinPaths(currentRoute, href);
+ }
+}
+
+function joinPaths(...paths: string[]) {
+ let parts: string[] = [];
+ for (const path of paths) {
+ // If we're not the first path but are an absolute path, throw an error
+ console.log(parts, path);
+ if (path.startsWith("/") && parts.length > 0) {
+ throw new Error("Cannot join an absolute path with a relative path");
+ }
+
+ const newParts = path.split("/");
+ for (const part of newParts) {
+ if (part == ".") continue;
+ if (part == "..") {
+ parts.pop();
+ }
+ parts.push(part);
+ }
+ }
+ return parts.join("/");
+}
+
+export interface IdsFromColGroup {
+ project_id?: number;
+}
+
+async function fetchIdsFromColGroup(
+ col_group_id: number
+): Promise {
+ const { data, error } = await pg
+ .from("col_groups")
+ .select("project_id")
+ .match({ id: col_group_id });
+ if (data) {
+ return data[0];
+ }
+ return {};
+}
+
+export interface IdsFromUnit {
+ unit_id?: number;
+ section_id?: number;
+ col_id?: number;
+ project_id?: number;
+}
+
+async function fetchIdsFromUnitId(unit_id: number): Promise {
+ const { data, error } = await pg
+ .from("units")
+ .select("section_id, cols!units_col_id_fkey(id, project_id)")
+ .match({ id: unit_id });
+
+ if (data) {
+ const { section_id, cols } = data[0];
+ const { id: col_id, project_id } = cols;
+ return { section_id, col_id, project_id, unit_id };
+ }
+ return {};
+}
+
+export interface IdsFromSection {
+ col_id?: number;
+ section_id?: number;
+ project_id?: number;
+}
+
+async function fetchIdsFromSectionId(
+ section_id: number
+): Promise {
+ const { data, error } = await pg
+ .from("sections")
+ .select("cols!sections_col_id_fkey(id, project_id)")
+ .match({ id: section_id });
+
+ if (data) {
+ const { id: col_id, project_id } = data[0]["cols"];
+ return { col_id, project_id, section_id };
+ }
+ return {};
+}
+
+export interface IdsFromCol {
+ col_id?: number;
+ project_id?: number;
+}
+
+async function fetchIdsFromColId(col_id: number): Promise {
+ const { data, error } = await pg
+ .from("cols")
+ .select("project_id")
+ .match({ id: col_id });
+
+ if (data) {
+ return { ...data[0], col_id };
+ }
+ return {};
+}
+
+/**
+ *
+ * Legacy NextJS implementation of breadcrumbs
+ interface BreadCrumbsHookI {
+ query: QueryI;
+ router: NextRouter;
+ }
+ function useBreadCrumbs(props: BreadCrumbsHookI) {
+ const { query, router } = props;
+
+ const filterCrumbs = (obj: CrumbsI): boolean => {
+ if (obj.text == "Projects") {
+ return true;
+ }
+
+ if (!(obj.predicate in query)) return false;
+ return true;
+ };
+
+ const breadCrumbs: CrumbsI[] = [
+ {
+ text: "Projects",
+ onClick: async () => {
+ router.push("/");
+ },
+ predicate: "",
+ },
+ {
+ text: "Column Groups",
+ onClick: async () => {
+ router.push(`/column-groups/${query.project_id}`);
+ },
+ predicate: "project_id",
+ },
+ {
+ text: "Column",
+ onClick: async () => {
+ router.push(`/column/${query.col_id}`);
+ },
+ predicate: "col_id",
+ },
+ {
+ text: "Section",
+ onClick: async () => {
+ router.push(`/section/${query.section_id}`);
+ },
+ predicate: "section_id",
+ },
+ {
+ text: "Unit",
+ onClick: async () => {
+ router.push(`/unit/${query.unit_id}/edit`);
+ },
+ predicate: "unit_id",
+ },
+ ].filter(filterCrumbs);
+
+ return breadCrumbs;
+ }
+ */
+
+export {
+ fetchIdsFromColId,
+ fetchIdsFromSectionId,
+ fetchIdsFromUnitId,
+ fetchIdsFromColGroup,
+ //useBreadCrumbs,
+};
diff --git a/packages/column-builder/src/components/section/index.ts b/packages/column-builder/src/components/section/index.ts
new file mode 100644
index 00000000..dbe2dc79
--- /dev/null
+++ b/packages/column-builder/src/components/section/index.ts
@@ -0,0 +1,2 @@
+export * from "./new-helpers";
+export * from "./table";
diff --git a/packages/column-builder/src/components/section/new-helpers.ts b/packages/column-builder/src/components/section/new-helpers.ts
new file mode 100644
index 00000000..e809e205
--- /dev/null
+++ b/packages/column-builder/src/components/section/new-helpers.ts
@@ -0,0 +1,86 @@
+import pg, { tableInsert, UnitsView } from "../..";
+
+const keys = [
+ "strat_name",
+ "color",
+ "outcrop",
+ "fo",
+ "lo",
+ "position_bottom",
+ "position_top",
+ "max_thick",
+ "min_thick",
+ "section_id",
+ "col_id",
+ "notes",
+];
+
+async function createNewSection(col_id: number) {
+ const { data, error } = await pg
+ .from("sections")
+ .insert([{ col_id: col_id }]);
+
+ const s_id = data ? data[0].id : null;
+ return s_id;
+}
+
+export const persistNewUnitAbove = async (
+ updatedModel: UnitsView,
+ changeSet: Partial,
+ section_id: number,
+ col_id: number
+) => {
+ /*
+ we need to get the smalled position_bottom in section, that will be the position_bottom for the new unit.
+ Every unit below that in the column needs to have the position_bottom incremented by 1.
+ 1. get smallest position bottom in section
+ 2. for all units where position_bottom >= this.position_bottom: position_bottom++
+
+ but maybe ask shanan
+ */
+};
+
+export const persistNewUnitChanges = async (
+ updatedModel: UnitsView,
+ changeSet: Partial,
+ section_id: any,
+ col_id: number
+) => {
+ let s_id = section_id;
+ if (s_id == null) {
+ // we're making a new section with this unit
+ s_id = await createNewSection(col_id);
+ }
+ console.log(updatedModel, changeSet);
+ let unit_id: number;
+
+ const unit: Partial = {};
+ keys.map((k) => {
+ if (k == "strat_name") {
+ unit.strat_name_id = changeSet.strat_names.id;
+ } else {
+ //@ts-ignore
+ unit[k] = changeSet.unit[k];
+ }
+ });
+ unit.section_id = s_id;
+ const { data, error } = await tableInsert("units", {
+ col_id: col_id,
+ ...unit,
+ });
+
+ unit_id = data ? data[0].id : null;
+
+ if (changeSet.envs) {
+ const inserts = changeSet.envs.map((e) => {
+ return { unit_id: unit_id, environ_id: e.id };
+ });
+ const { data, error } = await pg.from("unit_environs").insert(inserts);
+ }
+ if (changeSet.liths) {
+ const inserts = changeSet.liths.map((e) => {
+ return { unit_id: unit_id, lith_id: e.id };
+ });
+ const { data, error } = await pg.from("unit_liths").insert(inserts);
+ }
+};
diff --git a/packages/column-builder/src/components/section/table.ts b/packages/column-builder/src/components/section/table.ts
new file mode 100644
index 00000000..04878402
--- /dev/null
+++ b/packages/column-builder/src/components/section/table.ts
@@ -0,0 +1,59 @@
+import { hyperStyled } from "@macrostrat/hyper";
+import styles from "../comp.module.sass";
+import { ColSectionI } from "~/types";
+import { Table, Row } from "../table";
+import { SectionUnitCheckBox } from "../unit-section-table/helpers";
+
+const h = hyperStyled(styles);
+
+function ColSectionsTable(props: {
+ colSections: ColSectionI[];
+ onChange: (id: number) => void;
+}) {
+ const { colSections, onChange } = props;
+ const headers = [
+ "",
+ "Section number",
+ "Top interval",
+ "Bottom interval",
+ "# of units",
+ ];
+ return h(Table, { interactive: true, headers }, [
+ colSections.map((section, i) => {
+ return h(
+ Row,
+ {
+ href: `/section/${section.id}`,
+ key: i,
+ },
+ [
+ h(
+ "td",
+ {
+ onClick: (e: React.MouseEvent) =>
+ e.stopPropagation(),
+ },
+ [
+ h(SectionUnitCheckBox, {
+ data: section.id,
+ onChange: onChange,
+ }),
+ ]
+ ),
+ h("td", [section.id]),
+ h("td", [section.top]),
+ h("td", [section.bottom]),
+ h("td", [
+ h(
+ "a",
+ { href: `/section/${section.id}` },
+ `view ${section.unit_count} units`
+ ),
+ ]),
+ ]
+ );
+ }),
+ ]);
+}
+
+export { ColSectionsTable };
diff --git a/packages/column-builder/src/components/ssr-data-helpers.ts b/packages/column-builder/src/components/ssr-data-helpers.ts
new file mode 100644
index 00000000..402c79c6
--- /dev/null
+++ b/packages/column-builder/src/components/ssr-data-helpers.ts
@@ -0,0 +1,34 @@
+import { UnitsView } from "@macrostrat-web/column-builder/src";
+
+/* A collection of data processing functions to run server side before page is rendered */
+
+/**
+ * Creates a list of objects where the key is a section_id and the values are the
+ * corresponding units belonging to that section
+ * @param units UnitsView[]
+ * @returns unitsBySection - {[section_id: number]: UnitsView[]}[]
+ */
+function createUnitBySections(
+ units: UnitsView[] | null
+): { [section_id: string | number]: UnitsView[] }[] {
+ if (!units) return [];
+ const seen: { [section_id: number | string]: number } = {}; // store section_ids and their index in array
+ const unitsBySections: { [section_id: string | number]: UnitsView[] }[] = [];
+
+ units.map((unit, i) => {
+ if (unit.section_id in seen) {
+ const index = seen[unit.section_id];
+ unitsBySections[index][unit.section_id].push(unit);
+ } else {
+ let index = 0;
+ if (unitsBySections.length > 0) {
+ index = unitsBySections.length;
+ }
+ seen[unit.section_id] = index;
+ unitsBySections.push({ [unit.section_id]: [unit] });
+ }
+ });
+ return unitsBySections;
+}
+
+export { createUnitBySections };
diff --git a/packages/column-builder/src/components/strat-name/hierarchy/fetch.ts b/packages/column-builder/src/components/strat-name/hierarchy/fetch.ts
new file mode 100644
index 00000000..23b74d17
--- /dev/null
+++ b/packages/column-builder/src/components/strat-name/hierarchy/fetch.ts
@@ -0,0 +1,95 @@
+import axios from "axios";
+import { IHierarchy } from "@macrostrat/ui-components/lib/types";
+
+const url = "https://macrostrat.org/api/v2/defs/strat_names";
+
+// most of this is copied from the sift codebase
+var rankMap = {
+ SGp: null,
+ Gp: "sgp",
+ SubGp: "gp",
+ Fm: "subgp",
+ Mbr: "fm",
+ Bed: "mbr",
+ 1: null,
+ 2: "sgp",
+ 3: "gp",
+ 4: "subgp",
+ 5: "fm",
+ 6: "mbr",
+};
+var rankMapOrder = { SGp: 1, Gp: 2, SubGp: 3, Fm: 4, Mbr: 5, Bed: 6 };
+
+const fetchStratNames = async (id: number | undefined) => {
+ // function to fetch stratnames and orgnize hierarchy
+ if (id === undefined) {
+ return null;
+ }
+ const res = await axios.get(url, {
+ params: { rule: "all", strat_name_id: id },
+ });
+
+ if (res.status != 200) {
+ return res.data;
+ }
+
+ const data = res.data.success.data;
+
+ data.forEach((d) => {
+ // Figure out if this is the target name or not
+ d.active = false;
+ if (d.strat_name_id == id) {
+ d.active = true;
+ }
+
+ d.children = [];
+ d.totalChildren =
+ data.filter((j) => {
+ if (j[d.rank.toLowerCase() + "_id"] == d.strat_name_id) {
+ return j;
+ }
+ }).length - 1;
+ d.total = d.totalChildren;
+ });
+
+ data.forEach((d) => {
+ var belongsTo = d[rankMap[d.rank] + "_id"];
+
+ // Need to make sure belongsTo doesn't = 0 when it shouldn't (ex: strat_name_id=9574)
+ var previousRank = 1;
+ while (belongsTo === 0) {
+ belongsTo = d[rankMap[rankMapOrder[d.rank] - previousRank] + "_id"];
+ previousRank--;
+ }
+
+ // Find the one it belongs to and add it
+ data.forEach((j) => {
+ if (j.strat_name_id == belongsTo && j.strat_name_id != d.strat_name_id) {
+ j.children.push(d);
+ }
+ });
+ });
+
+ const hierarchy = data.sort((a, b) => {
+ return b.totalChildren - a.totalChildren;
+ })[0];
+ const mappedData = mapToHier(hierarchy);
+ // Find the top of the hierarchy and return it
+ return mappedData;
+};
+
+const mapToHier = (data) => {
+ const Hier: Partial = {};
+ Hier.name = data.strat_name_long;
+ Hier.units = data.t_units;
+ Hier.active = data.active;
+ Hier.onClick = (e) => {
+ e.preventDefault();
+ const url = `https://macrostrat.org/sift/#/strat_name/${data.strat_name_id}`;
+ window.open(url, "_blank");
+ };
+ Hier.subhierarchy = data.children.map((c) => mapToHier(c));
+ return Hier;
+};
+
+export { fetchStratNames };
diff --git a/packages/column-builder/src/components/strat-name/hierarchy/hierarchy.module.scss b/packages/column-builder/src/components/strat-name/hierarchy/hierarchy.module.scss
new file mode 100644
index 00000000..3830b958
--- /dev/null
+++ b/packages/column-builder/src/components/strat-name/hierarchy/hierarchy.module.scss
@@ -0,0 +1,3 @@
+.strat-name-hierarchy {
+ margin-bottom: 20px;
+}
diff --git a/packages/column-builder/src/components/strat-name/hierarchy/index.ts b/packages/column-builder/src/components/strat-name/hierarchy/index.ts
new file mode 100644
index 00000000..491e0738
--- /dev/null
+++ b/packages/column-builder/src/components/strat-name/hierarchy/index.ts
@@ -0,0 +1,39 @@
+import { useState, useEffect } from "react";
+import { fetchStratNames } from "./fetch";
+import { Spinner } from "@blueprintjs/core";
+import { Hierarchy, IHierarchy } from "@macrostrat/data-components";
+import { hyperStyled } from "@macrostrat/hyper";
+import styles from "./hierarchy.module.scss";
+
+const h = hyperStyled(styles);
+
+export { Hierarchy };
+
+export function StratNameHierarchy({
+ strat_name_id,
+}: {
+ strat_name_id?: number;
+}) {
+ const [state, setState] = useState>({});
+
+ useEffect(() => {
+ async function fetch() {
+ const res = await fetchStratNames(strat_name_id);
+ setState(res);
+ }
+ if (typeof strat_name_id !== "undefined") {
+ fetch();
+ }
+ }, [strat_name_id]);
+
+ if (typeof strat_name_id === "undefined") return null;
+
+ if (!state) {
+ return h("h3", "No results");
+ }
+
+ return h("div.strat-name-hierarchy", [
+ h.if(state.name)(Hierarchy, { ...state }),
+ h.if(!state.name)(Spinner),
+ ]);
+}
diff --git a/packages/column-builder/src/components/strat-name/index.ts b/packages/column-builder/src/components/strat-name/index.ts
new file mode 100644
index 00000000..1c6447cd
--- /dev/null
+++ b/packages/column-builder/src/components/strat-name/index.ts
@@ -0,0 +1,3 @@
+export * from "./strat-name-editor";
+export * from "./strat-name";
+export * from "./modal-editor";
diff --git a/packages/column-builder/src/components/strat-name/modal-editor.ts b/packages/column-builder/src/components/strat-name/modal-editor.ts
new file mode 100644
index 00000000..90a299c2
--- /dev/null
+++ b/packages/column-builder/src/components/strat-name/modal-editor.ts
@@ -0,0 +1,131 @@
+import React, { useState } from "react";
+import { hyperStyled } from "@macrostrat/hyper";
+import { useModelEditor } from "@macrostrat/ui-components";
+import { Button, Callout, Dialog, Tag } from "@blueprintjs/core";
+import styles from "../comp.module.sass";
+import pg, { usePostgrest } from "../../db";
+import { RANK, StratNameConceptLongI, StratNameI } from "~/types";
+import { StratNameStack } from "./panel-stack";
+import { AuthorTag } from "./query-list";
+
+const h = hyperStyled(styles);
+
+const rankLong = {
+ Fm: "Formation",
+ Gp: "Group",
+ Mbr: "Member",
+ SGp: "SuperGroup",
+ Bed: "Bed",
+};
+
+export function StratNameConceptCard(props: {
+ concept_id?: number;
+ strat_name: StratNameI;
+}) {
+ const data: StratNameConceptLongI[] = usePostgrest(
+ pg
+ .from("strat_names_meta")
+ .select("*,intervals(*),refs(*)")
+ .match({ concept_id: props.concept_id })
+ );
+
+ if (!data || typeof data == "undefined") return null;
+
+ const concept: StratNameConceptLongI = data[0];
+
+ return h(
+ Callout,
+ {
+ className: "concept-card",
+ },
+ [
+ h("div.strat-title", [
+ h("h3", [
+ `${props.strat_name.strat_name} ${rankLong[props.strat_name.rank]}`,
+ ]),
+ h(Tag, { intent: "success", minimal: true, icon: "tick" }, [
+ concept.refs.author,
+ ]),
+ ]),
+ h("p.geologic-age", [concept.province]),
+ h("div", { style: { display: "flex", alignItems: "center" } }, [
+ h("p.geologic-age", [
+ concept.geologic_age,
+ " (",
+ concept.intervals.age_bottom,
+ "ma",
+ " - ",
+ concept.intervals.age_top,
+ "ma)",
+ ]),
+ h("div.color-block", {
+ style: {
+ background: concept.intervals.interval_color,
+ width: "15px",
+ height: "15px",
+ marginLeft: "3px",
+ },
+ }),
+ ]),
+ h("p.source", [
+ "reference: ",
+ h("a", { href: concept.url, target: "_blank" }, [concept.refs.author]),
+ ]),
+ ]
+ );
+}
+
+function UnitStratNameModalEditor() {
+ const [open, setOpen] = useState(false);
+ const { model: unit, actions } = useModelEditor();
+
+ const onSubmitStratName = (e: StratNameI | null) => {
+ if (!e) return;
+ actions.updateState({
+ model: {
+ strat_names: { $push: [e] },
+ },
+ });
+ };
+
+ const onDelete = (id: number) => {
+ const newNames = [...unit.strat_names].filter((sn) => sn.id != id);
+ actions.updateState({
+ model: {
+ strat_names: { $set: newNames },
+ },
+ });
+ };
+
+ const onStratNameSelect = (e: StratNameI | null) => {
+ onSubmitStratName(e);
+ };
+
+ return h(React.Fragment, [
+ h(Button, {
+ minimal: true,
+ onClick: () => setOpen(true),
+ icon: "edit",
+ style: { padding: 0 },
+ }),
+ h(
+ Dialog,
+ {
+ style: { width: "600px" },
+ isOpen: open,
+ title: `Modify Unit #${unit.id} strat_name`,
+ onClose: () => setOpen(false),
+ },
+ [
+ h(StratNameStack, {
+ col_id: unit.col_id,
+ stratNames: unit.strat_names,
+ onStratNameSelect,
+ onDelete,
+ }),
+ ]
+ ),
+ ]);
+}
+
+export { UnitStratNameModalEditor };
diff --git a/packages/column-builder/src/components/strat-name/panel-stack/index.ts b/packages/column-builder/src/components/strat-name/panel-stack/index.ts
new file mode 100644
index 00000000..2175d7a7
--- /dev/null
+++ b/packages/column-builder/src/components/strat-name/panel-stack/index.ts
@@ -0,0 +1 @@
+export * from "./panel-stack";
diff --git a/packages/column-builder/src/components/strat-name/panel-stack/panel-stack.ts b/packages/column-builder/src/components/strat-name/panel-stack/panel-stack.ts
new file mode 100644
index 00000000..9a14e29b
--- /dev/null
+++ b/packages/column-builder/src/components/strat-name/panel-stack/panel-stack.ts
@@ -0,0 +1,307 @@
+import React, { useContext, useState } from "react";
+import { hyperStyled } from "@macrostrat/hyper";
+import {
+ PanelProps,
+ PanelStack2,
+ Panel,
+ Button,
+ Intent,
+ Callout,
+ Menu,
+ MenuItem,
+ FormGroup,
+ InputGroup,
+ ControlGroup,
+} from "@blueprintjs/core";
+import styles from "./strat-name-panel.module.scss";
+import { StratNameI } from "~/types";
+import { StratNameListItem, StratNameSelect } from "../query-list";
+import { StratNameHierarchy } from "../hierarchy";
+import { StratNameConceptCard } from "../modal-editor";
+import { RankSelect } from "../strat-name-editor";
+import pg, { usePostgrest } from "@macrostrat-web/column-builder/src/db";
+
+const h = hyperStyled(styles);
+
+interface SearchPanelProps {
+ col_id: number;
+ onSubmitStratName: (l: StratNameI) => void;
+ onDelete: (id: number) => void;
+ stratNames: StratNameI[];
+}
+
+interface CurrentStratNamesProps {
+ stratName: StratNameI;
+ onDelete: (id: number) => void;
+ onClick: (stratName: StratNameI, canAdd: boolean) => void;
+}
+
+function CurrentStratName(props: CurrentStratNamesProps) {
+ const { stratName } = props;
+
+ const data: StratNameI[] = usePostgrest(
+ pg.rpc("get_strat_name_info", { strat_name_id: stratName.id })
+ );
+
+ if (!data) return null;
+ return h(MenuItem, {
+ text: h(StratNameListItem, { ...data[0] }),
+ onClick: () => props.onClick(stratName, false),
+ style: { marginBottom: "3px", background: "#EDEFF2" },
+ labelElement: h(Button, {
+ intent: "danger",
+ minimal: true,
+ icon: "trash",
+ onClick: (e: any) => {
+ e.stopPropagation();
+ props.onDelete(stratName.id);
+ },
+ }),
+ });
+}
+
+const SearchPanel: React.FC> = (props) => {
+ const { col_id, onDelete, onStratNameSelect, stratNames } =
+ useContext(StratStackContext);
+
+ const onItemSelect = (stratName: StratNameI, canAdd?: boolean) => {
+ props.openPanel({
+ props: { stratName, onStratNameSelect, col_id, canAdd },
+ renderPanel: MetaDataPanel,
+ });
+ };
+
+ const onClickCreateNew = () => {
+ props.openPanel({
+ props: { onStratNameSelect },
+ renderPanel: NewStratNamePanel,
+ });
+ };
+
+ return h("div.strat-name-select", [
+ h.if(stratNames.length > 0)("h3", ["Current stratigraphic names"]),
+ h.if(stratNames.length > 0)(Menu, { style: { maxWidth: "100%" } }, [
+ stratNames.map((stratName) => {
+ return h(CurrentStratName, {
+ key: stratName.id,
+ stratName,
+ onClick: onItemSelect,
+ onDelete,
+ });
+ }),
+ ]),
+ h("h3", ["Choose a stratigraphic name"]),
+ h(StratNameSelect, { col_id, onItemSelect, onClickCreateNew }),
+ ]);
+};
+
+interface NewStratNamePanelProps {
+ onStratNameSelect: (l: StratNameI) => void;
+}
+
+const NewStratNamePanel: React.FC> = (
+ props
+) => {
+ const [state, setState] = useState({ strat_name: "", rank: "Fm" });
+
+ const updateStratName = (field: string, value: string) => {
+ setState((prevState) => {
+ return { ...prevState, [field]: value };
+ });
+ };
+
+ const onBackClick = () => {
+ props.closePanel();
+ };
+
+ return h("div", [
+ h("div.action-btns", [
+ h(
+ Button,
+ {
+ intent: Intent.WARNING,
+ onClick: onBackClick,
+ minimal: true,
+ icon: "arrow-left",
+ },
+ ["Return to search"]
+ ),
+ ]),
+ h("div.bottom", [
+ h(
+ FormGroup,
+ {
+ helperText: "Create a stratigraphic name",
+ label: "Stratigraphic Name",
+ },
+ [
+ h(ControlGroup, { fill: true }, [
+ h(InputGroup, {
+ fill: true,
+ defaultValue: state.strat_name,
+ onChange: (e) => updateStratName("strat_name", e.target.value),
+ }),
+ h(RankSelect, { updateStratName, rank: state.rank }),
+ h(
+ Button,
+ { intent: "warning", disabled: state.strat_name.length < 1 },
+ ["Submit"]
+ ),
+ ]),
+ ]
+ ),
+ h(
+ Callout,
+ {
+ title: "Unlinked",
+ style: { borderRadius: "5px" },
+ },
+ [
+ h("div", [
+ "This name will be unlinked to external resources. ",
+ "The most valuable stratigraphic name is one linked to an official lexicon or reference.",
+ ]),
+ h(
+ Button,
+ {
+ intent: "success",
+ rightIcon: "arrow-right",
+ style: { marginTop: "3px" },
+ },
+ ["Link stratigraphic name"]
+ ),
+ ]
+ ),
+ ]),
+ ]);
+};
+
+interface MetaDataPanelProps {
+ stratName: StratNameI | null;
+ onStratNameSelect: (l: StratNameI) => void;
+ col_id: number;
+ canAdd?: boolean;
+}
+
+const MetaDataPanel: React.FC> = (props) => {
+ const { canAdd = true, stratName, onStratNameSelect, col_id } = props;
+
+ const onBackClick = () => {
+ props.closePanel();
+ };
+
+ const onSaveClick = (stratName: StratNameI | null) => {
+ if (stratName == null) {
+ return;
+ }
+ onStratNameSelect(stratName);
+ props.closePanel();
+ };
+
+ if (!props.stratName) return h("div");
+ const concept_id = props.stratName.concept_id;
+
+ return h("div", [
+ h("div.action-btns", [
+ h(
+ Button,
+ {
+ intent: Intent.WARNING,
+ onClick: onBackClick,
+ minimal: true,
+ icon: "arrow-left",
+ },
+ ["Search for another"]
+ ),
+ h.if(canAdd)(
+ Button,
+ {
+ minimal: true,
+ intent: Intent.SUCCESS,
+ onClick: () => onSaveClick(stratName),
+ icon: "plus",
+ },
+ ["add name"]
+ ),
+ ]),
+ h("div.strat-name-select", [
+ h.if(concept_id != null)(StratNameConceptCard, {
+ strat_name: props.stratName,
+ concept_id,
+ }),
+ h.if(concept_id == null)(
+ Callout,
+ { intent: "warning", title: "No official lexicon" },
+ [
+ "This stratigraphic name is not linked to an official lexicon reference. You can use this but it may be better to find a strat_name that is linked.",
+ ]
+ ),
+ h("h3", ["Stratigraphic name hierarchy"]),
+ h("div.strat-hierarchy-constainer", [
+ h(StratNameHierarchy, {
+ strat_name_id: props.stratName?.id,
+ }),
+ ]),
+ ]),
+ ]);
+};
+
+interface StratNameStackProps {
+ onStratNameSelect: (i: StratNameI | null) => void;
+ col_id: number;
+ stratNames: StratNameI[];
+ onDelete: (id: number) => void;
+}
+
+type StratPanelTypes = SearchPanelProps | MetaDataPanelProps;
+type StratPanels = Panel;
+
+/* PanelStack has the limitation of NOT re-rendering on props change.
+https://github.com/palantir/blueprint/issues/3173
+So I use a react context to get around the issue.
+Not perfect but better than nothing.
+*/
+
+const StratStackContext = React.createContext({});
+
+function StratNameStack(props: StratNameStackProps) {
+ const { col_id, onStratNameSelect, stratNames } = props;
+
+ const initialPanel: Panel = {
+ renderPanel: SearchPanel,
+ title: "Search for a strat name",
+ };
+
+ const [currentPanelStack, setCurrentPanelStack] = useState<
+ Array
+ >([initialPanel]);
+
+ const addToPanelStack = React.useCallback(
+ (newPanel: StratPanels) =>
+ setCurrentPanelStack((stack) => [...stack, newPanel]),
+ [stratNames]
+ );
+ const removeFromPanelStack = React.useCallback(
+ () =>
+ setCurrentPanelStack([
+ {
+ renderPanel: SearchPanel,
+ title: "Search for a strat name",
+ },
+ ]),
+ [stratNames]
+ );
+
+ return h(StratStackContext.Provider, { value: props }, [
+ h(PanelStack2, {
+ className: "strat-name-stack",
+ stack: currentPanelStack,
+ onOpen: addToPanelStack,
+ onClose: removeFromPanelStack,
+ renderActivePanelOnly: false,
+ showPanelHeader: false,
+ }),
+ ]);
+}
+
+export { StratNameStack };
diff --git a/packages/column-builder/src/components/strat-name/panel-stack/strat-name-panel.module.scss b/packages/column-builder/src/components/strat-name/panel-stack/strat-name-panel.module.scss
new file mode 100644
index 00000000..0fdd1357
--- /dev/null
+++ b/packages/column-builder/src/components/strat-name/panel-stack/strat-name-panel.module.scss
@@ -0,0 +1,26 @@
+.strat-name-stack {
+ height: 500px;
+}
+.action-btns {
+ display: flex;
+ justify-content: space-between;
+ position: sticky;
+ padding: 3px 0;
+ top: 0;
+ background: white;
+ margin-bottom: 5px;
+}
+.strat-name-select {
+ padding: 1px 10px 0 10px;
+}
+.bottom {
+ .row {
+ display: flex;
+ }
+ .new-strat-name {
+ display: flex;
+ justify-content: space-between;
+ margin: 10px;
+ }
+ margin: 10px;
+}
diff --git a/packages/column-builder/src/components/strat-name/query-list/index.ts b/packages/column-builder/src/components/strat-name/query-list/index.ts
new file mode 100644
index 00000000..1bed1dde
--- /dev/null
+++ b/packages/column-builder/src/components/strat-name/query-list/index.ts
@@ -0,0 +1 @@
+export * from "./query-list";
diff --git a/packages/column-builder/src/components/strat-name/query-list/query-list.ts b/packages/column-builder/src/components/strat-name/query-list/query-list.ts
new file mode 100644
index 00000000..bd4e1700
--- /dev/null
+++ b/packages/column-builder/src/components/strat-name/query-list/query-list.ts
@@ -0,0 +1,201 @@
+import React, { useState, useEffect } from "react";
+import { hyperStyled } from "@macrostrat/hyper";
+import {
+ QueryList,
+ ItemRenderer,
+ IQueryListRendererProps,
+ ItemPredicate,
+} from "@blueprintjs/select";
+import pg from "../../../db";
+import {
+ Button,
+ Callout,
+ InputGroup,
+ MenuItem,
+ NonIdealState,
+ Tag,
+} from "@blueprintjs/core";
+import styles from "./strat-name.module.scss";
+import {
+ PostgrestFilterBuilder,
+ PostgrestQueryBuilder,
+} from "@supabase/postgrest-js";
+import { StratNameI } from "~/types";
+import { Tooltip2 } from "@blueprintjs/popover2";
+
+const h = hyperStyled(styles);
+
+const StrtaNameQueryList = QueryList.ofType();
+
+const itemPredicate: ItemPredicate = (query, item, index) => {
+ const { strat_name } = item;
+
+ return strat_name?.toLowerCase().indexOf(query.toLowerCase()) >= 0;
+};
+
+const SourceTag = ({ source }: { source: string | undefined }) => {
+ return h.if(typeof source !== "undefined")(
+ Tooltip2,
+ {
+ content: source ?? "",
+ className: "source-text",
+ placement: "top",
+ minimal: true,
+ },
+ [
+ h.if(source === "unrelated")(Tag, { minimal: true, intent: "danger" }, [
+ h("b", ["may be unrelated"]),
+ ]),
+ h.if(source !== "unrelated")(Tag, { minimal: true }, [h("i", [source])]),
+ ]
+ );
+};
+
+const AuthorTag = ({
+ author,
+ concept_id,
+}: {
+ author: string | null;
+ concept_id: number | null;
+}) => {
+ return h(React.Fragment, [
+ h("div.author-tag", [
+ h.if(author != null)(Tag, { intent: "success", minimal: true }, [author]),
+ ]),
+ h("div.author-tag", [
+ h.if(!concept_id)(Tag, { intent: "warning", minimal: true }, "Unlinked"),
+ ]),
+ ]);
+};
+
+const StratNameListItem = (props: StratNameI) => {
+ const { strat_name, author, rank, parent, source, concept_id } = props;
+
+ const parentText = parent ? `${parent}` : "";
+
+ return h("div", [
+ h("div.flex-between", [
+ h("div.name-text", [
+ h("b", [`${strat_name} ${rank}`]),
+ h("i.parent-name", [`${parentText}`]),
+ ]),
+ h("div.author-source-tag", [
+ h(SourceTag, { source }),
+ h(AuthorTag, { author, concept_id }),
+ ]),
+ ]),
+ ]);
+};
+
+const StratNameItemRenderer: ItemRenderer = (
+ item: StratNameI,
+ { handleClick, index, modifiers }
+) => {
+ return h(MenuItem, {
+ key: index,
+ text: h(StratNameListItem, { ...item }),
+ onClick: handleClick,
+ active: modifiers.active,
+ });
+};
+
+const StratNameNewRenderer = (props: { onClickCreateNew: () => void }) => {
+ return h(NonIdealState, {
+ icon: "warning-sign",
+ title: "No results in Macrostrat lexicon",
+ description: h("div", [
+ h("li", ["Ensure column location is correct"]),
+ h("li", ["Try an alternative spelling"]),
+ ]),
+ action: h(
+ Button,
+ {
+ intent: "warning",
+ onClick: props.onClickCreateNew,
+ },
+ ["Create new"]
+ ),
+ });
+};
+
+const StratNameQueryListRenderer = (
+ props: IQueryListRendererProps
+) => {
+ const { itemList, handleKeyDown, handleKeyUp, ...listProps } = props;
+ return h(
+ "div.lith-query-list-renderer",
+ { onKeyDown: handleKeyDown, onKeyUp: handleKeyUp },
+ [
+ h(InputGroup, {
+ ["aria-autocomplete"]: "list",
+ leftIcon: "search",
+ placeholder: "Search for a stratigraphic name",
+ onChange: listProps.handleQueryChange,
+ value: listProps.query,
+ }),
+ itemList,
+ ]
+ );
+};
+
+const getStratNames = async (
+ query: string,
+ setNames: (e: StratNameI[]) => void,
+ col_id?: number
+) => {
+ let baseQuery:
+ | PostgrestFilterBuilder
+ | PostgrestQueryBuilder = pg.from("strat_names");
+ if (typeof col_id !== "undefined") {
+ baseQuery = pg.rpc("get_strat_names_col_priority", { _col_id: col_id });
+ }
+ if (query.length > 2) {
+ const { data, error } = await baseQuery
+ .select()
+ .ilike("strat_name", `%${query}%`)
+ .limit(50);
+ setNames(data ?? []);
+ } else {
+ const { data, error } = await baseQuery.select().limit(50);
+ setNames(data ?? []);
+ }
+};
+
+interface StratNameSelectProps {
+ onItemSelect: (l: StratNameI) => void;
+ onClickCreateNew: () => void;
+ col_id: number;
+}
+
+function StratNameSelect(props: StratNameSelectProps) {
+ const [names, setNames] = useState([]);
+ const onQueryChange = (i: string) => {
+ getStratNames(i, (e: StratNameI[]) => setNames(e), props.col_id);
+ };
+
+ useEffect(() => {
+ onQueryChange("");
+ }, []);
+
+ return h(StrtaNameQueryList, {
+ itemRenderer: StratNameItemRenderer,
+ itemPredicate,
+ onItemSelect: props.onItemSelect,
+ items: names,
+ renderer: StratNameQueryListRenderer,
+ resetOnSelect: false,
+ noResults: h(StratNameNewRenderer, {
+ onClickCreateNew: props.onClickCreateNew,
+ }),
+ menuProps: {
+ style: {
+ maxWidth: "100%",
+ margin: "0 10px",
+ maxHeight: "400px !important",
+ },
+ },
+ onQueryChange,
+ });
+}
+
+export { StratNameSelect, StratNameListItem, AuthorTag };
diff --git a/packages/column-builder/src/components/strat-name/query-list/strat-name.module.scss b/packages/column-builder/src/components/strat-name/query-list/strat-name.module.scss
new file mode 100644
index 00000000..79565315
--- /dev/null
+++ b/packages/column-builder/src/components/strat-name/query-list/strat-name.module.scss
@@ -0,0 +1,29 @@
+.flex-between {
+ display: flex;
+ justify-content: space-between;
+ min-height: 2.5rem;
+}
+.source-text {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 150px;
+ text-align: right;
+}
+.name-text {
+ display: flex;
+ flex-direction: column;
+}
+.author-source-tag {
+ display: flex;
+}
+.author-tag {
+ margin-left: 3px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.short {
+ max-width: 150px;
+}
+.parent-name {
+ color: #5f6b7c;
+}
diff --git a/packages/column-builder/src/components/strat-name/strat-name-editor.ts b/packages/column-builder/src/components/strat-name/strat-name-editor.ts
new file mode 100644
index 00000000..22902b78
--- /dev/null
+++ b/packages/column-builder/src/components/strat-name/strat-name-editor.ts
@@ -0,0 +1,210 @@
+import { hyperStyled } from "@macrostrat/hyper";
+import { StratNameSuggest } from "@macrostrat-web/column-builder/src";
+import { Select, ItemRenderer } from "@blueprintjs/select";
+import {
+ Button,
+ MenuItem,
+ FormGroup,
+ InputGroup,
+ Icon,
+ Card,
+ Callout,
+} from "@blueprintjs/core";
+import { ModelEditor, useModelEditor } from "@macrostrat/ui-components";
+import styles from "../comp.module.sass";
+import { RANK, StratNameI } from "../../types";
+import { SubmitButton } from "..";
+import { StratNameDataI } from ".";
+import { StratNameHierarchy } from "./hierarchy";
+import { DataI, ItemSelect } from "../suggest";
+import { Checkbox } from "@blueprintjs/core";
+
+const h = hyperStyled(styles);
+
+interface Model {
+ model: StratNameI;
+ actions: any;
+ hasChanges: () => boolean;
+}
+
+export function RankSelect({
+ updateStratName,
+ rank,
+}: {
+ updateStratName: (field: string, i: any) => void;
+ rank?: string;
+}) {
+ const possibleRanks = [
+ { value: "SGp", data: "SGp" },
+ { value: "Gp", data: "Gp" },
+ { value: "SubGp", data: "SubGp" },
+ { value: "Fm", data: "Fm" },
+ { value: "Mbr", data: "Mbr" },
+ { value: "Bed", data: "Bed" },
+ ];
+
+ const itemRenderer: ItemRenderer> = (
+ item: DataI,
+ { handleClick, index }
+ ) => {
+ const active = rank == item.value;
+ return h(MenuItem, {
+ key: index,
+ labelElement: active ? h(Icon, { icon: "tick" }) : null,
+ text: item.value,
+ onClick: handleClick,
+ active: active,
+ });
+ };
+
+ return h(
+ ItemSelect,
+ {
+ items: possibleRanks,
+ itemRenderer,
+ // selectedItem: model.rank,
+ onItemSelect: (item) => updateStratName("rank", item.value),
+ },
+ [h(Button, { rightIcon: "double-caret-vertical" }, [rank ?? "Fm"])]
+ );
+}
+
+/*
+Edit the name and rank of strat_name - text input and select
+Assign other strat_name as parent
+Add to a concept
+*/
+function StratNameEdit(props: { new_name?: boolean }) {
+ const { new_name = false } = props;
+ const { model, actions, hasChanges }: Model = useModelEditor();
+
+ const updateStratName = (field: string, e: any) => {
+ actions.updateState({ model: { [field]: { $set: e } } });
+ };
+
+ const title = new_name ? "Create new strat name" : "Edit strat name";
+ const helperText = new_name
+ ? "Create new strat name"
+ : "Edit existing strat name";
+
+ return h("div", [
+ h(StratNameHierarchy, { strat_name_id: model.id }),
+ h("div", [
+ h(Card, [
+ h("h3", { style: { marginTop: 0 } }, [title]),
+ h("div.row", [
+ h(
+ FormGroup,
+ {
+ helperText: helperText,
+ label: "Stratigraphic Name",
+ },
+ [
+ h(InputGroup, {
+ style: { width: "200px" },
+ defaultValue: model.strat_name,
+ onChange: (e) => updateStratName("strat_name", e.target.value),
+ }),
+ ]
+ ),
+ h(FormGroup, { label: "Rank" }, [
+ h(RankSelect, { updateStratName, rank: model.rank }),
+ ]),
+ ]),
+ h.if(!new_name)("div.row", [
+ h(Checkbox, { label: "Apply globally", style: { margin: "5px" } }),
+ h(Checkbox, {
+ label: "Apply to this unit only (create new strat name)",
+ style: { margin: "5px" },
+ }),
+ ]),
+ h(
+ Callout,
+ {
+ intent: "warning",
+ title: "Unlinked",
+ style: { width: "265px", borderRadius: "5px" },
+ },
+ ["This name will be unlinked to external resources"]
+ ),
+ ]),
+ h(Card, [
+ h("h3", { style: { marginTop: 0 } }, ["Edit Hierarcy"]),
+ h(
+ FormGroup,
+ {
+ helperText: `This will assign the parent of ${model.strat_name} ${model.rank}`,
+ label: "(re)-Assign Parent",
+ labelFor: "descrip-input",
+ },
+ [
+ h(StratNameSuggest, {
+ onChange: (item: StratNameDataI) => {
+ updateStratName("parent", item.data);
+ },
+ }),
+ ]
+ ),
+ h(
+ FormGroup,
+ {
+ helperText: `This will assign a child to ${model.strat_name} ${model.rank}`,
+ label: `Add Name to ${model.strat_name} ${model.rank}`,
+ },
+ [
+ h(StratNameSuggest, {
+ onChange: (item: StratNameDataI) => {
+ updateStratName("child", item.data);
+ },
+ }),
+ ]
+ ),
+ h("h3", { style: { marginTop: 0 } }, ["Create new strat name"]),
+ h("div.row", [
+ h(
+ FormGroup,
+ {
+ label: "Create new name",
+ labelInfo: "(optional)",
+ },
+ [
+ h(InputGroup, {
+ style: { width: "200px" },
+ onChange: (e) => console.log(e.target.value),
+ }),
+ ]
+ ),
+ h(FormGroup, { label: "Rank" }, [h(RankSelect, { updateStratName })]),
+ ]),
+ h("div.row", [
+ h(Checkbox, { label: "Assign as Child", style: { margin: "5px" } }),
+ h(Checkbox, {
+ label: "Assign as Parent",
+ style: { margin: "5px" },
+ }),
+ ]),
+ ]),
+ h(SubmitButton),
+ ]),
+ ]);
+}
+
+interface StratNameEditorProps {
+ model: StratNameI | {};
+ persistChanges: (e: StratNameI, c: Partial) => StratNameI;
+ new_name?: boolean;
+}
+
+export function StratNameEditor(props: StratNameEditorProps) {
+ const { new_name } = props;
+ return h(
+ ModelEditor,
+ {
+ model: props.model,
+ persistChanges: props.persistChanges,
+ isEditing: true,
+ canEdit: true,
+ },
+ [h(StratNameEdit, { new_name })]
+ );
+}
diff --git a/packages/column-builder/src/components/strat-name/strat-name.ts b/packages/column-builder/src/components/strat-name/strat-name.ts
new file mode 100644
index 00000000..f1f98642
--- /dev/null
+++ b/packages/column-builder/src/components/strat-name/strat-name.ts
@@ -0,0 +1,92 @@
+import { useState, useEffect } from "react";
+import pg from "../../db";
+import { hyperStyled } from "@macrostrat/hyper";
+import styles from "../comp.module.sass";
+import { StratNameI } from "../..";
+import { MenuItem } from "@blueprintjs/core";
+import { ItemRenderer } from "@blueprintjs/select";
+import { ItemSuggest } from "../suggest";
+import {
+ PostgrestFilterBuilder,
+ PostgrestQueryBuilder,
+} from "@supabase/postgrest-js";
+
+const h = hyperStyled(styles);
+
+export interface StratNameDataI {
+ value: string;
+ data: StratNameI;
+}
+
+const itemRenderer: ItemRenderer = (
+ item: StratNameDataI,
+ { handleClick, modifiers, index }
+) => {
+ const { value, data } = item;
+
+ return h(MenuItem, {
+ key: index,
+ intent: data.concept_id ? "primary" : "warning",
+ text: value,
+ onClick: handleClick,
+ active: modifiers.active,
+ });
+};
+
+const getStratNames = async (
+ query: string,
+ setNames: (e: StratNameDataI[]) => void,
+ col_id?: number
+) => {
+ let baseQuery: PostgrestFilterBuilder | PostgrestQueryBuilder =
+ pg.from("strat_names");
+ if (typeof col_id !== "undefined") {
+ baseQuery = pg.rpc("get_strat_names_col_priority", { _col_id: col_id });
+ }
+ if (query.length > 2) {
+ const { data, error } = await baseQuery
+ .select()
+ .like("strat_name", `%${query}%`)
+ .limit(50);
+ const d: StratNameDataI[] = data?.map((d: StratNameI) => {
+ return { value: `${d.strat_name} ${d.rank}`, data: d };
+ });
+ setNames(d);
+ } else {
+ const { data, error } = await baseQuery.select().limit(50);
+ const d: StratNameDataI[] = data?.map((d: StratNameI) => {
+ return { value: `${d.strat_name} ${d.rank}`, data: d };
+ });
+ setNames(d);
+ }
+};
+
+interface StratCellProps {
+ initialSelected?: StratNameDataI | undefined;
+ onChange: (item: StratNameDataI) => void;
+ placeholder?: string;
+ col_id?: number;
+}
+
+function StratNameSuggest(props: StratCellProps) {
+ const [names, setNames] = useState([]);
+
+ const onQueryChange = (i: string) => {
+ getStratNames(i, (e: StratNameDataI[]) => setNames(e), props.col_id);
+ };
+
+ useEffect(() => {
+ onQueryChange("");
+ }, []);
+
+ return h(ItemSuggest, {
+ items: names,
+ onQueryChange: onQueryChange,
+ onChange: props.onChange,
+ initialSelected: props.initialSelected,
+ itemRenderer,
+ placeholder: props.placeholder,
+ });
+}
+
+export { StratNameSuggest };
diff --git a/packages/column-builder/src/components/suggest.ts b/packages/column-builder/src/components/suggest.ts
new file mode 100644
index 00000000..c3fe0320
--- /dev/null
+++ b/packages/column-builder/src/components/suggest.ts
@@ -0,0 +1,150 @@
+import { ReactChild, useEffect, useState } from "react";
+import { hyperStyled } from "@macrostrat/hyper";
+import {
+ Suggest,
+ ItemRenderer,
+ ItemPredicate,
+ Select,
+ ItemListRenderer,
+} from "@blueprintjs/select";
+import { MenuItem, Icon, PopoverPosition } from "@blueprintjs/core";
+import styles from "./comp.module.sass";
+
+const h = hyperStyled(styles);
+
+export interface DataI {
+ value: string;
+ data: T;
+}
+
+interface SuggestI {
+ onChange: (e: DataI) => void;
+ initialSelected?: DataI;
+ items: DataI[];
+ itemRenderer?: ItemRenderer>;
+ onQueryChange?: (e: string) => void;
+ placeholder?: string;
+}
+const ItemSuggestComponent = Suggest.ofType();
+
+function ItemSuggest(props: SuggestI) {
+ let itemz = [...props.items];
+ //sees if initialSelected is in list, and moves to front
+ if (
+ props.initialSelected &&
+ props.items.map((s) => s.value).includes(props.initialSelected.value)
+ ) {
+ const spot = itemz.map((s) => s.value).indexOf(props.initialSelected.value);
+ itemz.splice(spot, 1);
+ }
+
+ itemz = props.initialSelected ? [props.initialSelected, ...itemz] : itemz;
+
+ const [selected, setSelected] = useState(props.initialSelected);
+
+ useEffect(() => {
+ setSelected(props.initialSelected);
+ }, [props.initialSelected]);
+
+ const itemRenderer: ItemRenderer> = (
+ item: DataI,
+ { handleClick, modifiers }
+ ) => {
+ const { value, data } = item;
+ const active = selected?.value == value;
+ return h(MenuItem, {
+ key: value,
+ labelElement: active ? h(Icon, { icon: "tick" }) : null,
+ text: value,
+ onClick: handleClick,
+ active: modifiers.active,
+ });
+ };
+
+ const itemPredicate: ItemPredicate> = (
+ query: string,
+ item: DataI
+ ) => {
+ const { value } = item;
+
+ return value?.toLowerCase().indexOf(query.toLowerCase()) >= 0;
+ };
+
+ const onItemSelect = (item: DataI) => {
+ setSelected(item);
+ props.onChange(item);
+ };
+
+ return h(ItemSuggestComponent, {
+ inputValueRenderer: (item: DataI) => item.value,
+ items: itemz,
+ popoverProps: {
+ minimal: true,
+ },
+ inputProps: {
+ placeholder: props.placeholder,
+ },
+ selectedItem: selected,
+ onItemSelect: onItemSelect,
+ itemRenderer: props.itemRenderer ?? itemRenderer,
+ itemPredicate: itemPredicate,
+ onQueryChange: props.onQueryChange,
+ resetOnQuery: true,
+ noResults: h(MenuItem, { disabled: true, text: "No Results" }),
+ });
+}
+
+interface ItemSelectI {
+ items: DataI[];
+ onItemSelect: (e: DataI) => void;
+ children: ReactChild;
+ itemRenderer?: ItemRenderer>;
+ itemPredicate?: ItemPredicate>;
+ itemListRenderer?: ItemListRenderer>;
+ filterable?: boolean;
+ position?: PopoverPosition;
+}
+
+const ItemSelectComponent = Select.ofType>();
+
+const itemRenderer: ItemRenderer> = (
+ item: DataI,
+ { handleClick, index, modifiers }
+) => {
+ const { value, data } = item;
+ return h(MenuItem, {
+ key: index,
+ text: value,
+ onClick: handleClick,
+ active: modifiers.active,
+ });
+};
+
+const itemPredicate: ItemPredicate> = (query, item, _index) => {
+ const { value } = item;
+
+ return value?.toLowerCase().indexOf(query.toLowerCase()) >= 0;
+};
+
+function ItemSelect(props: ItemSelectI) {
+ return h(
+ ItemSelectComponent,
+ {
+ filterable: props.filterable || false,
+ items: props.items,
+ popoverProps: {
+ minimal: true,
+ position: props.position,
+ popoverClassName: styles.itemSelectPopover,
+ },
+ itemListRenderer: props.itemListRenderer,
+ itemRenderer: props.itemRenderer || itemRenderer,
+ onItemSelect: props.onItemSelect,
+ itemPredicate: props.itemPredicate || itemPredicate,
+ noResults: h(MenuItem, { disabled: true, text: "No Results" }),
+ },
+ [props.children]
+ );
+}
+
+export { ItemSuggest, ItemSelect };
diff --git a/packages/column-builder/src/components/table.ts b/packages/column-builder/src/components/table.ts
new file mode 100644
index 00000000..e172035d
--- /dev/null
+++ b/packages/column-builder/src/components/table.ts
@@ -0,0 +1,283 @@
+import React, { useCallback } from "react";
+import { ReactChild } from "react";
+import h from "./comp.module.sass";
+import {
+ Draggable,
+ DraggableProvided,
+ DraggableStateSnapshot,
+ Droppable,
+ DroppableProvided,
+} from "react-beautiful-dnd";
+import { Card, Icon } from "@blueprintjs/core";
+import { useNavigate } from "../components";
+
+interface RowProps {
+ children: ReactChild;
+ draggableId?: string;
+ index: number;
+ href?: string;
+ drag?: boolean;
+ isMoved?: boolean;
+ onDoubleClick?: () => void;
+}
+
+const routePrefix = "/dev/column-editor";
+
+const getItemStyle = (isDragging: boolean, draggableStyle: any) => ({
+ display: isDragging ? "table" : "",
+ ...draggableStyle,
+});
+
+const RowWrapper = (props: {
+ link: string | undefined;
+ children: ReactChild;
+}) => {
+ const { link, children } = props;
+
+ return children;
+ // TODO: row links break things, now that links are not ephemeral items
+ /*
+ if (typeof link === "undefined") {
+ return h(React.Fragment, [children]);
+ } else {
+ return h(Link, { href: link }, [children]);
+ }
+ */
+};
+
+function Row(props: { href: string; children: ReactChild }) {
+ const { href, children } = props;
+ const navigate = useNavigate();
+
+ const onClick = useCallback(
+ (evt) => {
+ navigate(href);
+ },
+ [href]
+ );
+
+ return h("tr", { onClick }, children);
+}
+
+function DraggableRow(props: RowProps) {
+ const {
+ draggableId = "",
+ drag = false,
+ onDoubleClick = () => console.log("double clicked!"),
+ href,
+ isMoved,
+ } = props;
+
+ const className = isMoved ? "unit-moved" : null;
+
+ return h(
+ Draggable,
+ {
+ key: props.index,
+ index: props.index,
+ isDragDisabled: !drag,
+ draggableId,
+ },
+ [
+ (provided: DraggableProvided, snapshot: DraggableStateSnapshot) => {
+ return h(
+ `tr`,
+ {
+ onClick: (e: MouseEvent) => {
+ e.stopPropagation();
+ if (e.detail == 2) {
+ onDoubleClick();
+ if (href != null) {
+ navigate(href);
+ }
+ }
+ },
+ className,
+ ref: provided.innerRef,
+ ...provided.draggableProps,
+ style: getItemStyle(
+ snapshot.isDragging,
+ provided.draggableProps.style
+ ),
+ },
+ [
+ h.if(drag)(
+ "td",
+ {
+ ...provided.dragHandleProps,
+ width: "2%",
+ style: { verticalAlign: "middle" },
+ },
+ [h(Icon, { icon: "drag-handle-vertical" })]
+ ),
+ props.children,
+ ]
+ );
+ },
+ ]
+ );
+}
+
+interface FeatureCellI {
+ text: string;
+ children: ReactChild;
+ colSpan?: number;
+}
+
+function FeatureCell(props: FeatureCellI) {
+ return h(React.Fragment, [
+ h("td", [h("h4.strat-name", [props.text])]),
+ h("td", { colSpan: props.colSpan }, [props.children]),
+ ]);
+}
+
+interface TableProps {
+ interactive: boolean;
+ children: ReactChild;
+ headers?: any[];
+ title?: string;
+}
+
+function Table(props: TableProps) {
+ const { headers = [] } = props;
+ const baseClass =
+ "bp5-html-table .bp5-html-table-condensed .bp5-html-table-bordered";
+ let className = props.interactive
+ ? `${baseClass} .bp5-interactive`
+ : baseClass;
+
+ return h(Card, { className: "table-container" }, [
+ h(`table`, { style: { width: "100%", tableLayout: "auto" }, className }, [
+ h.if(headers.length > 0)(TableHeader, {
+ headers: headers,
+ title: props.title,
+ }),
+ h("tbody", [props.children]),
+ ]),
+ ]);
+}
+
+interface DnDTableProps {
+ interactive: boolean;
+ children: ReactChild;
+ drag?: boolean;
+ headers?: any[];
+ droppableId?: string;
+ draggableId?: string;
+ title?: string;
+ index: number;
+ widths?: number[];
+}
+
+function DnDTable(props: DnDTableProps) {
+ const {
+ drag = false,
+ headers = [],
+ widths,
+ droppableId = "table-drop-zone",
+ } = props;
+ const baseClass =
+ "bp5-html-table .bp5-html-table-condensed .bp5-html-table-bordered .base-table .full-width";
+ let tableClassName = props.interactive
+ ? `${baseClass} .bp5-interactive`
+ : baseClass;
+
+ return h(
+ Draggable,
+ {
+ key: props.index,
+ index: props.index,
+ isDragDisabled: !drag,
+ draggableId: props.draggableId ?? "",
+ },
+ [
+ (provided: DraggableProvided, snapshot: DraggableStateSnapshot) => {
+ return h(
+ `table.${tableClassName}`,
+ {
+ ref: provided.innerRef,
+ ...provided.draggableProps,
+ },
+ [
+ h.if(headers.length > 0)(TableHeader, {
+ dragProps: provided.dragHandleProps,
+ headers: headers,
+ widths,
+ title: props.title,
+ }),
+ h(TableBody, { drag, droppableId }, [props.children]),
+ ]
+ );
+ },
+ ]
+ );
+}
+
+function TableBody(props: {
+ children: ReactChild;
+ drag?: boolean;
+ droppableId?: string;
+}) {
+ const { drag = false, droppableId = "table-drop" } = props;
+ return h(
+ Droppable,
+ { droppableId: droppableId, isDropDisabled: !drag, type: "table-body" },
+ [
+ (provided: DroppableProvided) => {
+ return h(
+ "tbody",
+ {
+ ...provided.droppableProps,
+ ref: provided.innerRef,
+ },
+ [props.children, provided.placeholder]
+ );
+ },
+ ]
+ );
+}
+
+function TableHeader(props: {
+ headers: any[];
+ widths?: number[];
+ title?: string;
+ dragProps?: any;
+}) {
+ return h(React.Fragment, [
+ h.if(props.title != null)("thead", [
+ h("tr.table-header-row", [
+ h(
+ "th.table-header",
+ {
+ ...props.dragProps,
+ colSpan: props.headers.length,
+ },
+ [props.title]
+ ),
+ ]),
+ ]),
+ h("colgroup", [
+ props.widths?.map((width, i) => {
+ return h("col", {
+ key: i,
+ width: `${typeof width != "undefined" ? width : ""}%`,
+ });
+ }),
+ ]),
+ h("thead", [
+ h("tr", [
+ props.headers.map((head, i) => {
+ return h(
+ "th",
+ {
+ key: i,
+ },
+ [head]
+ );
+ }),
+ ]),
+ ]),
+ ]);
+}
+
+export { Row, Table, DnDTable, FeatureCell, TableHeader, DraggableRow };
diff --git a/packages/column-builder/src/components/tag.ts b/packages/column-builder/src/components/tag.ts
new file mode 100644
index 00000000..4b8aa81b
--- /dev/null
+++ b/packages/column-builder/src/components/tag.ts
@@ -0,0 +1,252 @@
+import { MouseEventHandler } from "react";
+import { hyperStyled } from "@macrostrat/hyper";
+import { Tooltip2 as Tooltip } from "@blueprintjs/popover2";
+import { Button, MenuItem, Spinner, Tag } from "@blueprintjs/core";
+import {
+ IItemModifiers,
+ ItemPredicate,
+ ItemRenderer,
+} from "@blueprintjs/select";
+import pg, { usePostgrest } from "../db";
+import styles from "./comp.module.sass";
+import { EnvironUnit, LithUnit } from "..";
+import { ItemSelect } from "./suggest";
+
+const h = hyperStyled(styles);
+
+interface SelectDataI {
+ data: any;
+ value: any;
+}
+
+interface tagInfo {
+ name: string;
+ description: string;
+ color: string;
+ id?: number;
+}
+
+interface tagBody extends tagInfo {
+ onClickDelete?: (e: number) => void;
+ onClick?: (e: tagInfo) => void | null;
+ disabled?: boolean;
+ isEditing?: boolean;
+ large?: boolean;
+}
+
+export function isTooDark(hexcolor: string) {
+ var r = parseInt(hexcolor.substr(1, 2), 16);
+ var g = parseInt(hexcolor.substr(3, 2), 16);
+ var b = parseInt(hexcolor.substr(4, 2), 16);
+ var yiq = (r * 299 + g * 587 + b * 114) / 1000;
+
+ return yiq < 90;
+}
+
+/**
+ *
+ * @param props: tagBody
+ * @returns
+ */
+function TagBody(props: tagBody) {
+ const {
+ name,
+ description,
+ color,
+ onClick = (e: tagInfo) => {},
+ onClickDelete = () => {},
+ isEditing = false,
+ id = 10000,
+ disabled = false,
+ large = true,
+ } = props;
+
+ const showName = name.length > 0 ? name : "Tag Preview";
+ const darkTag = isTooDark(color);
+
+ const textColor = darkTag ? "white" : "black";
+
+ let tag: tagInfo = { id, name, description, color };
+
+ const onRemove = () => {
+ onClickDelete(tag.id || 0);
+ };
+
+ return h(Tooltip, { content: description, disabled }, [
+ h(
+ Tag,
+ {
+ key: id,
+ large,
+ round: true,
+ className: styles.tag,
+ onRemove: isEditing ? onRemove : undefined,
+ onClick: (e) => onClick(tag),
+ interactive: props.onClick != null,
+ style: { backgroundColor: color, color: textColor },
+ },
+ [showName]
+ ),
+ ]);
+}
+
+interface LithMenuItemProps {
+ data: { name: string; color: string };
+ modifiers?: IItemModifiers;
+ handleClick: MouseEventHandler;
+}
+
+export function LithMenuItem(props: LithMenuItemProps) {
+ const { modifiers, handleClick, data } = props;
+
+ const style =
+ modifiers?.active ?? false
+ ? {
+ marginBottom: "2px",
+ }
+ : {
+ backgroundColor: data.color + "40", // add opaquness
+ marginBottom: "2px",
+ };
+
+ return h(MenuItem, {
+ active: modifiers?.active,
+ text: data.name,
+ onClick: handleClick,
+ style,
+ });
+}
+
+const lithItemRenderer: ItemRenderer = (
+ item: SelectDataI,
+ { handleClick, index, modifiers }
+) => {
+ const { value, data } = item;
+
+ return h(LithMenuItem, { key: index, data, modifiers, handleClick });
+};
+
+const itemPredicate: ItemPredicate = (query, item, index) => {
+ const {
+ data: { name },
+ } = item;
+
+ return name?.toLowerCase().indexOf(query.toLowerCase()) >= 0;
+};
+
+function LithTagsAdd(props: { onClick: (e: Partial) => void }) {
+ const liths: Partial[] = usePostgrest(pg.from("liths"));
+ if (!liths) return null;
+
+ const data: { data: any; value: any }[] = liths.map((lith, i) => {
+ return {
+ data: {
+ id: lith.id || 0,
+ color: lith.lith_color || "fffff",
+ name: lith.lith || "None",
+ description: lith.lith_class || "None",
+ },
+ value: { ...lith, type: "dom" },
+ };
+ });
+
+ return h(
+ ItemSelect,
+ {
+ filterable: true,
+ items: data,
+ itemRenderer: lithItemRenderer,
+ itemPredicate,
+ position: "bottom-left",
+ onItemSelect: (item: SelectDataI) => {
+ props.onClick(item.value);
+ },
+ },
+ [h(Button, { icon: "plus", minimal: true, intent: "success" })]
+ );
+}
+
+const envItemRenderer: ItemRenderer = (
+ item: SelectDataI,
+ { handleClick, index, modifiers }
+) => {
+ const { value, data } = item;
+
+ const style = modifiers.active
+ ? {
+ marginBottom: "2px",
+ }
+ : {
+ backgroundColor: data.color + "40", // add opaquness
+ marginBottom: "2px",
+ };
+
+ return h(MenuItem, {
+ active: modifiers.active,
+ key: index,
+ text: data.name,
+ onClick: handleClick,
+ style,
+ });
+};
+
+function EnvTagsAdd(props: { onClick: (e: Partial) => void }) {
+ const envs: Partial[] = usePostgrest(pg.from("environs"));
+ if (!envs) return null;
+
+ const data: SelectDataI[] = envs.map((env, i) => {
+ return {
+ data: {
+ id: env.id || 0,
+ color: env.environ_color || "fffff",
+ name: env.environ || "None",
+ description: env.environ_class || "None",
+ },
+ value: env,
+ };
+ });
+
+ return h(
+ ItemSelect,
+ {
+ filterable: true,
+ items: data,
+ itemRenderer: envItemRenderer,
+ itemPredicate,
+ position: "bottom-left",
+ onItemSelect: (item: SelectDataI) => props.onClick(item.value),
+ },
+ [h(Button, { icon: "plus", minimal: true, intent: "success" })]
+ );
+}
+
+interface TagCellProps {
+ data: tagInfo[];
+ disabled?: boolean;
+ isEditing?: boolean;
+ onClick?: (e: tagInfo) => void | null;
+ onClickDelete?: (e: number) => void;
+ large?: boolean;
+}
+
+function TagContainerCell(props: TagCellProps) {
+ const { large = true } = props;
+ return h("div", [
+ props.data.map((tag, i) => {
+ const { id, name, color, description } = tag;
+ return h(TagBody, {
+ key: i,
+ id,
+ color,
+ onClick: props.onClick,
+ isEditing: props.isEditing,
+ onClickDelete: props.onClickDelete,
+ name,
+ description,
+ large,
+ });
+ }),
+ ]);
+}
+
+export { TagBody, TagContainerCell, EnvTagsAdd, LithTagsAdd };
diff --git a/packages/column-builder/src/components/unit-section-table/async-helpers.ts b/packages/column-builder/src/components/unit-section-table/async-helpers.ts
new file mode 100644
index 00000000..8b14c774
--- /dev/null
+++ b/packages/column-builder/src/components/unit-section-table/async-helpers.ts
@@ -0,0 +1,39 @@
+import { PostgrestError, PostgrestResponse } from "@supabase/postgrest-js";
+import pg from "../../db";
+import { UnitsView } from "~/types";
+import { SectionUnits } from "./reducer";
+
+const createNewSection = async (col_id: number) => {
+ const { data, error }: PostgrestResponse<{ id: number; col_id: number }> =
+ await pg.from("sections").insert([{ col_id }]);
+ return data;
+};
+
+const saveColumnReorder = async (sections: SectionUnits) => {
+ // multiple things need to be done here.
+ // We need to go through and set the section_id for each unit as well as the p_bottom
+ // this will run in o(n) time, where n is the number of units
+ let position_bottom = 1;
+ const updates: { id: number; section_id: number; position_bottom: number }[] =
+ [];
+ sections.map((section) => {
+ const section_id = parseInt(Object.keys(section)[0]);
+ const units = section[section_id];
+ console.log("p_b", position_bottom);
+ units.map((unit) => {
+ console.log("p_b", position_bottom);
+ updates.push({ id: unit.id, section_id, position_bottom });
+ //increment p_bottom for next unit
+ position_bottom = position_bottom + 1;
+ });
+ });
+ updates.map(async (update) => {
+ const { id, position_bottom, section_id } = update;
+ const { data, error }: PostgrestResponse = await pg
+ .from("units")
+ .update({ position_bottom, section_id })
+ .match({ id });
+ });
+};
+
+export { createNewSection, saveColumnReorder };
diff --git a/packages/column-builder/src/components/unit-section-table/helpers.ts b/packages/column-builder/src/components/unit-section-table/helpers.ts
new file mode 100644
index 00000000..0656dd3d
--- /dev/null
+++ b/packages/column-builder/src/components/unit-section-table/helpers.ts
@@ -0,0 +1,264 @@
+import React, { useState } from "react";
+import {
+ Button,
+ ButtonGroup,
+ Checkbox,
+ Menu,
+ MenuItem,
+ MenuDivider,
+} from "@blueprintjs/core";
+import { Popover2, Tooltip2 } from "@blueprintjs/popover2";
+import { UnitsView } from "@macrostrat-web/column-builder/src";
+import styles from "../comp.module.sass";
+import { hyperStyled } from "@macrostrat/hyper";
+import { useUnitSectionContext } from "./index";
+
+const h = hyperStyled(styles);
+
+function SectionUnitCheckBox(props: {
+ data: any;
+ onChange: (e: number) => void;
+}) {
+ const onChange = (e: any) => {
+ e.stopPropagation();
+ props.onChange(props.data);
+ };
+ return h(Checkbox, { onChange });
+}
+
+function MergeDivideBtn(props: {
+ onClick: () => void;
+ disabled: boolean;
+ text: string;
+}) {
+ return h(
+ Button,
+ {
+ disabled: props.disabled,
+ onClick: props.onClick,
+ },
+ [props.text]
+ );
+}
+
+export interface ColBtnMenuI {
+ toggleUnitsView?: () => void;
+ toggleDrag: () => void;
+ onSave: () => void;
+ onCancel: () => void;
+ state: {
+ unitsView: boolean;
+ drag: boolean;
+ mergeIds: number[];
+ moved: { [unit_id: number]: boolean };
+ };
+ mergeSections: () => void;
+ noSectionView: boolean;
+}
+
+function ColumnPageBtnMenu(props: ColBtnMenuI) {
+ const {
+ state: { unitsView, drag, mergeIds, moved },
+ } = props;
+ return h("div", [
+ //@ts-ignore
+ h(ButtonGroup, [
+ h(
+ Button,
+ {
+ onClick: props.toggleUnitsView,
+ intent: unitsView ? "primary" : "none",
+ disabled: unitsView,
+ },
+ ["Unit view"]
+ ),
+ h.if(!props.noSectionView)(
+ Button,
+ {
+ onClick: props.toggleUnitsView,
+ intent: !unitsView ? "primary" : "none",
+ disabled: !unitsView,
+ },
+ ["Section View"]
+ ),
+ h.if(!unitsView)(MergeDivideBtn, {
+ onClick: props.mergeSections,
+ disabled: mergeIds.length < 2,
+ text: "Merge Sections",
+ }),
+ ]),
+ h.if(unitsView)(ReorderUnitsBtnGrp, {
+ drag,
+ onClick: props.toggleDrag,
+ moved,
+ onSave: props.onSave,
+ onCancel: props.onCancel,
+ }),
+ ]);
+}
+
+function ReorderUnitsBtnGrp(props: {
+ drag: boolean;
+ onClick: () => void;
+ onCancel: () => void;
+ onSave: () => void;
+ moved: { [unit_id: number]: boolean };
+}) {
+ //@ts-ignore
+ return h(ButtonGroup, { style: { marginLeft: "20px" } }, [
+ h.if(!props.drag)(Button, { onClick: props.onClick }, ["Reorder Units"]),
+ h.if(props.drag)(
+ Button,
+ {
+ intent: "success",
+ onClick: props.onSave,
+ disabled: Object.keys(props.moved).length == 0,
+ },
+ ["Save"]
+ ),
+ h.if(props.drag)(Button, { intent: "danger", onClick: props.onCancel }, [
+ "Cancel",
+ ]),
+ ]);
+}
+
+enum UNIT_ADD_POISITON {
+ ABOVE = "above",
+ BELOW = "below",
+ EDIT = "edit",
+}
+
+export interface UnitRowContextMenuI {
+ // either we are adding a new unit above, below or editing the current unit
+ // or we are editing the unit inRow
+ unit: UnitsView;
+ unit_index: number;
+ section_index: number;
+ copyUnitUp: () => void;
+ copyUnitDown: () => void;
+ addEmptyUnit: (unit_index: number) => void;
+ editUnitAt: (unit_index: number) => void;
+}
+function UnitRowContextMenu(props: UnitRowContextMenuI) {
+ const { state, runAction } = useUnitSectionContext();
+ const SubMenu = ({ pos }: { pos: UNIT_ADD_POISITON }) => {
+ return h(React.Fragment, [
+ h(MenuItem, {
+ text: `Copy unit #${props.unit.id}`,
+ icon: "duplicate",
+ onClick: () => {
+ if (pos == UNIT_ADD_POISITON.ABOVE) {
+ props.copyUnitUp();
+ } else props.copyUnitDown();
+ },
+ }),
+ h(MenuItem, {
+ text: `With empty unit`,
+ icon: "new-object",
+ onClick: () => {
+ if (pos == UNIT_ADD_POISITON.ABOVE) {
+ props.addEmptyUnit(props.unit_index);
+ } else props.addEmptyUnit(props.unit_index + 1);
+ },
+ }),
+ ]);
+ };
+
+ const ContextMenu = () =>
+ h(Menu, [
+ h(
+ MenuItem,
+ {
+ text: "Add Unit Above",
+ icon: "circle-arrow-up",
+ },
+ [h(SubMenu, { pos: UNIT_ADD_POISITON.ABOVE })]
+ ),
+ h(
+ MenuItem,
+ {
+ text: "Add Unit Below",
+ icon: "circle-arrow-down",
+ },
+ [h(SubMenu, { pos: UNIT_ADD_POISITON.BELOW })]
+ ),
+ h(MenuItem, {
+ text: `Edit unit #${props.unit.id}`,
+ icon: "annotation",
+ onClick: () => props.editUnitAt(props.unit_index),
+ }),
+ h(MenuDivider),
+ h(MenuItem, {
+ text: `Delete unit #${props.unit.id}`,
+ icon: "trash",
+ intent: "danger",
+ onClick: () =>
+ runAction({
+ type: "remove-unit",
+ section_index: props.section_index,
+ unit_index: props.unit_index,
+ }),
+ }),
+ ]);
+
+ return h(
+ Popover2,
+ {
+ content: h(ContextMenu),
+ minimal: true,
+ position: "left-top",
+ },
+ [h(Button, { minimal: true, icon: "more" })]
+ );
+}
+
+function AddBtnBetweenRows(props: {
+ onClick: (e: any) => void;
+ colSpan: number;
+}) {
+ const [style, setStyle] = useState({ display: "none" });
+ return h("tr", [
+ h("td", { colSpan: props.colSpan, style: { padding: 0 } }, [
+ h(
+ Tooltip2,
+ {
+ content: "add unit",
+ fill: true,
+ position: "right",
+ intent: "success",
+ },
+ [
+ h(
+ "div.btwn-row-btn",
+ {
+ onMouseEnter: (e: React.MouseEvent) => {
+ setStyle({ display: "flex" });
+ },
+ onMouseLeave: (e: React.MouseEvent) => {
+ setStyle({ display: "none" });
+ },
+ onClick: props.onClick,
+ },
+ [
+ h(Button, {
+ intent: "success",
+ fill: true,
+ onClick: props.onClick,
+ style: { ...style, minHeight: "5px" },
+ }),
+ ]
+ ),
+ ]
+ ),
+ ]),
+ ]);
+}
+
+export {
+ SectionUnitCheckBox,
+ MergeDivideBtn,
+ ColumnPageBtnMenu,
+ AddBtnBetweenRows,
+ UNIT_ADD_POISITON,
+ UnitRowContextMenu,
+};
diff --git a/packages/column-builder/src/components/unit-section-table/index.ts b/packages/column-builder/src/components/unit-section-table/index.ts
new file mode 100644
index 00000000..2e79e7d7
--- /dev/null
+++ b/packages/column-builder/src/components/unit-section-table/index.ts
@@ -0,0 +1,2 @@
+export * from "./table";
+export * from "./reducer";
diff --git a/packages/column-builder/src/components/unit-section-table/reducer.ts b/packages/column-builder/src/components/unit-section-table/reducer.ts
new file mode 100644
index 00000000..c193ea77
--- /dev/null
+++ b/packages/column-builder/src/components/unit-section-table/reducer.ts
@@ -0,0 +1,414 @@
+import { Dispatch } from "react";
+import { DropResult } from "react-beautiful-dnd";
+import {
+ filterOrAddIds,
+ UnitsView,
+} from "@macrostrat-web/column-builder/src/index";
+import { persistNewUnit, persistUnitChanges } from "../unit/edit-helpers";
+import { createNewSection, saveColumnReorder } from "./async-helpers";
+
+///////////////// helper functions //////////////
+/*
+ This would be async and would persist to db
+ then would return db representation which we
+ would add to units in a Sync Action
+*/
+function persistUnit(unit: UnitsView) {
+ let color = "#FFFFF";
+ if (typeof unit.lith_unit !== "undefined" && unit.lith_unit.length > 0) {
+ color = unit?.lith_unit[0].lith_color;
+ }
+ const newUnit = {
+ ...unit,
+ id: unit.id ?? 666,
+ color: unit.color ?? color,
+ };
+ return newUnit;
+}
+
+// a little function to help us with reordering the result
+const reorder = (list: any[], startIndex: number, endIndex: number): void => {
+ const [removed] = list.splice(startIndex, 1);
+ list.splice(endIndex, 0, removed);
+};
+
+const addElementToList = (list: any[], index: number, element: any): void => {
+ list.splice(index, 0, element);
+};
+
+/////////////// Data Types //////////////////
+
+export type SectionUnits = { [section_id: string | number]: UnitsView[] }[];
+type UnitSection = { unit_id: number; section_id: number };
+
+/////////////// async actions //////////////////
+
+type CreateNewSection = {
+ type: "create-new-section";
+ index: number;
+ col_id: number;
+};
+
+type SaveReorder = { type: "save-reorder"; sections: SectionUnits };
+type SaveUnitAt = {
+ type: "save-unit-at";
+ section_index: number;
+ unit_index: number;
+ unit: UnitsView;
+ changeSet: Partial;
+ og_unit: UnitsView;
+ sections: SectionUnits;
+};
+/////////////// Action Types ///////////////
+
+type CancelReorder = { type: "cancel-reorder" };
+type SetMergeIds = { type: "set-merge-ids"; id: number };
+type MergeIds = { type: "merge-ids" };
+type DroppedUnit = {
+ type: "dropped-unit";
+ result: DropResult;
+};
+type DroppedSection = {
+ type: "dropped-section";
+ result: DropResult;
+};
+type ToggleDrag = { type: "toggle-drag" };
+type ToggleUnitsView = { type: "toggle-units-view" };
+type AddSectionAt = {
+ type: "add-section-at";
+ index: number;
+ section_id: number;
+};
+
+type AddUnitAt = {
+ type: "add-unit-at";
+ section_index: number;
+ unit_index: number;
+ unit: UnitsView;
+};
+
+type PersistEditsAt = {
+ type: "persist-edits-at";
+ section_index: number;
+ unit_index: number;
+ unit: UnitsView;
+};
+
+type EditUnitAt = {
+ type: "edit-unit-at";
+ section_index: number;
+ unit_index: number;
+};
+
+type CancelEditing = {
+ type: "cancel-editing";
+ section_index: number;
+ unit_index: number;
+};
+
+type RemoveUnit = {
+ type: "remove-unit";
+ section_index: number;
+ unit_index: number;
+};
+
+type PersistReorder = { type: "persist-reorder" };
+
+export type SyncActions =
+ | PersistReorder
+ | CancelReorder
+ | RemoveUnit
+ | CancelEditing
+ | AddSectionAt
+ | EditUnitAt
+ | SetMergeIds
+ | DroppedUnit
+ | DroppedSection
+ | MergeIds
+ | ToggleDrag
+ | AddUnitAt
+ | PersistEditsAt
+ | ToggleUnitsView;
+
+export type AsyncActions = CreateNewSection | SaveReorder | SaveUnitAt;
+
+export type Actions = SyncActions | AsyncActions;
+
+export interface EditorState {
+ open: boolean;
+ section_index: number;
+ unit_index: number;
+}
+
+export interface ColumnStateI {
+ col_id: number;
+ sections: SectionUnits;
+ originalSections: SectionUnits;
+ mergeIds: number[];
+ moved: { [unit_id: number]: boolean };
+ drag: boolean;
+ unitsView: boolean;
+ edit: EditorState;
+ unitsMovedToNewSections: UnitSection[];
+}
+
+export interface UnitSectionTableCtx {
+ state: ColumnStateI;
+ runAction(action: Actions): Promise;
+}
+
+/// we can filter async actions through here first
+export const useUnitSectionTableActions = (dispatch: Dispatch) => {
+ return async (action: Actions) => {
+ switch (action.type) {
+ case "create-new-section":
+ const data = await createNewSection(action.col_id);
+ if (!data) {
+ throw Error("Section was not created");
+ }
+ return dispatch({
+ type: "add-section-at",
+ index: action.index,
+ section_id: data[0].id,
+ });
+ case "save-reorder":
+ await saveColumnReorder(action.sections);
+ return dispatch({ type: "persist-reorder" });
+ case "save-unit-at":
+ let persistedUnit: UnitsView;
+ if (action.unit.id === "new") {
+ persistedUnit = await persistNewUnit(
+ action.og_unit,
+ action.unit,
+ action.changeSet
+ );
+ } else {
+ persistedUnit = await persistUnitChanges(
+ action.og_unit,
+ action.unit,
+ action.changeSet
+ );
+ }
+ await saveColumnReorder(action.sections);
+ return dispatch({
+ type: "persist-edits-at",
+ unit: persistedUnit,
+ section_index: action.section_index,
+ unit_index: action.unit_index,
+ });
+ default:
+ return dispatch(action);
+ }
+ };
+};
+
+const columnReducer = (state: ColumnStateI, action: Actions): ColumnStateI => {
+ const currSections: SectionUnits = JSON.parse(JSON.stringify(state.sections));
+ switch (action.type) {
+ case "cancel-editing":
+ const _section_id_ = Object.keys(currSections[action.section_index])[0];
+ const _unit_ =
+ currSections[action.section_index][_section_id_][action.unit_index];
+ if (_unit_.id == "new") {
+ state = { ...state, edit: { ...state.edit, open: false } };
+ return columnReducer(state, {
+ type: "remove-unit",
+ section_index: action.section_index,
+ unit_index: action.unit_index,
+ });
+ }
+
+ return {
+ ...state,
+ edit: {
+ ...state.edit,
+ open: false,
+ },
+ };
+ case "edit-unit-at":
+ return {
+ ...state,
+ edit: {
+ open: true,
+ section_index: action.section_index,
+ unit_index: action.unit_index,
+ },
+ };
+ case "set-merge-ids":
+ const currentIds = [...state.mergeIds];
+ const id = action.id;
+ const newIds = filterOrAddIds(id, currentIds);
+ return {
+ ...state,
+ mergeIds: newIds,
+ };
+ case "cancel-reorder":
+ return {
+ ...state,
+ sections: state.originalSections,
+ drag: false,
+ moved: {},
+ };
+ case "persist-reorder":
+ return {
+ ...state,
+ drag: false,
+ moved: {},
+ };
+ case "toggle-drag":
+ return {
+ ...state,
+ drag: !state.drag,
+ };
+ case "toggle-units-view":
+ return {
+ ...state,
+ unitsView: !state.unitsView,
+ };
+ case "merge-ids":
+ console.log("Merging sections ", state.mergeIds);
+ return state;
+ case "add-section-at":
+ const sectionIndex = action.index;
+ //@ts-ignore
+ const newSection: SectionUnits = { [action.section_id]: [] };
+ addElementToList(currSections, sectionIndex, newSection);
+ return { ...state, sections: currSections };
+ case "remove-unit":
+ const _section_id = Object.keys(currSections[action.section_index])[0];
+ currSections[action.section_index][_section_id].splice(
+ action.unit_index,
+ 1
+ );
+ return {
+ ...state,
+ sections: currSections,
+ };
+ case "add-unit-at":
+ // this will encapsulate the add top and bottom
+ // mutate a the sections list in place
+ const section_id = Object.keys(currSections[action.section_index])[0];
+
+ currSections[action.section_index][section_id].splice(
+ action.unit_index,
+ 0,
+ persistUnit(action.unit)
+ );
+ return {
+ ...state,
+ sections: currSections,
+ edit: {
+ open: true,
+ section_index: action.section_index,
+ unit_index: action.unit_index,
+ },
+ };
+ case "persist-edits-at":
+ const section_id_ = Object.keys(currSections[action.section_index])[0];
+
+ currSections[action.section_index][section_id_].splice(
+ action.unit_index,
+ 1,
+ persistUnit(action.unit)
+ );
+ return {
+ ...state,
+ sections: currSections,
+ edit: {
+ ...state.edit,
+ open: false,
+ },
+ };
+ case "dropped-section":
+ if (!action.result.combine) return state;
+ /* Merge sections!! What data should you expect?
+ draggableId : `${section_id} ${index}` of section that was dropped.
+ combine.draggableID: `${section_id} ${index}` of section that was dropped on.
+
+ Get the indexes, whichever is greater, take those units and append to smaller one
+ */
+ const [s_id, s_index] = action.result.draggableId.split(" ");
+ const [d_id, d_index] = action.result.combine.draggableId.split(" ");
+
+ let big = { id: s_id, index: parseInt(s_index) };
+ let small = { id: d_id, index: parseInt(d_index) };
+ if (parseInt(s_index) < parseInt(d_index)) {
+ big = { id: d_id, index: parseInt(d_index) };
+ small = { id: s_id, index: parseInt(s_index) };
+ }
+
+ const newMoved: { [x: number]: boolean } = {};
+ currSections[big.index][big.id].forEach((unit) => {
+ newMoved[unit.id] = true;
+ });
+ currSections[small.index][small.id].push(
+ ...currSections[big.index][big.id]
+ );
+ currSections.splice(big.index, 1);
+
+ // set all units in moved section to be moved
+
+ return {
+ ...state,
+ sections: currSections,
+ moved: { ...state.moved, ...newMoved },
+ };
+ case "dropped-unit":
+ if (
+ typeof action.result.destination === "undefined" ||
+ action.result.destination == null
+ )
+ return state;
+ let source_index = action.result.source.index;
+ let destination_index = action.result.destination.index;
+
+ /// our drop result source and destination provide
+ // The index of where to find the section in our list as well
+ // as the section_id itself.
+ const [sourceSectionIndex, sourceSection] =
+ action.result.source.droppableId.split(" ");
+ const [destSectionIndex, destSection] =
+ action.result.destination.droppableId.split(" ");
+
+ const movedUnitId =
+ currSections[parseInt(sourceSectionIndex)][sourceSection][source_index][
+ "id"
+ ];
+ if (sourceSection == destSection && source_index == destination_index) {
+ //we haven't moved
+ return state;
+ }
+
+ if (sourceSection === destSection) {
+ // same section
+ reorder(
+ currSections[parseInt(sourceSectionIndex)][sourceSection],
+ source_index,
+ destination_index
+ );
+ } else {
+ // we changed sections!
+ const [movedUnit] = currSections[parseInt(sourceSectionIndex)][
+ sourceSection
+ ].splice(source_index, 1);
+
+ movedUnit["section_id"] = parseInt(destSection);
+
+ currSections[parseInt(destSectionIndex)][destSection].splice(
+ destination_index,
+ 0,
+ movedUnit
+ );
+ }
+
+ return {
+ ...state,
+ moved: { ...state.moved, [movedUnitId]: true },
+ sections: currSections,
+ };
+ default:
+ return state;
+ }
+};
+
+export { columnReducer };
diff --git a/packages/column-builder/src/components/unit-section-table/section.ts b/packages/column-builder/src/components/unit-section-table/section.ts
new file mode 100644
index 00000000..5a740095
--- /dev/null
+++ b/packages/column-builder/src/components/unit-section-table/section.ts
@@ -0,0 +1,119 @@
+import { hyperStyled } from "@macrostrat/hyper";
+import { UnitsView } from "@macrostrat-web/column-builder/src";
+import { DnDTable } from "../table";
+import { UnitRow } from "./unit";
+import { useUnitSectionContext } from "./table";
+import { AddBtnBetweenRows } from "./helpers";
+import styles from "../comp.module.sass";
+
+const h = hyperStyled(styles);
+
+const getEmptyUnit = (col_id: number) => {
+ let emptyUnit: UnitsView = {
+ id: "new",
+ strat_name: "unnamed",
+ strat_names: [],
+ lith_unit: [],
+ environ_unit: [],
+ color: "#fffff",
+ col_id,
+ name_fo: "",
+ age_bottom: 0,
+ name_lo: "",
+ age_top: 0,
+ };
+ return emptyUnit;
+};
+
+interface SectionTableProps {
+ index: number;
+ section: { [section_id: number | string]: UnitsView[] };
+ drag: boolean;
+ moved: { [unit_id: number]: boolean };
+ addUnitAt: (unit: UnitsView, unit_index: number) => void;
+ editUnitAt: (unit_index: number) => void;
+}
+
+function SectionTable(props: SectionTableProps) {
+ const { index, drag } = props;
+ const { state, runAction } = useUnitSectionContext();
+ const { edit } = state;
+
+ let headers = [
+ "ID",
+ "Unit Name",
+ "Strat Name",
+ "Liths",
+ "Envs",
+ "Interval",
+ "Thickness",
+ "notes",
+ "",
+ ];
+ let widths = [7, 15, 15, 15, 15, 10, 8, 10, 5];
+ if (drag) {
+ headers = ["", ...headers];
+ widths = [5, 5, 15, 15, 15, 10, 10, 10, 10, 5];
+ }
+
+ const units: UnitsView[] = Object.values(props.section)[0];
+ const id = Object.keys(props.section)[0];
+
+ return h(
+ DnDTable,
+ {
+ index,
+ interactive: false,
+ headers,
+ widths,
+ title: `Section ${id}`,
+ draggableId: `${id} ${index}`,
+ drag,
+ droppableId: index.toString() + " " + id.toString(),
+ },
+
+ [
+ h.if(units.length == 0)(AddBtnBetweenRows, {
+ colSpan: headers.length,
+ onClick: (e) => {
+ e.stopPropagation();
+ props.addUnitAt(getEmptyUnit(state.col_id), 0);
+ },
+ }),
+ units.map((unit, j) => {
+ const isEditing =
+ edit.unit_index == j && edit.section_index == index && edit.open;
+
+ // these ids here are meaningless... this action needs to be persisted
+ const copyUnitDown = () => {
+ props.addUnitAt({ ...unit, id: "new" }, j + 1);
+ };
+ const copyUnitUp = () => {
+ props.addUnitAt({ ...unit, id: "new" }, j);
+ };
+ const addEmptyUnit = (unit_index: number) => {
+ props.addUnitAt(getEmptyUnit(unit.col_id), unit_index);
+ };
+ const editUnitAt = (unit_index: number) => {
+ props.editUnitAt(unit_index);
+ };
+ return h(UnitRow, {
+ key: unit.id,
+ unit,
+ drag,
+ unit_index: j,
+ section_index: index,
+ colSpan: headers.length,
+ isMoved: unit.id in props.moved,
+ inRowEditing: isEditing,
+ copyUnitDown,
+ copyUnitUp,
+ addEmptyUnit,
+ editUnitAt,
+ });
+ }),
+ ]
+ );
+}
+
+export { SectionTable };
diff --git a/packages/column-builder/src/components/unit-section-table/table.ts b/packages/column-builder/src/components/unit-section-table/table.ts
new file mode 100644
index 00000000..67a76ee0
--- /dev/null
+++ b/packages/column-builder/src/components/unit-section-table/table.ts
@@ -0,0 +1,208 @@
+import React, { createContext, useContext, useReducer } from "react";
+import {
+ ColumnStateI,
+ UnitsView,
+ ColSectionsTable,
+ ColSectionI,
+ UnitSectionTableCtx,
+} from "@macrostrat-web/column-builder/src";
+import {
+ AsyncActions,
+ Actions,
+ columnReducer,
+ SyncActions,
+ useUnitSectionTableActions,
+} from "../column";
+import { DragDropContext, Droppable } from "react-beautiful-dnd";
+import { DropResult, DroppableProvided } from "react-beautiful-dnd";
+import { ColumnPageBtnMenu } from "./helpers";
+import { SectionTable } from "./section";
+import { NewSectionBtn } from "../unit/minimal-unit-editor";
+
+import h from "../comp.module.sass";
+
+interface SectionUnitTableProps {
+ onDragEnd: (r: DropResult) => void;
+}
+
+function SectionsDropContainer(props: SectionUnitTableProps) {
+ const { onDragEnd } = props;
+ const { state, runAction } = useUnitSectionContext();
+ const { sections, moved } = state;
+
+ return h("div", [
+ h(DragDropContext, { onDragEnd }, [
+ h(
+ Droppable,
+ {
+ droppableId: "unit-section-tables",
+ type: "SECTIONS",
+ isCombineEnabled: true,
+ },
+ [
+ (provided: DroppableProvided) => {
+ return h(
+ "div",
+ { ...provided.droppableProps, ref: provided.innerRef },
+ [
+ h(NewSectionBtn, {
+ index: 0,
+ addNewSection: (i: number) =>
+ runAction({
+ type: "create-new-section",
+ index: i,
+ col_id: state.col_id,
+ }),
+ }),
+ sections.map((section, i) => {
+ const addUnitAt = (e: UnitsView, n: number) => {
+ runAction({
+ type: "add-unit-at",
+ unit_index: n,
+ unit: e,
+ section_index: i,
+ });
+ };
+
+ const editUnitAt = (unit_index: number) => {
+ runAction({
+ type: "edit-unit-at",
+ section_index: i,
+ unit_index,
+ });
+ };
+
+ return h(React.Fragment, { key: i }, [
+ h(SectionTable, {
+ addUnitAt,
+ section,
+ index: i,
+ drag: state.drag,
+ editUnitAt,
+ moved,
+ }),
+ h(NewSectionBtn, {
+ index: i + 1,
+ addNewSection: (i: number) =>
+ runAction({
+ type: "create-new-section",
+ index: i,
+ col_id: state.col_id,
+ }),
+ }),
+ ]);
+ }),
+ provided.placeholder,
+ ]
+ );
+ },
+ ]
+ ),
+ ]),
+ ]);
+}
+
+const UnitSectionTableContext = createContext({
+ state: {
+ col_id: 0,
+ sections: [],
+ originalSections: [],
+ mergeIds: [],
+ moved: {},
+ drag: false,
+ unitsView: true,
+ edit: {
+ open: false,
+ section_index: 0,
+ unit_index: 0,
+ },
+ unitsMovedToNewSections: [],
+ },
+ runAction: async (action: SyncActions | AsyncActions) => {},
+});
+
+const useUnitSectionContext = () => useContext(UnitSectionTableContext);
+
+interface UnitSectionTableParams {
+ col_id: number;
+ colSections: ColSectionI[];
+ sections: { [section_id: number | string]: UnitsView[] }[];
+}
+
+function UnitSectionTable(props: UnitSectionTableParams) {
+ const { colSections, sections, col_id } = props;
+
+ const initialState: ColumnStateI = {
+ col_id,
+ sections,
+ originalSections: sections,
+ mergeIds: [],
+ moved: {},
+ drag: false,
+ unitsView: true,
+ edit: {
+ open: false,
+ section_index: 0,
+ unit_index: 0,
+ },
+ unitsMovedToNewSections: [],
+ };
+
+ const [state, dispatch] = useReducer(columnReducer, initialState);
+ const runAction = useUnitSectionTableActions(dispatch);
+
+ const onChange = (id: number) => {
+ dispatch({ type: "set-merge-ids", id });
+ };
+
+ const onDragEnd = (r: DropResult) => {
+ if (r.type == "SECTIONS") {
+ dispatch({ type: "dropped-section", result: r });
+ } else {
+ dispatch({ type: "dropped-unit", result: r });
+ }
+ };
+
+ const onReorderCancel = () => {
+ runAction({ type: "cancel-reorder" });
+ };
+
+ const onReorderSave = () => {
+ runAction({ type: "save-reorder", sections: state.sections });
+ };
+
+ return h(UnitSectionTableContext.Provider, { value: { state, runAction } }, [
+ h("div", [
+ h(ColumnPageBtnMenu, {
+ state: {
+ unitsView: state.unitsView,
+ drag: state.drag,
+ mergeIds: state.mergeIds,
+ moved: state.moved,
+ },
+ toggleUnitsView: () => runAction({ type: "toggle-units-view" }),
+ toggleDrag: () => {
+ runAction({ type: "toggle-drag" });
+ },
+ divideSection: () => {},
+ mergeSections: () => {},
+ onCancel: onReorderCancel,
+ onSave: onReorderSave,
+ noSectionView: colSections.length == 0,
+ }),
+ h.if(colSections.length > 0 && !state.unitsView)(ColSectionsTable, {
+ colSections,
+ onChange,
+ }),
+ h.if(state.unitsView)("div.unit-section-container", [
+ h("div.unit-section-tables", [
+ h(SectionsDropContainer, {
+ onDragEnd,
+ }),
+ ]),
+ ]),
+ ]),
+ ]);
+}
+
+export { UnitSectionTable, useUnitSectionContext, UnitSectionTableContext };
diff --git a/packages/column-builder/src/components/unit-section-table/unit.ts b/packages/column-builder/src/components/unit-section-table/unit.ts
new file mode 100644
index 00000000..8be4d57a
--- /dev/null
+++ b/packages/column-builder/src/components/unit-section-table/unit.ts
@@ -0,0 +1,266 @@
+import React from "react";
+import { Link } from "~/components";
+import { hyperStyled } from "@macrostrat/hyper";
+import {
+ UnitsView,
+ convertColorNameToHex,
+ IntervalDataI,
+ IntervalSuggest,
+} from "@macrostrat-web/column-builder/src";
+import {
+ EnvTags,
+ LithTags,
+ UnitEditorProps,
+ UnitRowThicknessEditor,
+ UnitRowStratNameEditor,
+ InformalUnitName,
+} from "../unit/common-editing";
+import { MinEditorCard } from "../unit/minimal-unit-editor";
+import { DraggableRow } from "../table";
+import { UnitRowContextMenu, AddBtnBetweenRows } from "./helpers";
+import { useUnitSectionContext } from "@macrostrat-web/column-builder/src";
+import styles from "../comp.module.sass";
+import { Button, Dialog, TextArea } from "@blueprintjs/core";
+import { ModelEditor, useModelEditor } from "@macrostrat/ui-components";
+import { SubmitButton } from "../buttons";
+
+const h = hyperStyled(styles);
+
+function UnitRowIntervalEditor() {
+ const {
+ model: unit,
+ actions,
+ isEditing,
+ }: { model: UnitsView; actions: any; isEditing: boolean } = useModelEditor();
+
+ const changeInterval = (interval: IntervalDataI, lo: boolean) => {
+ const { id, interval_name } = interval.data;
+
+ let intervalField = "fo";
+ let intervalName = "name_fo";
+ if (lo) {
+ intervalField = "lo";
+ intervalName = "name_lo";
+ }
+ actions.updateState({
+ model: {
+ [intervalField]: { $set: id },
+ [intervalName]: { $set: interval_name },
+ },
+ });
+ };
+
+ const onChangeLo = (interval: IntervalDataI) => {
+ changeInterval(interval, true);
+ };
+
+ const onChangeFo = (interval: IntervalDataI) => {
+ changeInterval(interval, false);
+ };
+
+ return h(React.Fragment, [
+ h.if(!isEditing)("div", [
+ unit.name_fo !== unit.name_lo
+ ? `${unit.name_fo} - ${unit.name_lo}`
+ : unit.name_lo,
+ ]),
+ h.if(isEditing)("div", { style: { display: "flex" } }, [
+ h(IntervalSuggest, {
+ placeholder: "Bottom interval",
+ initialSelected: {
+ value: unit?.name_fo,
+ data: { id: unit?.fo || 0, interval_name: unit?.name_fo },
+ },
+ onChange: onChangeFo,
+ }),
+ "-",
+ h(IntervalSuggest, {
+ placeholder: "Top Interval",
+ initialSelected: {
+ value: unit?.name_lo,
+ data: {
+ id: unit?.lo || 0,
+ interval_name: unit?.name_lo,
+ },
+ },
+ onChange: onChangeLo,
+ }),
+ ]),
+ ]);
+}
+
+function UnitRowNotes() {
+ const {
+ model: unit,
+ actions,
+ isEditing,
+ }: { model: UnitsView; actions: any; isEditing: boolean } = useModelEditor();
+
+ const updateUnit = (field: string, value: string) => {
+ actions.updateState({
+ model: {
+ [field]: { $set: value },
+ },
+ });
+ };
+
+ return h(React.Fragment, [
+ h.if(isEditing)(TextArea, {
+ style: { maxWidth: "100px" },
+ value: unit.notes ?? "",
+ onChange: (e) => updateUnit("notes", e.target.value),
+ }),
+ h.if(!isEditing)("p.ellipse", [unit.notes]),
+ ]);
+}
+
+function UnitCellGroup(props: { unit: UnitsView; onCancel: () => void }) {
+ const { unit } = props;
+ const {
+ isEditing,
+ actions,
+ }: { isEditing: boolean; actions: { persistChanges: any } } =
+ useModelEditor();
+
+ const backgroundColor = convertColorNameToHex(unit.color) + "80";
+ return h(React.Fragment, [
+ h("td", [
+ h(Link, { href: `../unit/${unit.id}/edit` }, [h("a", [unit.id])]),
+ ]),
+ h("td", { style: { background: backgroundColor } }, [h(InformalUnitName)]),
+ h("td", { style: { background: backgroundColor } }, [
+ h(UnitRowStratNameEditor),
+ ]),
+ h("td", [h(LithTags, { large: false })]),
+ h("td", [h(EnvTags, { large: false })]),
+ h("td", [h(UnitRowIntervalEditor)]),
+ h("td", [h(UnitRowThicknessEditor)]),
+ h("td", [h(UnitRowNotes)]),
+ h.if(isEditing)("td", [
+ h(Button, { intent: "danger", onClick: props.onCancel }, ["Cancel"]),
+ h(SubmitButton),
+ ]),
+ ]);
+}
+
+interface UnitRowProps {
+ unit: UnitsView;
+ drag: boolean;
+ unit_index: number;
+ section_index: number;
+ colSpan: number;
+ isMoved: boolean;
+ inRowEditing: boolean;
+ copyUnitUp: () => void;
+ copyUnitDown: () => void;
+ addEmptyUnit: (unit_index: number) => void;
+ editUnitAt: (unit_index: number) => void;
+}
+
+function UnitRow(props: UnitRowProps) {
+ const { state, runAction } = useUnitSectionContext();
+
+ const persistChanges = (e: UnitsView, c: Partial) => {
+ runAction({
+ type: "save-unit-at",
+ unit: e,
+ changeSet: c,
+ og_unit: props.unit,
+ unit_index: props.unit_index,
+ section_index: props.section_index,
+ sections: state.sections,
+ });
+ };
+
+ const onCancel = () => {
+ runAction({
+ type: "cancel-editing",
+ section_index: props.section_index,
+ unit_index: props.unit_index,
+ });
+ };
+
+ return h(React.Fragment, { key: props.unit.id }, [
+ h.if(props.unit_index == 0)(AddBtnBetweenRows, {
+ colSpan: props.colSpan,
+ onClick: (e) => {
+ e.stopPropagation();
+ props.addEmptyUnit(props.unit_index);
+ },
+ }),
+ h(
+ DraggableRow,
+ {
+ key: props.unit.id,
+ index: props.unit_index,
+ drag: props.drag,
+ draggableId: props.unit.strat_name + props.unit.id.toString(),
+ href: undefined,
+ isMoved: props.isMoved,
+ onDoubleClick: () => {
+ runAction({
+ type: "edit-unit-at",
+ unit_index: props.unit_index,
+ section_index: props.section_index,
+ });
+ },
+ },
+ [
+ h(
+ ModelEditor,
+ {
+ isEditing: props.inRowEditing,
+ //@ts-ignore
+ persistChanges,
+ model: { ...props.unit },
+ },
+ [
+ h(UnitCellGroup, {
+ unit: props.unit,
+ key: props.unit_index,
+ onCancel,
+ }),
+ ]
+ ),
+ h.if(!props.inRowEditing)("td", { width: "0%" }, [
+ h(UnitRowContextMenu, {
+ unit: props.unit,
+ unit_index: props.unit_index,
+ section_index: props.section_index,
+ copyUnitUp: props.copyUnitUp,
+ copyUnitDown: props.copyUnitDown,
+ addEmptyUnit: props.addEmptyUnit,
+ editUnitAt: props.editUnitAt,
+ }),
+ ]),
+ ]
+ ),
+
+ h(AddBtnBetweenRows, {
+ colSpan: props.colSpan,
+ onClick: (e) => {
+ e.stopPropagation();
+ props.addEmptyUnit(props.unit_index + 1);
+ },
+ }),
+ ]);
+}
+
+function UnitRowEditorModal(
+ props: UnitEditorProps & {
+ onCancel: () => void;
+ title: string;
+ open: boolean;
+ }
+) {
+ return h(Dialog, { isOpen: props.open, style: { width: "50%" } }, [
+ h(MinEditorCard, {
+ title: props.title,
+ persistChanges: props.persistChanges,
+ model: props.model,
+ onCancel: props.onCancel,
+ }),
+ ]);
+}
+
+export { UnitRow, UnitRowEditorModal };
diff --git a/packages/column-builder/src/components/unit/color.ts b/packages/column-builder/src/components/unit/color.ts
new file mode 100644
index 00000000..5a9f31cd
--- /dev/null
+++ b/packages/column-builder/src/components/unit/color.ts
@@ -0,0 +1,33 @@
+import pkg from "react-color";
+import { Popover2 } from "@blueprintjs/popover2";
+import h from "../comp.module.sass";
+
+interface ColorProps {
+ color: string;
+ onChange: (hex: string) => void;
+}
+
+function ColorBlock(props: ColorProps) {
+ const onChange = (color: { hex: string }) => {
+ const { hex } = color;
+ props.onChange(hex);
+ };
+ const color = props.color ?? "black";
+
+ console.log(pkg);
+
+ return h("div", [
+ h(
+ Popover2,
+ {
+ content: h(pkg, {
+ onChange: onChange,
+ color,
+ }),
+ },
+ h("div.color-block", { style: { backgroundColor: color } })
+ ),
+ ]);
+}
+
+export { ColorBlock };
diff --git a/packages/column-builder/src/components/unit/common-editing.ts b/packages/column-builder/src/components/unit/common-editing.ts
new file mode 100644
index 00000000..e94dcc15
--- /dev/null
+++ b/packages/column-builder/src/components/unit/common-editing.ts
@@ -0,0 +1,226 @@
+import React from "react";
+import { hyperStyled } from "@macrostrat/hyper";
+import {
+ UnitsView,
+ LithUnit,
+ Lith,
+ EnvironUnit,
+ TagContainerCell,
+} from "../../index";
+import { InputGroup, NumericInput, FormGroup } from "@blueprintjs/core";
+import {
+ useModelEditor,
+ //@ts-ignore
+} from "@macrostrat/ui-components";
+import styles from "../comp.module.sass";
+import { EnvTagsAdd } from "..";
+import { UnitStratNameModalEditor } from "..";
+import { LithContainer } from "../lith";
+const h = hyperStyled(styles);
+
+export interface UnitEditorProps {
+ persistChanges: (e: UnitsView, c: Partial) => void;
+ model: UnitsView | {};
+}
+
+export function EnvTags(props: { large: boolean }) {
+ const { large = true } = props;
+ const {
+ model: unit,
+ isEditing,
+ actions,
+ }: {
+ model: UnitsView;
+ isEditing: boolean;
+ actions: any;
+ } = useModelEditor();
+ const { environ_unit: envs } = unit;
+
+ const tagData =
+ envs?.map((env) => {
+ return {
+ id: env.id,
+ color: env.environ_color,
+ name: env.environ,
+ description: env.environ_class,
+ };
+ }) ?? [];
+
+ const onClickDelete = (id: number) => {
+ const filteredEnvs = [...(envs ?? [])].filter((l) => l.id != id);
+ actions.updateState({
+ model: { environ_unit: { $set: filteredEnvs } },
+ });
+ };
+
+ const onClick = (env: Partial) => {
+ actions.updateState({
+ model: { environ_unit: { $push: [env] } },
+ });
+ };
+
+ return h("div.tag-container", [
+ h.if(tagData.length == 0 && isEditing)("div", ["Add environments"]),
+ h(TagContainerCell, { data: tagData, onClickDelete, isEditing, large }),
+ h.if(isEditing)(EnvTagsAdd, { onClick }),
+ ]);
+}
+
+export function LithTags(props: { large?: boolean }) {
+ const { large = true } = props;
+ const {
+ model: unit,
+ isEditing,
+ actions,
+ }: {
+ model: UnitsView;
+ isEditing: boolean;
+ actions: any;
+ } = useModelEditor();
+ const { lith_unit: liths = [] } = unit;
+
+ const onClickDelete = (lith: LithUnit) => {
+ const filteredLiths = [...(liths ?? [])].filter((l) => l.id != lith.id);
+ actions.updateState({
+ model: { lith_unit: { $set: filteredLiths } },
+ });
+ };
+
+ const onAdd = (lith: Lith) => {
+ lith.dom = "sub";
+ actions.updateState({ model: { lith_unit: { $push: [lith] } } });
+ };
+
+ const onSwitchProp = (id: number) => {
+ const liths_ = JSON.parse(JSON.stringify(liths));
+ const index = liths_.findIndex((lith: LithUnit) => lith.id == id);
+ const arrayOfDeleted = liths_.splice(index, 1);
+ const lith: LithUnit = arrayOfDeleted[0];
+ if (lith.dom == "dom") {
+ lith.dom = "sub";
+ } else lith.dom = "dom";
+ liths_.splice(index, 0, lith);
+ actions.updateState({ model: { lith_unit: { $set: liths_ } } });
+ };
+
+ return h("div", [
+ h.if(liths.length == 0 && isEditing)("div", ["Add lithologies"]),
+ h(LithContainer, {
+ large,
+ liths,
+ onAdd,
+ onSwitchProp,
+ onRemove: isEditing ? onClickDelete : undefined,
+ isEditing,
+ }),
+ ]);
+}
+
+export function UnitThickness(props: {
+ field: string;
+ defaultValue: number | undefined;
+ placeholder: string;
+ small?: boolean;
+}) {
+ const { model: unit, actions }: { model: UnitsView; actions: any } =
+ useModelEditor();
+
+ const update = (field: string, e: any) => {
+ actions.updateState({ model: { [field]: { $set: e } } });
+ };
+ const width = props.small ?? false ? "60px" : undefined;
+
+ return h(NumericInput, {
+ style: { width },
+ onValueChange: (e) => update(props.field, e),
+ defaultValue: props.defaultValue,
+ placeholder: props.placeholder,
+ buttonPosition: props.small ?? false ? "none" : undefined,
+ });
+}
+
+export function UnitRowThicknessEditor() {
+ const {
+ model: unit,
+ actions,
+ isEditing,
+ }: { model: UnitsView; actions: any; isEditing: boolean } = useModelEditor();
+
+ return h(React.Fragment, [
+ h.if(!isEditing)("div", [
+ unit.min_thick != unit.max_thick
+ ? `${unit.min_thick} - ${unit.max_thick}`
+ : unit.min_thick,
+ ]),
+ h.if(isEditing)("div", { style: { display: "flex" } }, [
+ h(UnitThickness, {
+ field: "min_thick",
+ placeholder: "min thickness",
+ defaultValue: unit?.min_thick,
+ small: true,
+ }),
+ " - ",
+ h(UnitThickness, {
+ field: "max_thick",
+ placeholder: "max thickness",
+ defaultValue: unit?.max_thick,
+ small: true,
+ }),
+ ]),
+ ]);
+}
+
+export function InformalUnitName() {
+ const { model: unit, actions, isEditing } = useModelEditor();
+
+ const updateUnitName = (e: string) => {
+ actions.updateState({
+ model: { strat_name: { $set: e } },
+ });
+ };
+
+ return h("div", [
+ h.if(!isEditing)("p", [unit.strat_name]),
+ h.if(isEditing)(InputGroup, {
+ placeholder: "Informal Unit Name",
+ style: { width: "120px" },
+ value: unit.strat_name || undefined,
+ onChange: (e) => updateUnitName(e.target.value),
+ }),
+ ]);
+}
+
+export function UnitRowStratNameEditor() {
+ const {
+ model: unit,
+ actions,
+ isEditing,
+ }: { model: UnitsView; actions: any; isEditing: boolean } = useModelEditor();
+
+ const nameText = unit.strat_names.length
+ ? unit.strat_names.map((sn) => `${sn.strat_name} ${sn.rank}`).join(", ")
+ : "No stratigraphic name";
+
+ return h("div", [nameText, h.if(isEditing)(UnitStratNameModalEditor)]);
+}
+
+export function FormalStratName() {
+ /** TODO: this is invalid */
+ const { model: unit, actions, isEditing } = useModelEditor();
+
+ const updateUnitName = (e: string) => {
+ actions.updateState({
+ model: { strat_name: { $set: e } },
+ });
+ };
+
+ return h("div", [
+ h.if(!isEditing)("p", [unit.strat_name]),
+ h.if(isEditing)(InputGroup, {
+ placeholder: "Informal Unit Name",
+ style: { width: "120px" },
+ value: unit.strat_name || undefined,
+ onChange: (e) => updateUnitName(e.target.value),
+ }),
+ ]);
+}
diff --git a/packages/column-builder/src/components/unit/edit-helpers.ts b/packages/column-builder/src/components/unit/edit-helpers.ts
new file mode 100644
index 00000000..6b3c3559
--- /dev/null
+++ b/packages/column-builder/src/components/unit/edit-helpers.ts
@@ -0,0 +1,204 @@
+import { PostgrestResponse } from "@supabase/postgrest-js";
+import pg, {
+ UnitsView,
+ tableUpdate,
+ StratNameI,
+ EnvironUnit,
+ LithUnit,
+} from "../..";
+import { detectDeletionsAndAdditions } from "../helpers";
+
+async function handleLithCollection(
+ collection: LithUnit[],
+ changes: LithUnit[],
+ unit_id: number
+) {
+ // find deletions, and additions
+ // for rest, set the prop where the id is already set
+ const { deletions, additions } = detectDeletionsAndAdditions(
+ collection,
+ changes
+ );
+
+ changes.map(async (change) => {
+ if (additions.has(change.id)) {
+ // this is completely new! Insert!
+ const { data, error } = await pg
+ .from("unit_liths")
+ .insert([{ unit_id: unit_id, lith_id: change.id, dom: change.dom }]);
+ } else {
+ // already exists! update!
+ const { data, error } = await pg
+ .from("unit_liths")
+ .update({ dom: change.dom })
+ .match({ unit_id: unit_id, lith_id: change.id });
+ }
+ });
+ deletions.forEach(async (id) => {
+ // delete from the table where id
+ const { data, error } = await pg
+ .from("unit_liths")
+ .delete()
+ .match({ unit_id: unit_id, lith_id: id });
+ });
+}
+
+async function handleEnvironCollection(
+ collection: EnvironUnit[],
+ changes: EnvironUnit[],
+ unit_id: number
+) {
+ const { deletions, additions } = detectDeletionsAndAdditions(
+ collection,
+ changes
+ );
+
+ deletions.forEach(async (id) => {
+ const { data, error } = await pg
+ .from("unit_environs")
+ .delete()
+ .match({ unit_id: unit_id, environ_id: id });
+ });
+ const inserts = [];
+ additions.forEach((id) => {
+ inserts.push({ unit_id, environ_id: id });
+ });
+ const { data, error } = await pg.from("unit_environs").insert(inserts);
+}
+
+async function handleStratNameCollection(
+ collection: StratNameI[],
+ changes: StratNameI[],
+ unit_id: number
+) {
+ const { deletions, additions } = detectDeletionsAndAdditions(
+ collection,
+ changes
+ );
+ deletions.forEach(async (id) => {
+ const { data, error } = await pg
+ .from("unit_strat_names")
+ .delete()
+ .match({ unit_id: unit_id, strat_name_id: id });
+ });
+ const inserts = [];
+ additions.forEach((id) => {
+ inserts.push({ unit_id, strat_name_id: id });
+ });
+ const { data, error } = await pg.from("unit_strat_names").insert(inserts);
+}
+
+const persistable_fields = new Set([
+ "strat_name",
+ "lo",
+ "fo",
+ "min_thick",
+ "max_thick",
+ "notes",
+ "color",
+ "section_id",
+ "col_id",
+]);
+
+async function updateExistingUnit(
+ unit: UnitsView,
+ updatedModel: UnitsView,
+ changeSet: Partial
+) {
+ if (changeSet) {
+ const updates = Object.keys(changeSet)
+ .filter((key) => persistable_fields.has(key))
+ .reduce((cur, key) => {
+ return Object.assign(cur, { [key]: changeSet[key] });
+ }, {});
+ const { data, error } = await tableUpdate("units", {
+ changes: updates,
+ id: unit.id,
+ });
+ }
+}
+
+async function insertNewUnit(unit: UnitsView) {
+ const inserts = Object.keys(unit)
+ .filter((key) => persistable_fields.has(key))
+ .reduce((cur, key) => {
+ return Object.assign(cur, { [key]: unit[key] });
+ }, {});
+ const { data, error }: PostgrestResponse = await pg
+ .from("units")
+ .insert([inserts]);
+ return data[0];
+}
+
+/*
+Function to handle changes to Units! This is a bit complicated because of the
+one to many relationship between a unit and environments, lithologies, and strat_names.
+*/
+export async function persistUnitChanges(
+ unit: UnitsView,
+ updatedModel: UnitsView,
+ changeSet: Partial
+) {
+ console.log(unit, updatedModel, changeSet);
+
+ await updateExistingUnit(unit, updatedModel, changeSet);
+
+ if (changeSet?.environ_unit) {
+ await handleEnvironCollection(
+ unit.environ_unit ?? [],
+ changeSet.environ_unit,
+ unit.id
+ );
+ }
+ if (changeSet?.lith_unit) {
+ await handleLithCollection(
+ unit.lith_unit ?? [],
+ changeSet.lith_unit,
+ unit.id
+ );
+ }
+ if (changeSet?.strat_names) {
+ await handleStratNameCollection(
+ unit.strat_names ?? [],
+ changeSet.strat_names,
+ unit.id
+ );
+ }
+ return updatedModel;
+}
+
+export async function persistNewUnit(
+ unit: UnitsView,
+ updatedModel: UnitsView,
+ changeSet: Partial
+) {
+ const { id } = await insertNewUnit(updatedModel);
+ unit.id = id;
+ updatedModel.id = id;
+ console.log(updatedModel);
+
+ if (updatedModel?.environ_unit) {
+ updatedModel.environ_unit.map(async (env) => {
+ const { data, error } = await pg
+ .from("unit_environs")
+ .insert([{ unit_id: updatedModel.id, environ_id: env.id }]);
+ });
+ }
+ if (updatedModel?.lith_unit) {
+ updatedModel.lith_unit.map(async (lith) => {
+ const { data, error } = await pg
+ .from("unit_liths")
+ .insert([
+ { unit_id: updatedModel.id, lith_id: lith.id, dom: lith.dom },
+ ]);
+ });
+ }
+ if (updatedModel?.strat_names) {
+ updatedModel.strat_names.map(async (strat_name) => {
+ const { data, error } = await pg
+ .from("unit_strat_names")
+ .insert([{ unit_id: updatedModel.id, strat_name_id: strat_name.id }]);
+ });
+ }
+ return updatedModel;
+}
diff --git a/packages/column-builder/src/components/unit/index.ts b/packages/column-builder/src/components/unit/index.ts
new file mode 100644
index 00000000..0499ce7e
--- /dev/null
+++ b/packages/column-builder/src/components/unit/index.ts
@@ -0,0 +1,6 @@
+export * from "./common-editing";
+export * from "./minimal-unit-editor";
+export * from "./color";
+export * from "./interval-suggest";
+export * from "./unit-editor";
+export * from "../table";
diff --git a/packages/column-builder/src/components/unit/interval-suggest.ts b/packages/column-builder/src/components/unit/interval-suggest.ts
new file mode 100644
index 00000000..bdc07e7c
--- /dev/null
+++ b/packages/column-builder/src/components/unit/interval-suggest.ts
@@ -0,0 +1,135 @@
+import React, { useState, useEffect } from "react";
+import { hyperStyled } from "@macrostrat/hyper";
+import { Spinner, MenuItem } from "@blueprintjs/core";
+import { IntervalI } from "../../types";
+import pg from "../../db";
+import styles from "../comp.module.sass";
+import { ItemSuggest } from "../suggest";
+import { FeatureCell } from "../table";
+import { ItemRenderer } from "@blueprintjs/select";
+
+const h = hyperStyled(styles);
+
+interface IntervalProps {
+ onChange: (e: IntervalDataI) => void;
+ initialSelected?: IntervalDataI;
+ onQueryChange?: (e: string) => void;
+ placeholder?: string;
+}
+
+export interface IntervalDataI {
+ value: string;
+ data: IntervalI | Partial;
+}
+
+interface IntervalRowProps extends IntervalProps {
+ age_bottom?: number;
+ age_top?: number;
+ bottom: boolean;
+}
+
+const intervalItemRenderer: ItemRenderer = (
+ item: IntervalDataI,
+ { modifiers, handleClick }
+) => {
+ const {
+ interval_name,
+ age_bottom,
+ age_top,
+ interval_color,
+ interval_type,
+ id,
+ } = item.data;
+
+ const style =
+ modifiers?.active ?? false
+ ? {
+ marginBottom: "2px",
+ }
+ : {
+ backgroundColor: interval_color + "40", // add opaquness
+ marginBottom: "2px",
+ };
+
+ return h(MenuItem, {
+ key: id,
+ text: h("div.interval-row", [
+ `${interval_name} (${interval_type})`,
+ h("i", [`${age_bottom}-${age_top} Ma`]),
+ ]),
+ onClick: handleClick,
+ active: modifiers.active,
+ style,
+ });
+};
+
+function IntervalSuggest(props: IntervalProps) {
+ const [intervals, setIntervals] = useState([]);
+ const getIntervals = async (query: string) => {
+ if (query.length > 2) {
+ const { data, error } = await pg
+ .from("intervals")
+ .select()
+ .like("interval_name", `%${query}%`)
+ .order("age_bottom")
+ .limit(200);
+ const d = data?.map((d: IntervalI) => {
+ return { value: d.interval_name, data: d };
+ });
+ setIntervals(d);
+ } else {
+ const { data, error } = await pg
+ .from("intervals")
+ .select()
+ .order("age_bottom")
+ .limit(50);
+ const d = data?.map((d: IntervalI) => {
+ return { value: d.interval_name, data: d };
+ });
+ setIntervals(d);
+ }
+ };
+
+ useEffect(() => {
+ const getData = async () => {
+ const { data, error } = await pg
+ .from("intervals")
+ .select()
+ .order("age_bottom")
+ .limit(50);
+ const d = data?.map((d: IntervalI) => {
+ return { value: d.interval_name, data: d };
+ });
+ setIntervals(d);
+ };
+ getData();
+ }, []);
+
+ return h(React.Fragment, [
+ h.if(intervals == undefined)(Spinner),
+ h.if(intervals != undefined)(ItemSuggest, {
+ items: intervals,
+ onChange: props.onChange,
+ onQueryChange: getIntervals,
+ initialSelected: props.initialSelected,
+ itemRenderer: intervalItemRenderer,
+ placeholder: props.placeholder,
+ }),
+ ]);
+}
+
+function IntervalRow(props: IntervalRowProps) {
+ const label: string = !props.bottom ? "Top (LO): " : "Bottom (FO): ";
+
+ const ageLabel: string = props.bottom ? "Age Bottom: " : "Age Top: ";
+
+ return h(React.Fragment, [
+ h(FeatureCell, { text: label }, [h(IntervalSuggest, { ...props })]),
+ h(FeatureCell, { text: ageLabel }, [
+ props.age_bottom || props.age_top,
+ " ma",
+ ]),
+ ]);
+}
+
+export { IntervalRow, IntervalSuggest };
diff --git a/packages/column-builder/src/components/unit/minimal-unit-editor.ts b/packages/column-builder/src/components/unit/minimal-unit-editor.ts
new file mode 100644
index 00000000..85d737f7
--- /dev/null
+++ b/packages/column-builder/src/components/unit/minimal-unit-editor.ts
@@ -0,0 +1,263 @@
+import { hyperStyled } from "@macrostrat/hyper";
+import {
+ IntervalDataI,
+ Table,
+ IntervalSuggest,
+} from "@macrostrat-web/column-builder/src";
+import { Button, TextArea, Card, Collapse, Dialog } from "@blueprintjs/core";
+import { ModelEditor, useModelEditor } from "@macrostrat/ui-components";
+import styles from "../comp.module.sass";
+import { SubmitButton } from "..";
+import {
+ UnitThickness,
+ UnitEditorProps,
+ InformalUnitName,
+ FormalStratName,
+ EnvTags,
+ LithTags,
+} from "./common-editing";
+import { useState } from "react";
+import { AddButton } from "../buttons";
+import { UnitsView } from "~/types";
+const h = hyperStyled(styles);
+
+function UnitEditCancelAlert(props: {
+ onCancel: () => void;
+ onClose: () => void;
+ open: boolean;
+}) {
+ return h(
+ Dialog,
+ {
+ isOpen: props.open,
+ icon: "warning-sign",
+ title: "Unsaved Changes",
+ },
+ [
+ h(
+ "div",
+ {
+ style: { margin: "10px" },
+ },
+ [
+ h("p", [
+ "There are unsaved changes, are you sure you want to leave?",
+ ]),
+ h("div", [
+ h(Button, { intent: "danger", onClick: props.onCancel }, [
+ "Don't Save",
+ ]),
+ h(Button, { intent: "primary", onClick: props.onClose }, [
+ "Back to Editing",
+ ]),
+ ]),
+ ]
+ ),
+ ]
+ );
+}
+
+function UnitEdit(props: { onCancel: () => void }) {
+ const [open, setOpen] = useState(false);
+ const { model, hasChanges, actions, ...rest } = useModelEditor();
+ const { unit }: { unit: UnitsView } = model;
+
+ const updateUnit = (field: string, e: any) => {
+ actions.updateState({ model: { unit: { [field]: { $set: e } } } });
+ };
+
+ const onChangeLo = (interval: IntervalDataI) => {
+ const { data } = interval;
+ const { id: lo, interval_name: name_lo } = data;
+ actions.updateState({
+ model: {
+ unit: {
+ lo: { $set: lo },
+ name_lo: { $set: name_lo },
+ },
+ },
+ });
+ };
+
+ const onChangeFo = (interval: IntervalDataI) => {
+ const { data } = interval;
+ const { id: fo, interval_name: name_fo } = data;
+ actions.updateState({
+ model: {
+ unit: {
+ fo: { $set: fo },
+ name_fo: { $set: name_fo },
+ },
+ },
+ });
+ };
+
+ const onCancelBtnClick = () => {
+ if (hasChanges()) {
+ setOpen(true);
+ } else {
+ props.onCancel();
+ }
+ };
+
+ return h("div", [
+ h(UnitEditCancelAlert, {
+ open,
+ onCancel: props.onCancel,
+ onClose: () => setOpen(false),
+ }),
+ h(Table, { interactive: false }, [
+ h("tr", [
+ h("td", [
+ h("div.margin-bottom-spacing", [h(InformalUnitName)]),
+ h(FormalStratName),
+ ]),
+ h("td", [
+ h("div.margin-bottom-spacing", [h(LithTags, { large: false })]),
+ h(EnvTags, { large: false }),
+ ]),
+
+ h("td", [
+ h("div.margin-bottom-spacing", [
+ h(UnitThickness, {
+ field: "min_thick",
+ placeholder: "min thickness",
+ defaultValue: unit?.min_thick || undefined,
+ }),
+ ]),
+ h(UnitThickness, {
+ field: "max_thick",
+ placeholder: "max thickness",
+ defaultValue: unit?.max_thick || undefined,
+ }),
+ ]),
+ ]),
+ h("tr", [
+ h("td.interval-cell-min-editor", [
+ h(IntervalSuggest, {
+ placeholder: "Top interval",
+ initialSelected: {
+ value: unit?.name_lo,
+ data: { id: unit?.lo || 0, interval_name: unit?.name_lo },
+ },
+ onChange: onChangeLo,
+ }),
+ h(IntervalSuggest, {
+ placeholder: "Bottom Interval",
+ initialSelected: {
+ value: unit?.name_fo,
+ data: {
+ id: unit?.fo || 0,
+ interval_name: unit?.name_fo,
+ },
+ },
+ onChange: onChangeFo,
+ }),
+ ]),
+ h("td", { colSpan: 2 }, [
+ h("div", { style: { display: "flex", flexDirection: "column" } }, [
+ h(TextArea, {
+ value: unit.notes,
+ onChange: (e) => updateUnit("notes", e.target.value),
+ }),
+ h("div", { style: { marginTop: "10px" } }, [
+ h(SubmitButton),
+ h(Button, { intent: "danger", onClick: onCancelBtnClick }, [
+ "Cancel",
+ ]),
+ ]),
+ ]),
+ ]),
+ ]),
+ ]),
+ ]);
+}
+
+interface MinUnitEditorProps extends UnitEditorProps {
+ onCancel: () => void;
+}
+
+function MinUnitEditor(props: MinUnitEditorProps) {
+ return h(
+ ModelEditor,
+ {
+ model: props.model,
+ //@ts-ignore
+ persistChanges: props.persistChanges,
+ canEdit: true,
+ isEditing: true,
+ },
+ [h(UnitEdit, { onCancel: props.onCancel })]
+ );
+}
+
+interface ToggleI extends UnitEditorProps {
+ btnText: string;
+ btnPosition: "top" | "bottom";
+}
+
+function MinEditorToggle(props: ToggleI) {
+ const [add, setAdd] = useState(false);
+
+ const model = {
+ unit: { new_section: false, lith_unit: [], environ_unit: [] },
+ };
+
+ const persistChanges = (e: UnitsView, c: Partial) => {
+ props.persistChanges(e, c);
+ setAdd(false);
+ };
+
+ const onCancel = () => {
+ setAdd(false);
+ };
+
+ return h("div", [
+ h.if(props.btnPosition == "top")(
+ AddButton,
+ { onClick: () => setAdd(!add) },
+ [props.btnText]
+ ),
+ h(Collapse, { isOpen: add }, [
+ h(MinEditorCard, {
+ persistChanges,
+ onCancel,
+ model,
+ title: props.btnText,
+ }),
+ ]),
+ h.if(props.btnPosition == "bottom")(
+ AddButton,
+ { onClick: () => setAdd(!add) },
+ [props.btnText]
+ ),
+ ]);
+}
+
+function NewSectionBtn(props: {
+ addNewSection: (i: number) => void;
+ index: number;
+}) {
+ return h(AddButton, { onClick: () => props.addNewSection(props.index) }, [
+ "Add Section",
+ ]);
+}
+
+function MinEditorCard(
+ props: UnitEditorProps & {
+ onCancel: () => void;
+ title?: string;
+ }
+) {
+ const { persistChanges, model, onCancel, title } = props;
+ return h(Card, { style: { padding: 0, paddingBottom: "5px" } }, [
+ h("div.header", [title]),
+ h(MinUnitEditor, {
+ model,
+ persistChanges,
+ onCancel,
+ }),
+ ]);
+}
+
+export { MinUnitEditor, MinEditorToggle, MinEditorCard, NewSectionBtn };
diff --git a/packages/column-builder/src/components/unit/unit-editor.ts b/packages/column-builder/src/components/unit/unit-editor.ts
new file mode 100644
index 00000000..7fcb6d1f
--- /dev/null
+++ b/packages/column-builder/src/components/unit/unit-editor.ts
@@ -0,0 +1,216 @@
+import React from "react";
+import { hyperStyled } from "@macrostrat/hyper";
+import {
+ UnitsView,
+ IntervalRow,
+ IntervalDataI,
+ ColorBlock,
+ Table,
+ FeatureCell,
+} from "../../index";
+import { NumericInput, TextArea } from "@blueprintjs/core";
+import {
+ ModelEditor,
+ useModelEditor,
+ //@ts-ignore
+} from "@macrostrat/ui-components";
+import styles from "../comp.module.sass";
+import { SubmitButton } from "..";
+import {
+ UnitEditorProps,
+ EnvTags,
+ LithTags,
+ UnitRowStratNameEditor,
+ InformalUnitName,
+ UnitThickness,
+} from "./common-editing";
+const h = hyperStyled(styles);
+
+function UnitThicknesses() {
+ const { model: unit, actions }: { model: UnitsView; actions: any } =
+ useModelEditor();
+
+ return h(React.Fragment, [
+ h(FeatureCell, { text: "Min-Thick" }, [
+ h(UnitThickness, {
+ field: "min_thick",
+ defaultValue: unit?.min_thick || undefined,
+ placeholder: "Min thick",
+ }),
+ ]),
+ h(FeatureCell, { text: "Max-Thick: " }, [
+ h(UnitThickness, {
+ field: "max_thick",
+ defaultValue: unit?.max_thick || undefined,
+ placeholder: "Max thick",
+ }),
+ ]),
+ ]);
+}
+
+function StratName() {
+ const { model: unit }: { model: UnitsView } = useModelEditor();
+
+ if (unit?.strat_names == null) {
+ return null;
+ }
+
+ const baseURl = `/unit/${unit.id}`;
+ // this complexity is born of the confusing strat_name issues in the db
+ // const href =
+ unit.strat_names.length > 0
+ ? `${baseURl}/strat-name/${unit.strat_names[0].id}/edit`
+ : `${baseURl}/strat-name/new`;
+
+ const linkText = unit.strat_names.length > 0 ? "(modify)" : "(create)";
+
+ return h("tr", [
+ h(FeatureCell, { text: "Informal Unit Name" }, [h(InformalUnitName)]),
+ h(FeatureCell, { text: "Formal Stratigraphic Name: " }, [
+ h(UnitRowStratNameEditor),
+ // h(Link, { href }, [h("a", { style: { fontSize: "10px" } }, [linkText])]),
+ ]),
+ ]);
+}
+
+interface UnitPositionI {
+ bottom: boolean;
+ position_bottom?: number;
+ position_top?: number;
+ onPositionChange: (e: number) => void;
+}
+
+function UnitPosition(props: UnitPositionI) {
+ const positionLabel: string = props.bottom
+ ? "Position Bottom: "
+ : "Position Top: ";
+
+ return h(React.Fragment, [
+ h(FeatureCell, { text: positionLabel }, [
+ h(NumericInput, {
+ onValueChange: props.onPositionChange,
+ defaultValue: props.position_bottom || props.position_top,
+ }),
+ ]),
+ ]);
+}
+
+/*
+Probably the most complicated component, bc there are so many editable things.
+*/
+function UnitEdit() {
+ const { model: unit, hasChanges, actions, ...rest } = useModelEditor();
+
+ const updateUnit = (field: string, e: any) => {
+ actions.updateState({ model: { [field]: { $set: e } } });
+ };
+
+ const onChangeLo = (interval: IntervalDataI) => {
+ const { data } = interval;
+ const { id: lo, interval_name: name_lo, age_top } = data;
+ actions.updateState({
+ model: {
+ lo: { $set: lo },
+ name_lo: { $set: name_lo },
+ age_top: { $set: age_top },
+ },
+ });
+ };
+
+ const onChangeFo = (interval: IntervalDataI) => {
+ const { data } = interval;
+ const { id: fo, interval_name: name_fo, age_bottom } = data;
+ actions.updateState({
+ model: {
+ fo: { $set: fo },
+ name_fo: { $set: name_fo },
+ age_bottom: { $set: age_bottom },
+ },
+ });
+ };
+
+ return h("div", [
+ h(Table, { interactive: false }, [
+ h(StratName),
+ h("tr", [
+ h(IntervalRow, {
+ bottom: false,
+ age_top: unit?.age_top,
+ initialSelected: {
+ value: unit?.name_lo,
+ data: { id: unit?.lo || 0, interval_name: unit?.name_lo },
+ },
+ onChange: onChangeLo,
+ }),
+ h(UnitPosition, {
+ bottom: false,
+ onPositionChange: (e) => updateUnit("position_top", e),
+ position_top: unit?.position_top || undefined,
+ }),
+ ]),
+ h("tr", [
+ h(IntervalRow, {
+ bottom: true,
+ age_bottom: unit?.age_bottom,
+ initialSelected: {
+ value: unit?.name_fo,
+ data: {
+ id: unit?.fo || 0,
+ interval_name: unit?.name_fo,
+ },
+ },
+ onChange: onChangeFo,
+ }),
+ h(UnitPosition, {
+ bottom: true,
+ onPositionChange: (e) => updateUnit("position_bottom", e),
+ position_bottom: unit?.position_bottom || undefined,
+ }),
+ ]),
+ h("tr", [
+ h(FeatureCell, { text: "Color: " }, [
+ h(ColorBlock, {
+ onChange: (color) => {
+ actions.updateState({
+ model: { color: { $set: color } },
+ });
+ },
+ color: unit?.color,
+ }),
+ ]),
+ h(UnitThicknesses),
+ ]),
+ h("tr", [
+ h(FeatureCell, { text: "Notes: ", colSpan: 5 }, [
+ h(TextArea, {
+ value: unit.notes,
+ onChange: (e) => updateUnit("notes", e.target.value),
+ }),
+ ]),
+ ]),
+ h("tr", [
+ h(FeatureCell, { text: "Lithologies: ", colSpan: 5 }, [h(LithTags)]),
+ ]),
+ h("tr", [
+ h(FeatureCell, { text: "Environments: ", colSpan: 5 }, [h(EnvTags)]),
+ ]),
+ ]),
+ h(SubmitButton),
+ ]);
+}
+
+function UnitEditor(props: UnitEditorProps) {
+ return h(
+ ModelEditor,
+ {
+ model: props.model,
+ //@ts-ignore
+ persistChanges: props.persistChanges,
+ canEdit: true,
+ isEditing: true,
+ },
+ h(UnitEdit)
+ );
+}
+
+export { UnitEditor };
diff --git a/packages/column-builder/src/data-fetching/index.ts b/packages/column-builder/src/data-fetching/index.ts
new file mode 100644
index 00000000..76fe7251
--- /dev/null
+++ b/packages/column-builder/src/data-fetching/index.ts
@@ -0,0 +1 @@
+export * from "./units"
\ No newline at end of file
diff --git a/packages/column-builder/src/data-fetching/units.ts b/packages/column-builder/src/data-fetching/units.ts
new file mode 100644
index 00000000..138c59d9
--- /dev/null
+++ b/packages/column-builder/src/data-fetching/units.ts
@@ -0,0 +1,34 @@
+import { PostgrestError, PostgrestResponse } from "@supabase/postgrest-js";
+import pg, {
+ createUnitBySections,
+ UnitsView,
+} from "@macrostrat-web/column-builder/src";
+
+type ReturnType = {
+ data: { [section_id: number | string]: UnitsView[] }[];
+ error: PostgrestError | null;
+};
+
+export async function getSectionData(
+ match: any,
+ limit: number | null = null
+): Promise {
+ const { data: units, error }: PostgrestResponse = await pg
+ .from("units")
+ .select(
+ /// joins the lith_unit and environ_unit table
+ "*, unit_strat_name_expanded(*,strat_names(*, strat_names_meta(*))),lith_unit(*),environ_unit(*)"
+ )
+ .order("position_bottom", { ascending: true })
+ .match(match)
+ .limit(limit ?? 100000);
+
+ const u1 = units ?? [];
+
+ const unitsMapped: UnitsView[] = u1.map((d) => {
+ const { unit_strat_name_expanded = [], ...rest } = d;
+ return { ...rest, strat_names: unit_strat_name_expanded };
+ });
+
+ return { data: createUnitBySections(unitsMapped), error };
+}
diff --git a/packages/column-builder/src/db/index.ts b/packages/column-builder/src/db/index.ts
new file mode 100644
index 00000000..3807bbdd
--- /dev/null
+++ b/packages/column-builder/src/db/index.ts
@@ -0,0 +1,148 @@
+import { useEffect, useCallback, useState } from "react";
+import {
+ PostgrestClient,
+ PostgrestFilterBuilder,
+ PostgrestQueryBuilder,
+ PostgrestResponse,
+} from "@supabase/postgrest-js";
+import fetch from "cross-fetch";
+import { postgrestPrefix } from "@macrostrat-web/settings";
+
+function isServer() {
+ return typeof window === "undefined";
+}
+
+// The address of the postgrest service is different between the client and the server!
+const pg = new PostgrestClient(
+ //@ts-ignore
+ postgrestPrefix,
+ {
+ fetch(input, options) {
+ console.log(input);
+ return fetch(input, options);
+ },
+ }
+);
+
+/**
+ * Fetch data using postgrestclient
+ * Takes in a postgrestclient QueryBuilder or FilterBuilder
+ * which are js objects, more at https://github.com/supabase/postgrest-js
+ * returns data
+ * @param query : A postgrest-js querybuilder or filterbuilder object
+ */
+function usePostgrest(
+ query: PostgrestQueryBuilder | PostgrestFilterBuilder
+) {
+ const [result, setResult] = useState(); // cop-out type for now
+
+ const getData = useCallback(async () => {
+ const { data, error } = await query;
+ if (error) {
+ console.error(error);
+ } else {
+ setResult(data);
+ }
+ }, [query]);
+
+ useEffect(() => {
+ getData();
+ }, []);
+
+ return result;
+}
+interface SelectTableI {
+ match?: number | Record;
+ limit?: number;
+ columns?: string | undefined;
+}
+
+/*
+ * Helper hook to abstract some query building
+ */
+function useTableSelect(table: string, opts: SelectTableI) {
+ let query = pg.from(table).select(opts.columns);
+ if (opts.match) {
+ if (typeof opts.match !== "number") {
+ query = query.match(opts.match);
+ } else {
+ query = query.match({ id: opts.match });
+ }
+ }
+ if (opts.limit) {
+ query = query.limit(opts.limit);
+ }
+ return usePostgrest(query);
+}
+
+interface QueryOptsI {
+ columns?: string;
+ match?: number | Record;
+ limit?: number;
+}
+
+async function tableSelect(table: string, opts: QueryOptsI = {}) {
+ let query = pg.from(table).select(opts.columns);
+ if (opts.match) {
+ if (typeof opts.match !== "number") {
+ query = query.match(opts.match);
+ } else {
+ query = query.match({ id: opts.match });
+ }
+ }
+ if (opts.limit) {
+ query = query.limit(opts.limit);
+ }
+
+ return await query;
+}
+
+async function selectFirst(table: string, opts: QueryOptsI) {
+ const { data, error }: PostgrestResponse = await tableSelect(
+ table,
+ opts
+ );
+
+ const firstData = data ? data[0] : null;
+ return { firstData, error };
+}
+
+interface UpdateTableI {
+ id: number | Record;
+ changes: object;
+}
+
+async function tableUpdate(table: string, opts: UpdateTableI) {
+ let query = pg.from(table).update(opts.changes);
+ if (typeof opts.id !== "number") {
+ query = query.match(opts.id);
+ } else {
+ query = query.match({ id: opts.id });
+ }
+ return await query;
+}
+
+/*
+ Hook for easy table inserts
+*/
+async function tableInsert(table: string, row: object) {
+ let query = pg.from(table).insert([row]);
+ return await query;
+}
+
+async function tableInsertMany(table: string, rows: object[]) {
+ let query = pg.from(table).insert(rows);
+ return await query;
+}
+
+export default pg;
+export {
+ usePostgrest,
+ useTableSelect,
+ tableUpdate,
+ tableInsert,
+ selectFirst,
+ tableInsertMany,
+ tableSelect,
+ isServer,
+};
diff --git a/packages/column-builder/src/index.ts b/packages/column-builder/src/index.ts
new file mode 100644
index 00000000..07e1897c
--- /dev/null
+++ b/packages/column-builder/src/index.ts
@@ -0,0 +1,6 @@
+import pg from "./db";
+export * from "./db";
+export * from "./components";
+export * from "./types";
+
+export default pg;
diff --git a/packages/column-builder/src/types.ts b/packages/column-builder/src/types.ts
new file mode 100644
index 00000000..4f072832
--- /dev/null
+++ b/packages/column-builder/src/types.ts
@@ -0,0 +1,181 @@
+/*
+The different data types used in the application. Usually matching up with a specific db view in
+macrostrat_api schema
+*/
+
+import { PointGeom } from "@macrostrat/form-components";
+
+export interface Project {
+ descrip: string;
+ id?: number;
+ project: string;
+ timescale_id?: number;
+}
+
+export interface TimeScale {
+ id: number;
+ timescale: string;
+ ref_id: number;
+}
+
+export interface ColumnGroupI {
+ col_group: string;
+ col_group_long: string;
+ cols: ICol[];
+ id: number;
+ project_id: number;
+}
+
+export interface RefI {
+ id?: number;
+ pub_year: number;
+ author: string;
+ ref: string;
+ doi?: string;
+ url?: string;
+}
+
+export interface ColumnForm {
+ id: number;
+ col_area: number;
+ col_type: string;
+ coordinate: PointGeom;
+ poly_geom: { type: "Polygon"; coordinates: [][] } | null;
+ project_id: number;
+ col_name: string;
+ col: number;
+ lng: number;
+ lat: number;
+ notes?: string;
+ wkt: string;
+ refs: RefI[];
+}
+
+// interface for col that shows up in column_group
+export interface ICol {
+ col_id: number;
+ col_number?: number;
+ col_name: string;
+ status_code?: string;
+}
+
+export interface IColumnSection extends ICol {
+ bottom: string;
+ position_bottom: number;
+ position_top: number;
+ top: string;
+ section_id: number;
+ units?: number;
+}
+
+export interface UnitsView {
+ id: number;
+ strat_name: string;
+ strat_names: StratNameI[];
+ color: string;
+ outcrop?: string;
+ fo?: number;
+ name_fo: string;
+ age_bottom: number;
+ lo?: number;
+ name_lo: string;
+ age_top: number;
+ section_id: number;
+ col_id: number;
+ notes?: string;
+ position_bottom: number;
+ position_top: number;
+ max_thick: number;
+ min_thick: number;
+ lith_unit?: LithUnit[];
+ environ_unit?: EnvironUnit[];
+}
+
+export interface Lith {
+ id: number;
+ lith: string;
+ lith_group?: string;
+ lith_type: string;
+ lith_class: string;
+ lith_color: string;
+ dom: "dom" | "sub";
+ mod_prop: number;
+ comp_prop: number;
+}
+
+export interface LithUnit extends Lith {
+ unit_id: number;
+}
+
+export interface Environ {
+ id: number;
+ environ: string;
+ environ_type: string;
+ environ_class: string;
+ environ_color: string;
+}
+
+export interface EnvironUnit extends Environ {
+ unit_id: number;
+}
+
+export interface IntervalI {
+ id: number;
+ age_bottom: number;
+ age_top: number;
+ interval_name: string;
+ interval_abbrev?: string;
+ interval_type?: string;
+ interval_color: string;
+ rank: number;
+}
+
+export enum RANK {
+ SGp = "SGp",
+ Gp = "Gp",
+ SubGp = "SubGp",
+ Fm = "Fm",
+ Mbr = "Mbr",
+ Bed = "Bed",
+}
+
+interface StratNameConceptBase {
+ concept_id: number;
+ orig_id: number;
+ name: string;
+ geologic_age: string;
+ b_int: number;
+ t_int: number;
+ usage_notes: string;
+ other: string;
+ province: string;
+ url: string;
+}
+export interface StratNameConceptI extends StratNameConceptBase {
+ interval_id: number;
+ ref_id: number;
+}
+
+export interface StratNameConceptLongI extends StratNameConceptBase {
+ intervals: IntervalI;
+ refs: RefI;
+}
+
+export interface StratNameI {
+ id: number;
+ strat_name: string;
+ rank: RANK;
+ ref_id: number;
+ author: string | null;
+ concept_id: number | null;
+ parent: string | null;
+ source?: string;
+ strat_names_meta?: StratNameConceptBase;
+}
+
+export interface ColSectionI {
+ id: number;
+ unit_count: number;
+ top: string;
+ bottom: string;
+}
diff --git a/packages/column-builder/tsconfig.json b/packages/column-builder/tsconfig.json
new file mode 100644
index 00000000..abc91aac
--- /dev/null
+++ b/packages/column-builder/tsconfig.json
@@ -0,0 +1,33 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ "baseUrl": ".",
+ "paths": {
+ "~/*": ["./src/*"],
+ "@macrostrat/ui-components": [
+ "deps/web-components/packages/ui-components/src/"
+ ],
+ "@macrostrat/form-components": [
+ "deps/web-components/packages/form-components/src/"
+ ],
+ "@macrostrat/data-components": [
+ "deps/web-components/packages/data-components/src/"
+ ]
+ }
+ },
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
+ "exclude": ["node_modules"]
+}
diff --git a/pages/_error/+Page.ts b/pages/_error/+Page.ts
index 49c057cc..0240169b 100644
--- a/pages/_error/+Page.ts
+++ b/pages/_error/+Page.ts
@@ -2,23 +2,31 @@ import h from "@macrostrat/hyper";
import { CenteredContentPage } from "~/layouts";
import { PageHeader } from "~/components";
import { usePageContext } from "vike-react/usePageContext";
+import { ClientOnly } from "vike-react/ClientOnly";
+import { Spinner, Button } from "@blueprintjs/core";
export function Page() {
+ return h(CenteredContentPage, [h(PageHeader), h(PageContent)]);
+}
+
+function PageContent() {
const ctx = usePageContext();
const is404 = ctx.is404;
+ const path = ctx.urlPathname;
+ const statusCode = ctx.abortStatusCode;
+ const reason = ctx.abortReason;
- return h(CenteredContentPage, [
- h(PageHeader, { title: "Macrostrat" }),
- h(PageContent, { is404, path: ctx.urlPathname }),
- ]);
-}
-
-function PageContent({ is404, path }: { is404: boolean; path: string }) {
if (is404) {
return h([
h("h1", [h("code.bp5-code", "404"), " Page Not Found"]),
h("p", ["Could not find a page at path ", h("code.bp5-code", path), "."]),
]);
+ } else if (statusCode == 401) {
+ return h([
+ h("h1", [h("code.bp5-code", "401"), " Unauthorized"]),
+ h("p", [reason]),
+ h(LoginButton),
+ ]);
} else {
return h([
h("h1", "Internal Error"),
@@ -27,3 +35,24 @@ function PageContent({ is404, path }: { is404: boolean; path: string }) {
]);
}
}
+
+function LoginButton() {
+ /** For now, the login button only loads on the client side */
+ return h(ClientOnly, {
+ load: async () => {
+ const res = await import("@macrostrat/auth-components");
+ return res.AuthStatus;
+ },
+ fallback: h(
+ Button,
+ {
+ disabled: true,
+ icon: h(Spinner, { size: 16 }),
+ minimal: true,
+ large: true,
+ },
+ "Not logged in"
+ ),
+ children: (component) => h(component),
+ });
+}
diff --git a/pages/dev/+Page.mdx b/pages/dev/+Page.mdx
index 81e01f99..41741872 100644
--- a/pages/dev/+Page.mdx
+++ b/pages/dev/+Page.mdx
@@ -10,6 +10,12 @@ import { PageHeader } from "~/components";
- [Paleogeography](/dev/paleo)
+## Column editing
+
+- [Column editor](/dev/column-editor)
+
+## xDD integration
+
## xDD
- [Map legend affinity](/dev/map/legend-affinity)
diff --git a/pages/dev/+config.ts b/pages/dev/+config.ts
index 56c3523b..ff8b4c56 100644
--- a/pages/dev/+config.ts
+++ b/pages/dev/+config.ts
@@ -1,4 +1 @@
-export default {
- // Forces global style separation from other pages by reloading
- clientRouting: false,
-};
+export default {};
diff --git a/pages/dev/column-editor/+config.ts b/pages/dev/column-editor/+config.ts
new file mode 100644
index 00000000..73a0f7f7
--- /dev/null
+++ b/pages/dev/column-editor/+config.ts
@@ -0,0 +1,11 @@
+export default {
+ meta: {
+ Page: {
+ env: {
+ client: true,
+ server: false,
+ },
+ },
+ },
+ title: "Column editor",
+};
diff --git a/pages/dev/column-editor/+guard.ts b/pages/dev/column-editor/+guard.ts
new file mode 100644
index 00000000..6bd9cc8e
--- /dev/null
+++ b/pages/dev/column-editor/+guard.ts
@@ -0,0 +1,10 @@
+import { render } from "vike/abort";
+
+// This guard() hook protects all pages /pages/admin/**/+Page.js
+// https://vike.dev/guard
+
+export async function guard(pageContext) {
+ if (pageContext.user?.role != "web_admin") {
+ throw render(401, "You aren't allowed to access this page.");
+ }
+}
diff --git a/pages/dev/column-editor/column-group/@col_group_id/edit/+Page.ts b/pages/dev/column-editor/column-group/@col_group_id/edit/+Page.ts
new file mode 100644
index 00000000..37f02967
--- /dev/null
+++ b/pages/dev/column-editor/column-group/@col_group_id/edit/+Page.ts
@@ -0,0 +1,33 @@
+import h from "@macrostrat/hyper";
+import {
+ BasePage,
+ ColumnGroupEditor,
+ ColumnGroupI,
+ tableUpdate,
+} from "@macrostrat-web/column-builder";
+import { useData } from "vike-react/useData";
+import { EditColumnGroupData } from "./+data";
+
+export function Page() {
+ const { columnGroup, query, errors } = useData();
+ const persistChanges = async (
+ e: Partial,
+ changes: Partial
+ ) => {
+ const { data, error } = await tableUpdate("col_groups", {
+ changes,
+ id: e.id || 0,
+ });
+ if (!error) {
+ return data[0];
+ } else {
+ console.error(error);
+ }
+ };
+
+ return h(BasePage, { query, errors }, [
+ h("h3", ["Edit Column Group: ", columnGroup.col_group_long]),
+ //@ts-ignore
+ h(ColumnGroupEditor, { model: columnGroup, persistChanges }),
+ ]);
+}
diff --git a/pages/dev/column-editor/column-group/@col_group_id/edit/+data.ts b/pages/dev/column-editor/column-group/@col_group_id/edit/+data.ts
new file mode 100644
index 00000000..787ab637
--- /dev/null
+++ b/pages/dev/column-editor/column-group/@col_group_id/edit/+data.ts
@@ -0,0 +1,34 @@
+import {
+ ColumnGroupI,
+ fetchIdsFromColGroup,
+ IdsFromColGroup,
+ tableSelect,
+} from "@macrostrat-web/column-builder";
+import { PostgrestError, PostgrestResponse } from "@supabase/postgrest-js";
+import { PageContext } from "vike/types";
+
+export async function data(ctx: PageContext): Promise {
+ let { col_group_id } = ctx.routeParams;
+ if (Array.isArray(col_group_id)) {
+ col_group_id = col_group_id[0];
+ }
+
+ const query: IdsFromColGroup = await fetchIdsFromColGroup(
+ parseInt(col_group_id ?? "0")
+ );
+
+ const { data, error }: PostgrestResponse> =
+ await tableSelect("col_groups", {
+ match: { id: col_group_id ?? "0" },
+ });
+
+ const columnGroup = data ? data[0] : {};
+ const errors = [error].filter((e) => e != null);
+ return { col_group_id, columnGroup, query, errors };
+}
+
+export interface EditColumnGroupData {
+ errors: PostgrestError[];
+ columnGroup: Partial;
+ query: IdsFromColGroup;
+}
diff --git a/pages/dev/column-editor/column-group/@col_group_id/new-column/+Page.ts b/pages/dev/column-editor/column-group/@col_group_id/new-column/+Page.ts
new file mode 100644
index 00000000..0e408a47
--- /dev/null
+++ b/pages/dev/column-editor/column-group/@col_group_id/new-column/+Page.ts
@@ -0,0 +1,62 @@
+import h from "@macrostrat/hyper";
+import {
+ BasePage,
+ ColumnEditor,
+ ColumnForm,
+ tableInsert,
+} from "@macrostrat-web/column-builder";
+import { useData } from "vike-react/useData";
+import { NewColumnData } from "./+data";
+
+export function Page() {
+ const { colGroup, col_group_id, errors } = useData();
+
+ const persistChanges = async (
+ e: ColumnForm,
+ changes: Partial
+ ) => {
+ //create the correct column object for persistence.
+ // project_id, col_group_id, col (#), col_name, status_code, col_type
+ //get the id back and enter that into the ref_col table
+ const newColumn = {
+ project_id: colGroup.project_id,
+ col_group_id,
+ col: e.col_number,
+ col_name: e.col_name,
+ status_code: "in process",
+ col_type: "column",
+ lat: e.lat,
+ lng: e.lng,
+ };
+
+ const { data, error } = await tableInsert("cols", newColumn);
+
+ if (!error) {
+ // create new col_refs from new id
+ const col_id: number = data[0].id;
+ const ref_col = { ref_id: e.ref.id, col_id: col_id };
+
+ const { data: data_, error } = await tableInsert("col_refs", ref_col);
+
+ if (!error) {
+ return e;
+ } else {
+ //catch errror
+ }
+ } else {
+ //catch error
+ }
+ };
+
+ return h(BasePage, { query: props.query, errors }, [
+ h("h3", [
+ `Add a new column to ${colGroup.col_group_long}(${colGroup.col_group})`,
+ ]),
+ //@ts-ignore
+ h(ColumnEditor, {
+ model: {},
+ persistChanges,
+ curColGroup: colGroup,
+ }),
+ ]);
+}
diff --git a/pages/dev/column-editor/column-group/@col_group_id/new-column/+data.ts b/pages/dev/column-editor/column-group/@col_group_id/new-column/+data.ts
new file mode 100644
index 00000000..02c10fab
--- /dev/null
+++ b/pages/dev/column-editor/column-group/@col_group_id/new-column/+data.ts
@@ -0,0 +1,36 @@
+import pg, {
+ ColumnGroupI,
+ fetchIdsFromColGroup,
+ IdsFromColGroup,
+} from "@macrostrat-web/column-builder";
+import { PostgrestError, PostgrestResponse } from "@supabase/postgrest-js";
+import { PageContext } from "vike/types";
+
+export async function data(ctx: PageContext) {
+ let { col_group_id } = ctx.routeParams;
+
+ if (Array.isArray(col_group_id)) {
+ col_group_id = col_group_id[0];
+ }
+
+ const query: IdsFromColGroup = await fetchIdsFromColGroup(
+ parseInt(col_group_id ?? "0")
+ );
+
+ const { data, error }: PostgrestResponse> = await pg
+ .from("col_groups")
+ .select()
+ .match({ id: col_group_id });
+
+ const colGroup = data ? data[0] : {};
+
+ const errors = error == null ? [] : [error];
+ return { props: { col_group_id, colGroup, query, errors } };
+}
+
+export interface NewColumnData {
+ col_group_id: string;
+ colGroup: Partial;
+ query: IdsFromColGroup;
+ errors: PostgrestError[];
+}
diff --git a/pages/dev/column-editor/column-groups/@project_id/+Page.ts b/pages/dev/column-editor/column-groups/@project_id/+Page.ts
new file mode 100644
index 00000000..3481e08a
--- /dev/null
+++ b/pages/dev/column-editor/column-groups/@project_id/+Page.ts
@@ -0,0 +1,68 @@
+import h from "@macrostrat/hyper";
+import { PostgrestError } from "@supabase/postgrest-js";
+import { useData } from "vike-react/useData";
+import pg, {
+ ColumnGroupI,
+ Row,
+ BasePage,
+ Table,
+ CreateButton,
+ EditButton,
+} from "@macrostrat-web/column-builder";
+import type { ColumnGroupsData } from "./+data";
+
+export function Page() {
+ const props = useData();
+
+ const { project_id, errors } = props;
+
+ const headers = ["ID", "Name", "Col #", "Status"];
+
+ return h(BasePage, { query: { project_id }, errors }, [
+ h("h3", [
+ `Column Groups for Project #${props.project_id}: ${props.projectName}`,
+ h(CreateButton, {
+ href: `/column-groups/${project_id}/new`,
+ text: "Add New Group",
+ }),
+ ]),
+ h("div", { style: { display: "flex", flexWrap: "wrap" } }, [
+ props.columnGroups.map((colGroup, i) => {
+ return h(
+ "div",
+ { key: i, style: { textAlign: "center", height: "100%" } },
+ [
+ h("div.col-group-name", [
+ h("h3", { style: { margin: 0 } }, colGroup.col_group_long),
+ h(EditButton, {
+ small: true,
+ href: `../column-group/${colGroup.id}/edit`,
+ }),
+ ]),
+ h(Table, { interactive: true, headers }, [
+ colGroup.cols.map((id, i) => {
+ return h(
+ Row,
+ {
+ key: id.col_id,
+ href: `../column/${id.col_id}`,
+ },
+ [
+ h("td", [id.col_id]),
+ h("td", [id.col_name]),
+ h("td", [id.col_number]),
+ h("td", [id.status_code]),
+ ]
+ );
+ }),
+ ]),
+ h(CreateButton, {
+ href: `/column-group/${colGroup.id}/new-column`,
+ text: "Add New Column",
+ }),
+ ]
+ );
+ }),
+ ]),
+ ]);
+}
diff --git a/pages/dev/column-editor/column-groups/@project_id/+data.ts b/pages/dev/column-editor/column-groups/@project_id/+data.ts
new file mode 100644
index 00000000..3e65cad0
--- /dev/null
+++ b/pages/dev/column-editor/column-groups/@project_id/+data.ts
@@ -0,0 +1,24 @@
+import pg, { ColumnGroupI } from "@macrostrat-web/column-builder";
+import { PageContext } from "vike/types";
+import { PostgrestError } from "@supabase/postgrest-js";
+
+export async function data(ctx: PageContext): Promise {
+ const { project_id } = ctx.routeParams;
+
+ const { data, error } = await pg
+ .from("col_group_with_cols")
+ .select("*")
+ .match({ project_id });
+
+ const projectName: string = data && data.length > 0 ? data[0].project : "";
+ const errors = [error].filter((e) => e != null);
+
+ return { project_id, projectName, columnGroups: data, errors };
+}
+
+export interface ColumnGroupsData {
+ projectName: string;
+ project_id: number;
+ columnGroups: ColumnGroupI[];
+ errors: PostgrestError[];
+}
diff --git a/pages/dev/column-editor/column-groups/@project_id/colgroup.module.scss b/pages/dev/column-editor/column-groups/@project_id/colgroup.module.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/pages/dev/column-editor/column-groups/@project_id/new/+Page.ts b/pages/dev/column-editor/column-groups/@project_id/new/+Page.ts
new file mode 100644
index 00000000..eeac3853
--- /dev/null
+++ b/pages/dev/column-editor/column-groups/@project_id/new/+Page.ts
@@ -0,0 +1,37 @@
+import pg, {
+ BasePage,
+ ColumnGroupEditor,
+ ColumnGroupI,
+} from "@macrostrat-web/column-builder";
+import h from "../colgroup.module.scss";
+import { useData } from "vike-react/useData";
+import type { NewColumnGroupParams } from "./+data";
+
+export function Page() {
+ const { project, project_id, errors } = useData();
+
+ const newColumnGroup: Partial = {
+ col_group: "",
+ col_group_long: "",
+ };
+
+ const persistChanges = async (
+ columnGroup: Partial,
+ c: Partial
+ ) => {
+ const { data, error } = await pg
+ .from("col_groups")
+ .insert([{ ...columnGroup, project_id: project_id }]);
+ if (!error) {
+ return data[0];
+ } else {
+ //catch error
+ }
+ };
+
+ return h(BasePage, { query: { project_id }, errors }, [
+ h("h3", ["Create a New Column Group for ", project.project]),
+ //@ts-ignore
+ h(ColumnGroupEditor, { model: newColumnGroup, persistChanges }),
+ ]);
+}
diff --git a/pages/dev/column-editor/column-groups/@project_id/new/+data.ts b/pages/dev/column-editor/column-groups/@project_id/new/+data.ts
new file mode 100644
index 00000000..1838b85e
--- /dev/null
+++ b/pages/dev/column-editor/column-groups/@project_id/new/+data.ts
@@ -0,0 +1,21 @@
+import { Project, tableSelect } from "@macrostrat-web/column-builder";
+import { PostgrestError } from "@supabase/postgrest-js";
+import { PageContext } from "vike/types";
+
+export async function data(ctx: PageContext): Promise {
+ const { project_id } = ctx.routeParams;
+
+ const { data, error } = await tableSelect("projects", {
+ match: { id: project_id },
+ });
+
+ const project = data ? data[0] : {};
+ const errors = [error].filter((e) => e != null);
+ return { project_id, project, errors };
+}
+
+export interface NewColumnGroupParams {
+ project_id: number;
+ project: Project;
+ errors: PostgrestError[];
+}
diff --git a/pages/dev/column-editor/column/@col_id/+Page.ts b/pages/dev/column-editor/column/@col_id/+Page.ts
new file mode 100644
index 00000000..ada611b3
--- /dev/null
+++ b/pages/dev/column-editor/column/@col_id/+Page.ts
@@ -0,0 +1,27 @@
+import h from "@macrostrat/hyper";
+import {
+ BasePage,
+ EditButton,
+ UnitSectionTable,
+} from "@macrostrat-web/column-builder";
+import { useData } from "vike-react/useData";
+import { ColumnProps } from "./+data";
+
+export function Page() {
+ const props: ColumnProps = useData();
+ const { col_id, colSections, column, query, sections, errors } = props;
+
+ const columnName = column ? column[0].col_name : null;
+
+ return h(BasePage, { query, errors }, [
+ h("h3", [
+ `Sections for column ${columnName}`,
+ h(EditButton, {
+ href: `./${col_id}/edit`,
+ }),
+ ]),
+ // there doesn't appear to be a good solution yet, so this is the best we can do. It loses the SSR
+ // for this component unfortunately
+ h(UnitSectionTable, { sections, colSections, col_id }),
+ ]);
+}
diff --git a/pages/dev/column-editor/column/@col_id/+data.ts b/pages/dev/column-editor/column/@col_id/+data.ts
new file mode 100644
index 00000000..cf1de81b
--- /dev/null
+++ b/pages/dev/column-editor/column/@col_id/+data.ts
@@ -0,0 +1,58 @@
+import { PostgrestError, PostgrestResponse } from "@supabase/postgrest-js";
+import { PageContext } from "vike/types";
+import pg, {
+ ColSectionI,
+ fetchIdsFromColId,
+ IdsFromCol,
+ UnitsView,
+} from "@macrostrat-web/column-builder";
+
+import { getSectionData } from "@macrostrat-web/column-builder/src/data-fetching";
+
+export async function data(ctx: PageContext) {
+ let {
+ routeParams: { col_id },
+ } = ctx;
+ if (Array.isArray(col_id)) {
+ col_id = col_id[0];
+ }
+
+ const query: IdsFromCol = await fetchIdsFromColId(parseInt(col_id ?? "0"));
+
+ const { data: colSections, error: e }: PostgrestResponse =
+ await pg.from("col_section_data").select().match({ col_id });
+
+ const {
+ data: column,
+ error: col_error,
+ }: PostgrestResponse<{ col_name: string }> = await pg
+ .from("cols")
+ .select("col_name")
+ .match({ id: col_id });
+
+ const { data: sections, error: unit_error } = await getSectionData({
+ col_id,
+ });
+
+ const errors = [e, col_error, unit_error].filter((e) => e != null);
+ if (errors.length > 0) {
+ console.error(errors);
+ }
+ return {
+ col_id,
+ colSections,
+ column,
+ errors,
+ query,
+ sections,
+ };
+}
+
+export interface ColumnProps {
+ col_id: string;
+ colSections: ColSectionI[];
+ column: { col_name: string }[];
+ errors: PostgrestError[];
+ query: IdsFromCol;
+ sections: { [section_id: number | string]: UnitsView[] }[];
+}
diff --git a/pages/dev/column-editor/column/@col_id/edit/+Page.ts b/pages/dev/column-editor/column/@col_id/edit/+Page.ts
new file mode 100644
index 00000000..486055de
--- /dev/null
+++ b/pages/dev/column-editor/column/@col_id/edit/+Page.ts
@@ -0,0 +1,85 @@
+import h from "@macrostrat/hyper";
+import pg, {
+ BasePage,
+ ColumnEditor,
+ ColumnForm,
+ IdsFromCol,
+ tableUpdate,
+} from "@macrostrat-web/column-builder";
+import { PostgrestError } from "@supabase/postgrest-js";
+import { useData } from "vike-react/useData";
+
+interface EditColumnData {
+ col_id: string;
+ curColGroup: any;
+ column: ColumnForm[];
+ query: IdsFromCol;
+ errors: PostgrestError[];
+}
+
+export function Page() {
+ const props = useData();
+ const { col_id, curColGroup, column, errors }: EditColumnData = props;
+ console.log(column);
+ const persistChanges = async (
+ e: ColumnForm,
+ changes: Partial
+ ) => {
+ console.log(e, changes);
+ // port names to match db (only col_numer -> col)
+ let ref_id: number | undefined = undefined;
+ if (changes.refs) {
+ // handle the changing of a ref, either one that exists or was created
+ ref_id = changes.refs[0].id;
+ delete changes.refs;
+ }
+ // lat,lng only need to be entered to update coordinate and wkt.
+ // DB triggers, see /api-views/02-functions.sql
+ const { data, error } = await tableUpdate("cols", {
+ changes,
+ id: e.id,
+ });
+
+ if (!error) {
+ if (ref_id) {
+ const ref_col = { ref_id: ref_id };
+ const { data: count, error: _ } = await pg
+ .from("col_refs")
+ .select()
+ .match({ col_id: e.id });
+ if (count?.length ?? 0 > 1) {
+ const { data: data_, error } = await pg
+ .from("col_refs")
+ .update({ ref_id })
+ .match({ col_id: e.id });
+ } else {
+ const { data: data_, error } = await pg
+ .from("col_refs")
+ .insert([{ ref_id, col_id: e.id }]);
+ }
+ }
+ if (error) {
+ //catch errror
+ }
+ return e;
+ } else {
+ //catch error
+ }
+
+ // check if ref has changed
+
+ return e;
+ };
+
+ return h(BasePage, { query: props.query, errors }, [
+ h("h3", [
+ `Edit column ${column[0].col_name}, part of ${curColGroup.col_group_long}(${curColGroup.col_group}) Column Group`,
+ ]),
+ //@ts-ignore
+ h(ColumnEditor, {
+ model: column[0],
+ persistChanges,
+ curColGroup: curColGroup,
+ }),
+ ]);
+}
diff --git a/pages/dev/column-editor/column/@col_id/edit/+data.ts b/pages/dev/column-editor/column/@col_id/edit/+data.ts
new file mode 100644
index 00000000..f01429c7
--- /dev/null
+++ b/pages/dev/column-editor/column/@col_id/edit/+data.ts
@@ -0,0 +1,39 @@
+import pg, {
+ ColumnForm,
+ fetchIdsFromColId,
+ IdsFromCol,
+ selectFirst,
+} from "@macrostrat-web/column-builder";
+import { PostgrestResponse } from "@supabase/postgrest-js";
+import { PageContext } from "vike/types";
+
+export async function data(ctx: PageContext) {
+ let { col_id } = ctx.routeParams;
+ if (Array.isArray(col_id)) {
+ col_id = col_id[0];
+ }
+ const query: IdsFromCol = await fetchIdsFromColId(parseInt(col_id ?? "0"));
+
+ const { data, error }: PostgrestResponse = await pg
+ .from("cols")
+ .select("*,refs(*)")
+ .match({ id: parseInt(col_id ?? "0") });
+
+ const { firstData, error: error_ } = await selectFirst("cols", {
+ columns: "col_groups!cols_col_group_id_fkey(*)",
+ match: { id: parseInt(col_id ?? "0") },
+ limit: 1,
+ });
+
+ const errors = [error, error_].filter((e) => e != null);
+
+ console.log(data);
+
+ return {
+ col_id,
+ column: data,
+ curColGroup: firstData.col_groups,
+ query,
+ errors,
+ };
+}
diff --git a/pages/dev/column-editor/column/@col_id/new/+Page.ts b/pages/dev/column-editor/column/@col_id/new/+Page.ts
new file mode 100644
index 00000000..37676ad2
--- /dev/null
+++ b/pages/dev/column-editor/column/@col_id/new/+Page.ts
@@ -0,0 +1,27 @@
+import h from "@macrostrat/hyper";
+import {
+ BasePage,
+ UnitEditor,
+ IdsFromCol,
+ UnitsView,
+} from "@macrostrat-web/column-builder";
+import { persistNewUnitChanges } from "@macrostrat-web/column-builder/src/components/section/new-helpers";
+import { useData } from "vike-react/useData";
+import type { NewUnitData } from "./+data";
+
+function Page() {
+ const { col_id, query }: NewUnitData = useData();
+ const model = { unit: { col_id: col_id }, liths: [], envs: [] };
+
+ const persistChanges = async (
+ updatedModel: UnitsView,
+ changeSet: Partial
+ ) => {
+ return await persistNewUnitChanges(updatedModel, changeSet, null, col_id);
+ };
+
+ return h(BasePage, { query, errors: [] }, [
+ //@ts-ignore
+ h(UnitEditor, { model, persistChanges }),
+ ]);
+}
diff --git a/pages/dev/column-editor/column/@col_id/new/+data.ts b/pages/dev/column-editor/column/@col_id/new/+data.ts
new file mode 100644
index 00000000..917d0692
--- /dev/null
+++ b/pages/dev/column-editor/column/@col_id/new/+data.ts
@@ -0,0 +1,19 @@
+import { fetchIdsFromColId, IdsFromCol } from "@macrostrat-web/column-builder";
+
+import { PageContext } from "vike/types";
+
+export async function data(ctx: PageContext): Promise {
+ let { col_id } = ctx.routeParams;
+
+ if (Array.isArray(col_id)) {
+ col_id = col_id[0];
+ }
+ const query: IdsFromCol = await fetchIdsFromColId(parseInt(col_id ?? "0"));
+
+ return { col_id, query };
+}
+
+export interface NewUnitData {
+ col_id: number;
+ query: IdsFromCol;
+}
diff --git a/pages/dev/column-editor/index/+Page.ts b/pages/dev/column-editor/index/+Page.ts
new file mode 100644
index 00000000..5a2cb46d
--- /dev/null
+++ b/pages/dev/column-editor/index/+Page.ts
@@ -0,0 +1,54 @@
+import h from "@macrostrat/hyper";
+import { PostgrestError } from "@supabase/postgrest-js";
+import {
+ Row,
+ Project,
+ BasePage,
+ Table,
+ EditButton,
+ CreateButton,
+} from "@macrostrat-web/column-builder";
+import { useData } from "vike-react/useData";
+
+export function Page() {
+ const data: {
+ projects: Project[];
+ errors: PostgrestError[];
+ } = useData();
+ const { projects, errors } = data;
+
+ const headers = Object.keys(projects[0]);
+
+ return h(BasePage, { query: {}, errors }, [
+ h("h3,", [
+ "Choose a Project",
+ h(CreateButton, {
+ minimal: true,
+ href: "/project/new",
+ text: "Create New Project",
+ }),
+ ]),
+ h(Table, { interactive: true, headers }, [
+ projects.map((project, i) => {
+ return h(
+ Row,
+ {
+ key: i,
+ href: `/column-groups/${project.id}`,
+ },
+ [
+ h("td", [project.id]),
+ h("td", [project.project]),
+ h("td", [project.descrip]),
+ h("td", [project.timescale_id]),
+ h("td", [
+ h(EditButton, {
+ href: `/project/${project.id}/edit`,
+ }),
+ ]),
+ ]
+ );
+ }),
+ ]),
+ ]);
+}
diff --git a/pages/dev/column-editor/index/+config.ts b/pages/dev/column-editor/index/+config.ts
new file mode 100644
index 00000000..6fbafe04
--- /dev/null
+++ b/pages/dev/column-editor/index/+config.ts
@@ -0,0 +1,4 @@
+export default {
+ title: "Dacite v2",
+ description: "A modern rewrite of Macrostrat's classic column editing app.",
+};
diff --git a/pages/dev/column-editor/index/+data.ts b/pages/dev/column-editor/index/+data.ts
new file mode 100644
index 00000000..e12da89f
--- /dev/null
+++ b/pages/dev/column-editor/index/+data.ts
@@ -0,0 +1,10 @@
+import { PageContext } from "vike/types";
+import { Project, tableSelect } from "@macrostrat-web/column-builder";
+
+export async function data(ctx: PageContext) {
+ const { data, error } = await tableSelect("projects");
+ const projects: Project[] = data ? data : [{}];
+
+ const errors = [error].filter((e) => e != null);
+ return { projects, errors };
+}
diff --git a/pages/dev/column-editor/project/@project_id/edit/+Page.ts b/pages/dev/column-editor/project/@project_id/edit/+Page.ts
new file mode 100644
index 00000000..23c5acc7
--- /dev/null
+++ b/pages/dev/column-editor/project/@project_id/edit/+Page.ts
@@ -0,0 +1,31 @@
+import {
+ BasePage,
+ Project,
+ ProjectEditor,
+ tableUpdate,
+} from "@macrostrat-web/column-builder";
+import h from "../../project.module.scss";
+import { useData } from "vike-react/useData";
+import type { ProjectData } from "./+data";
+
+export function Page() {
+ const { project, project_id, errors } = useData();
+
+ const persistChanges = async (e: Project, changes: Partial) => {
+ const { data, error } = await tableUpdate("projects", {
+ id: e.id,
+ changes,
+ });
+
+ if (!error) {
+ return data[0];
+ } else {
+ // error catching here
+ }
+ };
+
+ return h(BasePage, { query: {}, errors }, [
+ h("h3", ["Create a New Project"]),
+ h(ProjectEditor, { project: project, persistChanges }),
+ ]);
+}
diff --git a/pages/dev/column-editor/project/@project_id/edit/+data.ts b/pages/dev/column-editor/project/@project_id/edit/+data.ts
new file mode 100644
index 00000000..68d00b0a
--- /dev/null
+++ b/pages/dev/column-editor/project/@project_id/edit/+data.ts
@@ -0,0 +1,20 @@
+import { Project, selectFirst } from "@macrostrat-web/column-builder";
+import { PageContext } from "vike/types";
+import { PostgrestError } from "@supabase/postgrest-js";
+
+export async function data(ctx: PageContext): Promise {
+ const { project_id } = ctx.routeParams;
+
+ const { firstData, error } = await selectFirst("projects", {
+ match: { id: project_id },
+ });
+ const project = firstData ? firstData : {};
+ const errors = [error].filter((e) => e != null);
+ return { project_id, project, errors };
+}
+
+export interface ProjectData {
+ project_id: string;
+ project: Project;
+ errors: PostgrestError[];
+}
diff --git a/pages/dev/column-editor/project/new/+Page.ts b/pages/dev/column-editor/project/new/+Page.ts
new file mode 100644
index 00000000..3100b943
--- /dev/null
+++ b/pages/dev/column-editor/project/new/+Page.ts
@@ -0,0 +1,26 @@
+import {
+ tableInsert,
+ BasePage,
+ Project,
+ ProjectEditor,
+} from "@macrostrat-web/column-builder";
+import h from "../project.module.scss";
+
+export function Page() {
+ const newProject: Project = {
+ project: "",
+ descrip: "",
+ timescale_id: undefined,
+ };
+
+ const persistChanges = async (project: Project, c: Partial) => {
+ const { data, error } = await tableInsert("projects", project);
+ return data ? data[0] : {};
+ };
+
+ return h(BasePage, { query: {}, errors: [] }, [
+ h("h3", ["Create a New Project"]),
+ //@ts-ignore
+ h(ProjectEditor, { project: newProject, persistChanges }),
+ ]);
+}
diff --git a/pages/dev/column-editor/project/project.module.scss b/pages/dev/column-editor/project/project.module.scss
new file mode 100644
index 00000000..bd283f77
--- /dev/null
+++ b/pages/dev/column-editor/project/project.module.scss
@@ -0,0 +1,4 @@
+.textArea {
+ min-width: 500px;
+ min-height: 170px;
+}
diff --git a/pages/dev/column-editor/section/@section_id/+Page.ts b/pages/dev/column-editor/section/@section_id/+Page.ts
new file mode 100644
index 00000000..4a9fa23a
--- /dev/null
+++ b/pages/dev/column-editor/section/@section_id/+Page.ts
@@ -0,0 +1,17 @@
+import h from "@macrostrat/hyper";
+import { BasePage, UnitSectionTable } from "@macrostrat-web/column-builder";
+import { useData } from "vike-react/useData";
+import type { SectionData } from "./+data";
+
+export function Page() {
+ const { section_id, sections, errors } = useData();
+
+ return h(BasePage, { query: props.query, errors }, [
+ h("h3", [`Units in Section #${section_id}`]),
+ h(UnitSectionTable, {
+ sections,
+ colSections: [],
+ col_id: props.query.col_id,
+ }),
+ ]);
+}
diff --git a/pages/dev/column-editor/section/@section_id/+data.ts b/pages/dev/column-editor/section/@section_id/+data.ts
new file mode 100644
index 00000000..284b67c2
--- /dev/null
+++ b/pages/dev/column-editor/section/@section_id/+data.ts
@@ -0,0 +1,34 @@
+import {
+ UnitsView,
+ fetchIdsFromSectionId,
+ IdsFromSection,
+} from "@macrostrat-web/column-builder";
+import { PageContext } from "vike/types";
+import { PostgrestError } from "@supabase/postgrest-js";
+import { getSectionData } from "@macrostrat-web/column-builder/src/data-fetching";
+
+export interface SectionData {
+ section_id: string;
+ query: IdsFromSection;
+ sections: { [section_id: number | string]: UnitsView[] }[];
+ errors: PostgrestError[];
+}
+
+export async function data(ctx: PageContext): Promise {
+ let { section_id } = ctx.routeParams;
+
+ if (Array.isArray(section_id)) {
+ section_id = section_id[0];
+ } else if (typeof section_id == "undefined") {
+ section_id = "0";
+ }
+
+ const query: IdsFromSection = await fetchIdsFromSectionId(
+ parseInt(section_id)
+ );
+
+ const { data: sections, error } = await getSectionData({ section_id });
+
+ const errors = [error].filter((e) => e != null);
+ return { section_id, query, sections, errors };
+}
diff --git a/pages/dev/column-editor/section/@section_id/new-unit/+Page.ts b/pages/dev/column-editor/section/@section_id/new-unit/+Page.ts
new file mode 100644
index 00000000..34d17ef2
--- /dev/null
+++ b/pages/dev/column-editor/section/@section_id/new-unit/+Page.ts
@@ -0,0 +1,32 @@
+import h from "@macrostrat/hyper";
+import {
+ BasePage,
+ UnitEditor,
+ UnitsView,
+ persistNewUnitChanges,
+} from "@macrostrat-web/column-builder";
+import { useData } from "vike-react/useData";
+import type { NewUnitData } from "./+data";
+
+export function Page() {
+ const { col_id, section_id, query, errors } = useData();
+
+ const model = { unit: { col_id: col_id }, liths: [], envs: [] };
+
+ const persistChanges = async (
+ updatedModel: UnitsView,
+ changeSet: Partial
+ ) => {
+ return await persistNewUnitChanges(
+ updatedModel,
+ changeSet,
+ section_id,
+ col_id
+ );
+ };
+
+ return h(BasePage, { query, errors }, [
+ //@ts-ignore
+ h(UnitEditor, { model, persistChanges }),
+ ]);
+}
diff --git a/pages/dev/column-editor/section/@section_id/new-unit/+data.ts b/pages/dev/column-editor/section/@section_id/new-unit/+data.ts
new file mode 100644
index 00000000..594022a6
--- /dev/null
+++ b/pages/dev/column-editor/section/@section_id/new-unit/+data.ts
@@ -0,0 +1,36 @@
+import {
+ IdsFromSection,
+ fetchIdsFromSectionId,
+ selectFirst,
+} from "@macrostrat-web/column-builder";
+import { PageContext } from "vike/types";
+import { PostgrestError } from "@supabase/postgrest-js";
+
+export interface NewUnitData {
+ col_id: number;
+ section_id: string;
+ query: IdsFromSection;
+ errors: PostgrestError[];
+}
+
+export async function data(ctx: PageContext): Promise {
+ let { section_id } = ctx.routeParams;
+
+ if (Array.isArray(section_id)) {
+ section_id = section_id[0];
+ } else if (typeof section_id == "undefined") {
+ section_id = "0";
+ }
+
+ const query: IdsFromSection = await fetchIdsFromSectionId(
+ parseInt(section_id)
+ );
+
+ const { firstData, error } = await selectFirst("sections", {
+ match: { id: section_id },
+ });
+
+ const { col_id } = firstData;
+ const errors = error == null ? [] : [error];
+ return { section_id: ctx.query.section_id, col_id, query, errors };
+}
diff --git a/pages/dev/column-editor/unit/@unit_id/edit/+Page.ts b/pages/dev/column-editor/unit/@unit_id/edit/+Page.ts
new file mode 100644
index 00000000..d7b67d7c
--- /dev/null
+++ b/pages/dev/column-editor/unit/@unit_id/edit/+Page.ts
@@ -0,0 +1,35 @@
+import h from "@macrostrat/hyper";
+import {
+ BasePage,
+ UnitEditor,
+ UnitsView,
+} from "@macrostrat-web/column-builder";
+import { persistUnitChanges } from "@macrostrat-web/column-builder/src/components/unit/edit-helpers";
+import { useData } from "vike-react/useData";
+import type { UnitEditParams } from "./+data";
+
+/*
+Needs a strat_name displayer, we'll be stricter with editing that
+
+Need interval suggest component (2), Need A color picker, Contact suggests.
+Tags for liths and environs; adding components for those too.
+*/
+export function Page() {
+ const { unit, errors, unit_id, query } = useData();
+
+ const model = unit;
+ console.log("UnitA", model);
+
+ const persistChanges = async (
+ updatedModel: UnitsView,
+ changeSet: Partial
+ ) => {
+ return await persistUnitChanges(unit, updatedModel, changeSet);
+ };
+
+ return h(BasePage, { query, errors }, [
+ h("h3", [`Edit Unit #${unit.id}: `, unit.strat_name]),
+ //@ts-ignore
+ h(UnitEditor, { model, persistChanges }),
+ ]);
+}
diff --git a/pages/dev/column-editor/unit/@unit_id/edit/+data.ts b/pages/dev/column-editor/unit/@unit_id/edit/+data.ts
new file mode 100644
index 00000000..a1c0920b
--- /dev/null
+++ b/pages/dev/column-editor/unit/@unit_id/edit/+data.ts
@@ -0,0 +1,35 @@
+import {
+ fetchIdsFromUnitId,
+ IdsFromUnit,
+ UnitsView,
+} from "@macrostrat-web/column-builder";
+import { PageContext } from "vike/types";
+import { PostgrestError } from "@supabase/postgrest-js";
+import { getSectionData } from "@macrostrat-web/column-builder/src/data-fetching";
+
+export async function data(ctx: PageContext): Promise {
+ let { unit_id } = ctx.routeParams;
+
+ if (Array.isArray(unit_id)) {
+ unit_id = unit_id[0];
+ } else if (typeof unit_id == "undefined") {
+ unit_id = "0";
+ }
+
+ const query: IdsFromUnit = await fetchIdsFromUnitId(parseInt(unit_id));
+
+ const { data: units, error: e } = await getSectionData({ id: unit_id }, 1);
+
+ // This is kind of crazy but it seems to work OK
+ const unit = Object.values(units[0])[0][0];
+
+ const errors = e == null ? [] : [e];
+ return { unit_id, unit, query, errors };
+}
+
+export interface UnitEditParams {
+ unit_id: string;
+ unit: UnitsView;
+ query: IdsFromUnit;
+ errors: PostgrestError[];
+}
diff --git a/pages/dev/column-editor/unit/@unit_id/strat-name/@strat_name_id/edit/+Page.ts b/pages/dev/column-editor/unit/@unit_id/strat-name/@strat_name_id/edit/+Page.ts
new file mode 100644
index 00000000..3bda973d
--- /dev/null
+++ b/pages/dev/column-editor/unit/@unit_id/strat-name/@strat_name_id/edit/+Page.ts
@@ -0,0 +1,40 @@
+import {
+ BasePage,
+ StratNameEditor,
+ StratNameI,
+ tableUpdate,
+} from "@macrostrat-web/column-builder";
+import h from "../stratname.module.scss";
+import { useData } from "vike-react/useData";
+import type { EditStratigraphicNameData } from "./+data";
+
+export default function EditStratigraphicName() {
+ const { strat_name, errors } = useData();
+
+ const persistChanges = async (
+ e: StratNameI,
+ changes: Partial
+ ) => {
+ const { data, error } = await tableUpdate("strat_names", {
+ changes,
+ id: e.id,
+ });
+
+ if (!error) {
+ return data[0];
+ } else {
+ console.error(error);
+ }
+ };
+
+ return h(BasePage, { query: props.query, errors }, [
+ h("h3", [
+ "Edit Stratigraphic Name and Hierarchy for ",
+ strat_name.strat_name,
+ " ",
+ strat_name.rank,
+ ]),
+ //@ts-ignore
+ h(StratNameEditor, { model: strat_name, persistChanges }),
+ ]);
+}
diff --git a/pages/dev/column-editor/unit/@unit_id/strat-name/@strat_name_id/edit/+data.ts b/pages/dev/column-editor/unit/@unit_id/strat-name/@strat_name_id/edit/+data.ts
new file mode 100644
index 00000000..842d97e3
--- /dev/null
+++ b/pages/dev/column-editor/unit/@unit_id/strat-name/@strat_name_id/edit/+data.ts
@@ -0,0 +1,38 @@
+import {
+ fetchIdsFromUnitId,
+ IdsFromUnit,
+ selectFirst,
+ StratNameI,
+} from "@macrostrat-web/column-builder";
+import { PostgrestError } from "@supabase/postgrest-js";
+import { PageContext } from "vike/types";
+
+export async function data(
+ ctx: PageContext
+): Promise {
+ let { strat_name_id, unit_id } = ctx.routeParams;
+
+ if (Array.isArray(unit_id)) {
+ unit_id = unit_id[0];
+ } else if (typeof unit_id == "undefined") {
+ unit_id = "0";
+ }
+ const query: IdsFromUnit = await fetchIdsFromUnitId(parseInt(unit_id));
+
+ const { firstData: strat_name, error } = await selectFirst(
+ "strat_names_ref",
+ {
+ match: { id: strat_name_id },
+ }
+ );
+ const errors = error == null ? [] : [error];
+ return { strat_name_id, strat_name, errors, unit_id, query };
+}
+
+export interface EditStratigraphicNameData {
+ strat_name_id: number;
+ strat_name: StratNameI;
+ unit_id: number;
+ query: IdsFromUnit;
+ errors: PostgrestError[];
+}
diff --git a/pages/dev/column-editor/unit/@unit_id/strat-name/@strat_name_id/new/+Page.ts b/pages/dev/column-editor/unit/@unit_id/strat-name/@strat_name_id/new/+Page.ts
new file mode 100644
index 00000000..e2dc1ab8
--- /dev/null
+++ b/pages/dev/column-editor/unit/@unit_id/strat-name/@strat_name_id/new/+Page.ts
@@ -0,0 +1,50 @@
+import {
+ BasePage,
+ StratNameEditor,
+ StratNameI,
+ tableInsert,
+ tableUpdate,
+} from "@macrostrat-web/column-builder";
+import h from "../stratname.module.scss";
+import { useData } from "vike-react/useData";
+import type { StratNameData } from "./+data";
+
+export default function Page() {
+ const { name, unit_id, query } = useData();
+ const persistChanges = async (e: StratNameI, c: Partial) => {
+ const { data, error } = await tableInsert("strat_names", e);
+
+ const strat_name_id: number = data ? data[0].id : null;
+
+ if (!strat_name_id) {
+ const { data, error } = await tableUpdate("units", {
+ changes: { strat_name_id: strat_name_id },
+ id: unit_id,
+ });
+
+ return data[0];
+ } else {
+ console.error(error);
+ }
+ };
+
+ let model: Partial = {};
+ if (name != undefined && typeof name == "string") {
+ model.strat_name = name;
+ }
+
+ const pageTitle =
+ name == undefined
+ ? "Make New Stratigraphic Name "
+ : "This Stratigraphic name doesn't exist in the database. Make New Stratigraphic Name";
+
+ return h(BasePage, { query, errors: [] }, [
+ h("h3", [pageTitle]),
+ //@ts-ignore
+ h(StratNameEditor, {
+ model,
+ persistChanges,
+ new_name: true,
+ }),
+ ]);
+}
diff --git a/pages/dev/column-editor/unit/@unit_id/strat-name/@strat_name_id/new/+data.ts b/pages/dev/column-editor/unit/@unit_id/strat-name/@strat_name_id/new/+data.ts
new file mode 100644
index 00000000..203a709c
--- /dev/null
+++ b/pages/dev/column-editor/unit/@unit_id/strat-name/@strat_name_id/new/+data.ts
@@ -0,0 +1,27 @@
+import {
+ fetchIdsFromUnitId,
+ IdsFromUnit,
+} from "@macrostrat-web/column-builder";
+
+export interface StratNameData {
+ name: string | undefined;
+ unit_id: number;
+ query: IdsFromUnit;
+}
+
+export async function getServerSideProps(
+ ctx: GetServerSidePropsContext
+): Promise {
+ let {
+ query: { unit_id },
+ } = ctx;
+ if (Array.isArray(unit_id)) {
+ unit_id = unit_id[0];
+ } else if (typeof unit_id == "undefined") {
+ unit_id = "0";
+ }
+
+ const query: IdsFromUnit = await fetchIdsFromUnitId(parseInt(unit_id));
+
+ return { props: { unit_id, query } };
+}
diff --git a/pages/dev/column-editor/unit/@unit_id/strat-name/@strat_name_id/stratname.module.scss b/pages/dev/column-editor/unit/@unit_id/strat-name/@strat_name_id/stratname.module.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/pages/dev/me/+Page.client.ts b/pages/dev/me/+Page.client.ts
new file mode 100644
index 00000000..0f44ef7d
--- /dev/null
+++ b/pages/dev/me/+Page.client.ts
@@ -0,0 +1,7 @@
+import h from "@macrostrat/hyper";
+import { DocumentationPage } from "~/layouts";
+import { AuthStatus } from "@macrostrat/auth-components";
+
+export function Page() {
+ return h(DocumentationPage, { title: "Login" }, [h(AuthStatus)]);
+}
diff --git a/pages/dev/paleo/map-style.ts b/pages/dev/paleo/map-style.ts
index 643ef570..06569f79 100644
--- a/pages/dev/paleo/map-style.ts
+++ b/pages/dev/paleo/map-style.ts
@@ -117,6 +117,20 @@ const lightStyle = {
},
},
],
+ fog: {
+ color: "#ffffff",
+ "space-color": [
+ "interpolate",
+ ["linear"],
+ ["zoom"],
+ 4,
+ "hsl(215, 28%, 64%)",
+ 7,
+ "hsl(209, 92%, 85%)",
+ ],
+ "star-intensity": ["interpolate", ["linear"], ["zoom"], 5, 0.35, 6, 0],
+ range: [5, 15],
+ },
} as mapboxgl.Style;
export function replaceSourcesForTileset(
diff --git a/pages/integrations/xdd/types/+Page.client.ts b/pages/integrations/xdd/types/+Page.client.ts
index d32ff03b..dd3def67 100644
--- a/pages/integrations/xdd/types/+Page.client.ts
+++ b/pages/integrations/xdd/types/+Page.client.ts
@@ -9,7 +9,6 @@ import {
ColorPicker,
} from "@macrostrat/data-sheet2";
import { asChromaColor } from "@macrostrat/color-utils";
-import { LoginButton } from "#/maps/ingestion/components/navbar";
import { AuthStatus } from "@macrostrat/auth-components";
const colorField = {
diff --git a/server/vike-handler.ts b/server/vike-handler.ts
index bf50f31a..12d71d95 100644
--- a/server/vike-handler.ts
+++ b/server/vike-handler.ts
@@ -35,17 +35,16 @@ export async function vikeHandler<
async function getUserFromCookie(cookies: Record) {
// Pull out the authorization cookie and decrypt it
- let user: any = undefined;
+ let user: any = null;
try {
const authHeader = cookies?.["access_token"];
const secret = new TextEncoder().encode(process.env.SECRET_KEY);
const jwt = authHeader.substring(7, authHeader.length);
- // We probably don't need to verify the JWT on each request.
- // OR we can pass the user obju
- user = (await jose.jwtVerify(jwt, secret)).payload;
+ let res = await jose.jwtVerify(jwt, secret);
+ user = res.payload;
console.log("User", user);
} catch (e) {
- // I don't care if it fails, it just means the user isn't logged in
+ // If it fails, the user isn't logged in. Could also have an expired token...
console.log("Anonymous user");
}
@@ -67,9 +66,9 @@ function getCookies(request: Request) {
function synthesizeConfigFromEnvironment() {
/** Creates a mapping of environment variables that start with VITE_,
* and returns them as an object. This allows us to pass environment
- * variables to the client.
+ * variables to the client at runtime.
*
- * TODO: Ideally this would be defined in library code.
+ * TODO: Ideally this would be defined in a library.
* */
const env = {};
for (const key of Object.keys(process.env)) {
diff --git a/src/vike.d.ts b/src/vike.d.ts
index 6dec24e7..1d6c74d3 100644
--- a/src/vike.d.ts
+++ b/src/vike.d.ts
@@ -51,4 +51,4 @@ declare global {
}
// Tell TypeScript this file isn't an ambient module:
-export { PageContext, PageContextClient, PageContextServer };
+export {};
diff --git a/vite.config.ts b/vite.config.ts
index 2ddf4f11..32893bc6 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -100,7 +100,12 @@ export default defineConfig({
// If not building for server context
},
ssr: {
- noExternal: ["labella", "@supabase/postgrest-js"],
+ // https://vike.dev/broken-npm-package
+ noExternal: [
+ "labella",
+ "@supabase/postgrest-js",
+ "@macrostrat/auth-components",
+ ],
},
css: {
preprocessorOptions: {
diff --git a/yarn.lock b/yarn.lock
index 6cdfc2c0..fda60ba0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3115,6 +3115,15 @@ __metadata:
languageName: node
linkType: hard
+"@blueprintjs/colors@npm:^4.2.1":
+ version: 4.2.1
+ resolution: "@blueprintjs/colors@npm:4.2.1"
+ dependencies:
+ tslib: "npm:~2.5.0"
+ checksum: 10/4bac17586b88b975dda443098e1c70ef1ba7c30cedadec9985491c64d9de1e7e1a7205dbc724f5671b80e2036139f5d5288542c310a864f973a9b64b4819fb47
+ languageName: node
+ linkType: hard
+
"@blueprintjs/colors@npm:^5.1.1":
version: 5.1.1
resolution: "@blueprintjs/colors@npm:5.1.1"
@@ -3124,12 +3133,41 @@ __metadata:
languageName: node
linkType: hard
-"@blueprintjs/colors@npm:^5.1.2":
- version: 5.1.2
- resolution: "@blueprintjs/colors@npm:5.1.2"
+"@blueprintjs/colors@npm:^5.1.3":
+ version: 5.1.3
+ resolution: "@blueprintjs/colors@npm:5.1.3"
dependencies:
tslib: "npm:~2.6.2"
- checksum: 10/ef9aa91eaeb78c9738216a0c7b5884d417e4e21684c16d0a7a782939df9e9219d7b570ae1058311ff4bd0cee12ae3a8f7126be9c6fd3f7492df224f3c7b09259
+ checksum: 10/50c02828ec7671dcb42b2574d21c9669ab9d4c118d86cbd409207b635d622b97396b5cf25343dfcaf4fdc4fc654fa04eaeeaa68e0db21e4cd2085b56cee5bee0
+ languageName: node
+ linkType: hard
+
+"@blueprintjs/core@npm:^4.20.2":
+ version: 4.20.2
+ resolution: "@blueprintjs/core@npm:4.20.2"
+ dependencies:
+ "@blueprintjs/colors": "npm:^4.2.1"
+ "@blueprintjs/icons": "npm:^4.16.0"
+ "@juggle/resize-observer": "npm:^3.4.0"
+ "@types/dom4": "npm:^2.0.2"
+ classnames: "npm:^2.3.1"
+ dom4: "npm:^2.1.5"
+ normalize.css: "npm:^8.0.1"
+ popper.js: "npm:^1.16.1"
+ react-popper: "npm:^1.3.11"
+ react-transition-group: "npm:^4.4.5"
+ tslib: "npm:~2.5.0"
+ peerDependencies:
+ "@types/react": ^16.14.32 || 17 || 18
+ react: ^16.8 || 17 || 18
+ react-dom: ^16.8 || 17 || 18
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ bin:
+ upgrade-blueprint-2.0.0-rename: scripts/upgrade-blueprint-2.0.0-rename.sh
+ upgrade-blueprint-3.0.0-rename: scripts/upgrade-blueprint-3.0.0-rename.sh
+ checksum: 10/02fad0912fcac1bb97b18e847f68fcf5aa62465f9c002c4f56f21aded92cba7d6fcd1c93c3d2453a427873376dca7b1bab94cd0a3c322429969c1f9101ef7611
languageName: node
linkType: hard
@@ -3189,12 +3227,40 @@ __metadata:
languageName: node
linkType: hard
-"@blueprintjs/core@npm:^5.13.1":
- version: 5.13.1
- resolution: "@blueprintjs/core@npm:5.13.1"
+"@blueprintjs/core@npm:^5.10.5":
+ version: 5.10.5
+ resolution: "@blueprintjs/core@npm:5.10.5"
+ dependencies:
+ "@blueprintjs/colors": "npm:^5.1.1"
+ "@blueprintjs/icons": "npm:^5.10.0"
+ "@popperjs/core": "npm:^2.11.8"
+ classnames: "npm:^2.3.1"
+ normalize.css: "npm:^8.0.1"
+ react-popper: "npm:^2.3.0"
+ react-transition-group: "npm:^4.4.5"
+ react-uid: "npm:^2.3.3"
+ tslib: "npm:~2.6.2"
+ use-sync-external-store: "npm:^1.2.0"
+ peerDependencies:
+ "@types/react": ^16.14.41 || 17 || 18
+ react: ^16.8 || 17 || 18
+ react-dom: ^16.8 || 17 || 18
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ bin:
+ upgrade-blueprint-2.0.0-rename: scripts/upgrade-blueprint-2.0.0-rename.sh
+ upgrade-blueprint-3.0.0-rename: scripts/upgrade-blueprint-3.0.0-rename.sh
+ checksum: 10/1f8719dd69a2c306f3b2dff3f611d70c89f50e7085c1b5569fc0e5fa6df384311148f62c8e932c4f543ded6a7bfc47a40d6aad20417baf1c4bd0924797ec3a50
+ languageName: node
+ linkType: hard
+
+"@blueprintjs/core@npm:^5.14.0":
+ version: 5.14.0
+ resolution: "@blueprintjs/core@npm:5.14.0"
dependencies:
- "@blueprintjs/colors": "npm:^5.1.2"
- "@blueprintjs/icons": "npm:^5.13.0"
+ "@blueprintjs/colors": "npm:^5.1.3"
+ "@blueprintjs/icons": "npm:^5.14.0"
"@popperjs/core": "npm:^2.11.8"
classnames: "npm:^2.3.1"
normalize.css: "npm:^8.0.1"
@@ -3213,17 +3279,17 @@ __metadata:
bin:
upgrade-blueprint-2.0.0-rename: scripts/upgrade-blueprint-2.0.0-rename.sh
upgrade-blueprint-3.0.0-rename: scripts/upgrade-blueprint-3.0.0-rename.sh
- checksum: 10/3e6fe60bd35d6ede91e0525683234e291dd9f351ae288dda046d88aaee9a38fb2c49bfbb764437a967c3067c6822b059005f4cddb6168ef68d7a6c96db71284a
+ checksum: 10/71f57ad412e858621e3542c99e8ef517f37c07bab75e0954211b926aa03944c229d97d147bb6dedd498c8b6d1ece25dc5accb2cc8439fa3fe2683546546ef0b6
languageName: node
linkType: hard
"@blueprintjs/datetime2@npm:^2.3.11":
- version: 2.3.11
- resolution: "@blueprintjs/datetime2@npm:2.3.11"
+ version: 2.3.13
+ resolution: "@blueprintjs/datetime2@npm:2.3.13"
dependencies:
- "@blueprintjs/core": "npm:^5.13.1"
- "@blueprintjs/datetime": "npm:^5.3.11"
- "@blueprintjs/icons": "npm:^5.13.0"
+ "@blueprintjs/core": "npm:^5.14.0"
+ "@blueprintjs/datetime": "npm:^5.3.13"
+ "@blueprintjs/icons": "npm:^5.14.0"
classnames: "npm:^2.3.1"
date-fns: "npm:^2.28.0"
react-day-picker: "npm:^8.10.0"
@@ -3236,17 +3302,17 @@ __metadata:
peerDependenciesMeta:
"@types/react":
optional: true
- checksum: 10/7a3e6677deb57c50043f85097560037043963ea219e1720b0e52baef5f6096c415423a20b5e0db655ea65b735145b098d9faa67900a984df567a2045b0577b15
+ checksum: 10/293e2f698d5dffa4296c863dd5438120dbada8694d58a5a0aaf868545b829d6b13dfc14e6e7c7c30b6c8de9c16695410b727b5f8be7b46a7724e8cdf6d63c3da
languageName: node
linkType: hard
-"@blueprintjs/datetime@npm:^5.3.11":
- version: 5.3.11
- resolution: "@blueprintjs/datetime@npm:5.3.11"
+"@blueprintjs/datetime@npm:^5.3.13":
+ version: 5.3.13
+ resolution: "@blueprintjs/datetime@npm:5.3.13"
dependencies:
- "@blueprintjs/core": "npm:^5.13.1"
- "@blueprintjs/icons": "npm:^5.13.0"
- "@blueprintjs/select": "npm:^5.2.5"
+ "@blueprintjs/core": "npm:^5.14.0"
+ "@blueprintjs/icons": "npm:^5.14.0"
+ "@blueprintjs/select": "npm:^5.3.1"
classnames: "npm:^2.3.1"
date-fns: "npm:^2.28.0"
date-fns-tz: "npm:^2.0.0"
@@ -3259,13 +3325,24 @@ __metadata:
peerDependenciesMeta:
"@types/react":
optional: true
- checksum: 10/c92786cea9e8ee3b09037e5a5557de8c30ef732e96b35896b3a7a00f8d8eb38d074727dcf68e42725c839354907a35e969ed8df5d4b7daf2812eb020dccad888
+ checksum: 10/950b8748c685cb797011ef6037f9091a0a90c6ba278b457d4517d573497d86674428df51b1ddaef2a35ebb554aaa0210467188375d4972b78145ea521e9959a9
languageName: node
linkType: hard
-"@blueprintjs/icons@npm:^5.13.0":
- version: 5.13.0
- resolution: "@blueprintjs/icons@npm:5.13.0"
+"@blueprintjs/icons@npm:^4.16.0":
+ version: 4.16.0
+ resolution: "@blueprintjs/icons@npm:4.16.0"
+ dependencies:
+ change-case: "npm:^4.1.2"
+ classnames: "npm:^2.3.1"
+ tslib: "npm:~2.5.0"
+ checksum: 10/4750fafed488c7eb9f698fb20ccb57b2584a7c617a032782464339d93bcac9eb1435f130f701111ca614a821607d64b9f447f8f9016fc55de3d7252469201e6a
+ languageName: node
+ linkType: hard
+
+"@blueprintjs/icons@npm:^5.10.0":
+ version: 5.10.0
+ resolution: "@blueprintjs/icons@npm:5.10.0"
dependencies:
change-case: "npm:^4.1.2"
classnames: "npm:^2.3.1"
@@ -3277,7 +3354,25 @@ __metadata:
peerDependenciesMeta:
"@types/react":
optional: true
- checksum: 10/0e962fe73412c351466dd24f3ffff4f382af8f23de9dcf1d245e71cf0d2ee1e401f767fcf36f9f6df9d604e3b4a2874f6f0ae92e489d40d3b8abddfc0c352c66
+ checksum: 10/745bfe03509406ffc449a32812115f6dc03c3945ab23904102e5330e47d57cb953f6e6bbc30c7679b5eec2372c0773be2cf7cd85836c8966774660a95a44caa9
+ languageName: node
+ linkType: hard
+
+"@blueprintjs/icons@npm:^5.14.0":
+ version: 5.14.0
+ resolution: "@blueprintjs/icons@npm:5.14.0"
+ dependencies:
+ change-case: "npm:^4.1.2"
+ classnames: "npm:^2.3.1"
+ tslib: "npm:~2.6.2"
+ peerDependencies:
+ "@types/react": ^16.14.41 || 17 || 18
+ react: ^16.8 || 17 || 18
+ react-dom: ^16.8 || 17 || 18
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/7da68febcb07ef63e9ee32c88d7e2325612f13cd43e9feb787d8f062fb3cafc6912370fa1d337d93a53891ddadfa0d09fbc08a69e3499b99ffd7d79f2456e09c
languageName: node
linkType: hard
@@ -3299,6 +3394,28 @@ __metadata:
languageName: node
linkType: hard
+"@blueprintjs/popover2@npm:^1.2.1":
+ version: 1.14.11
+ resolution: "@blueprintjs/popover2@npm:1.14.11"
+ dependencies:
+ "@blueprintjs/core": "npm:^4.20.2"
+ "@juggle/resize-observer": "npm:^3.4.0"
+ "@popperjs/core": "npm:^2.11.7"
+ classnames: "npm:^2.3.1"
+ dom4: "npm:^2.1.5"
+ react-popper: "npm:^2.3.0"
+ tslib: "npm:~2.5.0"
+ peerDependencies:
+ "@types/react": ^16.14.32 || 17 || 18
+ react: ^16.8 || 17 || 18
+ react-dom: ^16.8 || 17 || 18
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/0ef9a112ab7756ddbda951290e2f79c34673adc80d7cf878664288024c2c6de3f27eecd3242d3bff75112a39df1b852ae7ad0e0662ab4e91a8e5c202aea378c9
+ languageName: node
+ linkType: hard
+
"@blueprintjs/select@npm:^5.1.4":
version: 5.1.4
resolution: "@blueprintjs/select@npm:5.1.4"
@@ -3318,12 +3435,12 @@ __metadata:
languageName: node
linkType: hard
-"@blueprintjs/select@npm:^5.2.5":
- version: 5.2.5
- resolution: "@blueprintjs/select@npm:5.2.5"
+"@blueprintjs/select@npm:^5.2.1":
+ version: 5.2.1
+ resolution: "@blueprintjs/select@npm:5.2.1"
dependencies:
- "@blueprintjs/core": "npm:^5.13.1"
- "@blueprintjs/icons": "npm:^5.13.0"
+ "@blueprintjs/core": "npm:^5.10.5"
+ "@blueprintjs/icons": "npm:^5.10.0"
classnames: "npm:^2.3.1"
tslib: "npm:~2.6.2"
peerDependencies:
@@ -3333,7 +3450,26 @@ __metadata:
peerDependenciesMeta:
"@types/react":
optional: true
- checksum: 10/2bf9306e942bd17e97d6a6ecb7fbacd61f042b35a931e2edca7308e05c5466fca7e9e8d02f77c5a7477d53560b4b943f26cde079f487338abf51914752eddbac
+ checksum: 10/b8a3a98fc4383d1fc1d683efdff0e64b26990af439c398fedb37544c7cf5adac5b91ee9d0c0ef7ee62e7befe5988e7a41f11beaa6545cb5db3e0b8c2932ff575
+ languageName: node
+ linkType: hard
+
+"@blueprintjs/select@npm:^5.3.1":
+ version: 5.3.1
+ resolution: "@blueprintjs/select@npm:5.3.1"
+ dependencies:
+ "@blueprintjs/core": "npm:^5.14.0"
+ "@blueprintjs/icons": "npm:^5.14.0"
+ classnames: "npm:^2.3.1"
+ tslib: "npm:~2.6.2"
+ peerDependencies:
+ "@types/react": ^16.14.41 || 17 || 18
+ react: ^16.8 || 17 || 18
+ react-dom: ^16.8 || 17 || 18
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10/9b24393a74e1b657affd7ce2dd2fbb57adca902d429fd7f7b8648208792e0b4a72a14a0602d2c1496e3c6b40f25affa57f2d1e775b905f0df709828dbfe1fca0
languageName: node
linkType: hard
@@ -3415,9 +3551,9 @@ __metadata:
linkType: hard
"@bufbuild/protobuf@npm:^2.0.0":
- version: 2.1.0
- resolution: "@bufbuild/protobuf@npm:2.1.0"
- checksum: 10/de780b67a36c1066c51cc1214eb15facb03619f08ec59f9c9ebff034ed7838069010739e615a2ee8f31b555127c554a1e6421f7d1d3d718dbcdd47c458cefef6
+ version: 2.2.2
+ resolution: "@bufbuild/protobuf@npm:2.2.2"
+ checksum: 10/f739b7787f3e978db7ed5eff55fb15ec6fea3d7ab9ae8f1de9e03375e786facd4c8bfd09ea4f9558bf29f8521b524781bfeec6960fc910e7d1309c4a2329317b
languageName: node
linkType: hard
@@ -4849,7 +4985,7 @@ __metadata:
languageName: node
linkType: hard
-"@eslint-community/eslint-utils@npm:^4.4.0":
+"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0":
version: 4.4.0
resolution: "@eslint-community/eslint-utils@npm:4.4.0"
dependencies:
@@ -4867,6 +5003,37 @@ __metadata:
languageName: node
linkType: hard
+"@eslint-community/regexpp@npm:^4.6.1":
+ version: 4.11.0
+ resolution: "@eslint-community/regexpp@npm:4.11.0"
+ checksum: 10/f053f371c281ba173fe6ee16dbc4fe544c84870d58035ccca08dba7f6ce1830d895ce3237a0db89ba37616524775dca82f1c502066b58e2d5712d7f87f5ba17c
+ languageName: node
+ linkType: hard
+
+"@eslint/eslintrc@npm:^2.1.4":
+ version: 2.1.4
+ resolution: "@eslint/eslintrc@npm:2.1.4"
+ dependencies:
+ ajv: "npm:^6.12.4"
+ debug: "npm:^4.3.2"
+ espree: "npm:^9.6.0"
+ globals: "npm:^13.19.0"
+ ignore: "npm:^5.2.0"
+ import-fresh: "npm:^3.2.1"
+ js-yaml: "npm:^4.1.0"
+ minimatch: "npm:^3.1.2"
+ strip-json-comments: "npm:^3.1.1"
+ checksum: 10/7a3b14f4b40fc1a22624c3f84d9f467a3d9ea1ca6e9a372116cb92507e485260359465b58e25bcb6c9981b155416b98c9973ad9b796053fd7b3f776a6946bce8
+ languageName: node
+ linkType: hard
+
+"@eslint/js@npm:8.57.0":
+ version: 8.57.0
+ resolution: "@eslint/js@npm:8.57.0"
+ checksum: 10/3c501ce8a997cf6cbbaf4ed358af5492875e3550c19b9621413b82caa9ae5382c584b0efa79835639e6e0ddaa568caf3499318e5bdab68643ef4199dce5eb0a0
+ languageName: node
+ linkType: hard
+
"@hattip/core@npm:0.0.45, @hattip/core@npm:^0.0.45":
version: 0.0.45
resolution: "@hattip/core@npm:0.0.45"
@@ -4907,6 +5074,44 @@ __metadata:
languageName: node
linkType: hard
+"@humanwhocodes/config-array@npm:^0.11.14":
+ version: 0.11.14
+ resolution: "@humanwhocodes/config-array@npm:0.11.14"
+ dependencies:
+ "@humanwhocodes/object-schema": "npm:^2.0.2"
+ debug: "npm:^4.3.1"
+ minimatch: "npm:^3.0.5"
+ checksum: 10/3ffb24ecdfab64014a230e127118d50a1a04d11080cbb748bc21629393d100850496456bbcb4e8c438957fe0934430d731042f1264d6a167b62d32fc2863580a
+ languageName: node
+ linkType: hard
+
+"@humanwhocodes/module-importer@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "@humanwhocodes/module-importer@npm:1.0.1"
+ checksum: 10/e993950e346331e5a32eefb27948ecdee2a2c4ab3f072b8f566cd213ef485dd50a3ca497050608db91006f5479e43f91a439aef68d2a313bd3ded06909c7c5b3
+ languageName: node
+ linkType: hard
+
+"@humanwhocodes/object-schema@npm:^2.0.2":
+ version: 2.0.3
+ resolution: "@humanwhocodes/object-schema@npm:2.0.3"
+ checksum: 10/05bb99ed06c16408a45a833f03a732f59bf6184795d4efadd33238ff8699190a8c871ad1121241bb6501589a9598dc83bf25b99dcbcf41e155cdf36e35e937a3
+ languageName: node
+ linkType: hard
+
+"@hypnosphi/create-react-context@npm:^0.3.1":
+ version: 0.3.1
+ resolution: "@hypnosphi/create-react-context@npm:0.3.1"
+ dependencies:
+ gud: "npm:^1.0.0"
+ warning: "npm:^4.0.3"
+ peerDependencies:
+ prop-types: ^15.0.0
+ react: ">=0.14.0"
+ checksum: 10/79b697d150f9b4aa6cadfb8026f20e023c05fefc4be841b1cdd5567c3fd970ccaae84a0ea6279f579fe2cc9844c201e80713a2691b24e59cc7d6925fa8130c34
+ languageName: node
+ linkType: hard
+
"@iarna/cli@npm:^2.1.0":
version: 2.1.0
resolution: "@iarna/cli@npm:2.1.0"
@@ -5273,7 +5478,7 @@ __metadata:
languageName: node
linkType: hard
-"@juggle/resize-observer@npm:^3.3.1":
+"@juggle/resize-observer@npm:^3.3.1, @juggle/resize-observer@npm:^3.4.0":
version: 3.4.0
resolution: "@juggle/resize-observer@npm:3.4.0"
checksum: 10/73d1d00ee9132fb6f0aea0531940a6b93603e935590bd450fc6285a328d906102eeeb95dea77b2edac0e779031a9708aa8c82502bd298ee4dd26e7dff48f397a
@@ -5421,17 +5626,35 @@ __metadata:
languageName: node
linkType: hard
-"@macrostrat-web/data-sheet-test@workspace:*, @macrostrat-web/data-sheet-test@workspace:packages/data-sheet-test":
+"@macrostrat-web/column-builder@workspace:*, @macrostrat-web/column-builder@workspace:packages/column-builder":
version: 0.0.0-use.local
- resolution: "@macrostrat-web/data-sheet-test@workspace:packages/data-sheet-test"
+ resolution: "@macrostrat-web/column-builder@workspace:packages/column-builder"
dependencies:
- "@blueprintjs/core": "npm:^5.10.2"
- "@blueprintjs/table": "npm:^5.1.4"
- "@macrostrat/data-sheet": "workspace:*"
- "@macrostrat/hyper": "npm:^2.2.1"
+ "@blueprintjs/core": "npm:^5.10.5"
+ "@blueprintjs/icons": "npm:^5.10.0"
+ "@blueprintjs/popover2": "npm:^1.2.1"
+ "@blueprintjs/select": "npm:^5.2.1"
+ "@macrostrat-web/settings": "workspace:*"
+ "@macrostrat/column-components": "workspace:*"
+ "@macrostrat/data-components": "workspace:*"
+ "@macrostrat/form-components": "workspace:*"
+ "@macrostrat/hyper": "npm:^2.0.1"
"@macrostrat/ui-components": "workspace:*"
- chroma-js: "npm:^2.4.2"
- react: "npm:^18.2.0"
+ "@mapbox/mapbox-gl-draw": "npm:^1.3.0"
+ "@supabase/postgrest-js": "npm:^0.36.0"
+ "@types/mapbox__mapbox-gl-draw": "npm:^1.2.3"
+ "@types/node": "npm:^17.0.10"
+ "@types/react": "npm:^17"
+ "@types/react-beautiful-dnd": "npm:^13.1.2"
+ axios: "npm:^0.27.2"
+ cross-fetch: "npm:^3.1.5"
+ eslint: "npm:^8.7.0"
+ eslint-config-next: "npm:^12.0.8"
+ mapbox-gl: "npm:^2.8.2"
+ react: "npm:^18"
+ react-beautiful-dnd: "npm:^13.1.0"
+ react-color: "npm:^2.19.3"
+ typescript: "npm:^4.5.4"
languageName: unknown
linkType: soft
@@ -5742,7 +5965,7 @@ __metadata:
languageName: node
linkType: hard
-"@macrostrat/data-components@workspace:deps/web-components/packages/data-components":
+"@macrostrat/data-components@workspace:*, @macrostrat/data-components@workspace:deps/web-components/packages/data-components":
version: 0.0.0-use.local
resolution: "@macrostrat/data-components@workspace:deps/web-components/packages/data-components"
dependencies:
@@ -5792,7 +6015,7 @@ __metadata:
languageName: unknown
linkType: soft
-"@macrostrat/data-sheet@workspace:*, @macrostrat/data-sheet@workspace:deps/web-components/packages/data-sheet":
+"@macrostrat/data-sheet@workspace:deps/web-components/packages/data-sheet":
version: 0.0.0-use.local
resolution: "@macrostrat/data-sheet@workspace:deps/web-components/packages/data-sheet"
dependencies:
@@ -5827,7 +6050,7 @@ __metadata:
languageName: unknown
linkType: soft
-"@macrostrat/form-components@workspace:deps/web-components/packages/form-components":
+"@macrostrat/form-components@workspace:*, @macrostrat/form-components@workspace:deps/web-components/packages/form-components":
version: 0.0.0-use.local
resolution: "@macrostrat/form-components@workspace:deps/web-components/packages/form-components"
dependencies:
@@ -5962,7 +6185,7 @@ __metadata:
dependencies:
"@macrostrat/color-utils": "npm:^1.0.0"
"@macrostrat/hyper": "npm:^3.0.0"
- "@macrostrat/mapbox-react": "npm:^2.2.3"
+ "@macrostrat/mapbox-react": "npm:^2.4.0"
"@macrostrat/mapbox-utils": "npm:^1.3.2"
"@macrostrat/ui-components": "npm:^4.0.4"
"@mapbox/tilebelt": "npm:^2.0.0"
@@ -5984,7 +6207,7 @@ __metadata:
languageName: unknown
linkType: soft
-"@macrostrat/mapbox-react@npm:^2.2.3, @macrostrat/mapbox-react@workspace:*, @macrostrat/mapbox-react@workspace:^2.1.0, @macrostrat/mapbox-react@workspace:deps/web-components/packages/mapbox-react":
+"@macrostrat/mapbox-react@npm:^2.4.0, @macrostrat/mapbox-react@workspace:*, @macrostrat/mapbox-react@workspace:^2.1.0, @macrostrat/mapbox-react@workspace:deps/web-components/packages/mapbox-react":
version: 0.0.0-use.local
resolution: "@macrostrat/mapbox-react@workspace:deps/web-components/packages/mapbox-react"
dependencies:
@@ -5999,6 +6222,7 @@ __metadata:
mapbox-gl: "npm:^2.15.0"
mapbox-gl-controls: "npm:^2.3.5"
parcel: "npm:^2.6.2"
+ zustand: "npm:^5.0.1"
peerDependencies:
"@blueprintjs/core": ^3||^4||^5.10.2
react: ^16||^17||^18
@@ -6131,7 +6355,7 @@ __metadata:
"@blueprintjs/table": "npm:^5.1.4"
"@lagunovsky/redux-react-router": "npm:^3.2.0"
"@loadable/component": "npm:^5.14.1"
- "@macrostrat-web/data-sheet-test": "workspace:*"
+ "@macrostrat-web/column-builder": "workspace:*"
"@macrostrat-web/globe": "workspace:*"
"@macrostrat-web/lithology-hierarchy": "workspace:*"
"@macrostrat-web/map-utils": "workspace:*"
@@ -6539,6 +6763,15 @@ __metadata:
languageName: node
linkType: hard
+"@next/eslint-plugin-next@npm:12.3.4":
+ version: 12.3.4
+ resolution: "@next/eslint-plugin-next@npm:12.3.4"
+ dependencies:
+ glob: "npm:7.1.7"
+ checksum: 10/173bc404d7199c127b29feee78876dc4d710e231faf8f0bff9b77b1482268d31bfe4ede866b1824a87e600a14e090a5e14e02ea677913fcac6724e3a50f7b60a
+ languageName: node
+ linkType: hard
+
"@nodelib/fs.scandir@npm:2.1.5":
version: 2.1.5
resolution: "@nodelib/fs.scandir@npm:2.1.5"
@@ -6556,7 +6789,7 @@ __metadata:
languageName: node
linkType: hard
-"@nodelib/fs.walk@npm:^1.2.3":
+"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8":
version: 1.2.8
resolution: "@nodelib/fs.walk@npm:1.2.8"
dependencies:
@@ -8271,7 +8504,7 @@ __metadata:
languageName: node
linkType: hard
-"@popperjs/core@npm:^2.11.8, @popperjs/core@npm:^2.9.3":
+"@popperjs/core@npm:^2.11.7, @popperjs/core@npm:^2.11.8, @popperjs/core@npm:^2.9.3":
version: 2.11.8
resolution: "@popperjs/core@npm:2.11.8"
checksum: 10/ddd16090cde777aaf102940f05d0274602079a95ad9805bd20bc55dcc7c3a2ba1b99dd5c73e5cc2753c3d31250ca52a67d58059459d7d27debb983a9f552936c
@@ -9244,6 +9477,13 @@ __metadata:
languageName: node
linkType: hard
+"@rushstack/eslint-patch@npm:^1.1.3":
+ version: 1.10.3
+ resolution: "@rushstack/eslint-patch@npm:1.10.3"
+ checksum: 10/e1986178618bfb5fb636a54c420a7c359879d7aed6a0e456333a92fdc93e0e7a9a914114284308317cdc75e522c0696f760cd6d0b77409ed8b9633e75f096628
+ languageName: node
+ linkType: hard
+
"@semantic-release/commit-analyzer@npm:^6.1.0":
version: 6.3.3
resolution: "@semantic-release/commit-analyzer@npm:6.3.3"
@@ -9395,6 +9635,15 @@ __metadata:
languageName: node
linkType: hard
+"@supabase/postgrest-js@npm:^0.36.0":
+ version: 0.36.2
+ resolution: "@supabase/postgrest-js@npm:0.36.2"
+ dependencies:
+ cross-fetch: "npm:^3.0.6"
+ checksum: 10/7adc59ece6a16741566cb29963f4ed69042ace6fa30666501665ee4b5ecb3b571b964a998324ec614af79b464ca41733e357577050b7437f2767f722896c485e
+ languageName: node
+ linkType: hard
+
"@supabase/postgrest-js@npm:^1.11.0":
version: 1.11.0
resolution: "@supabase/postgrest-js@npm:1.11.0"
@@ -10679,6 +10928,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/dom4@npm:^2.0.2":
+ version: 2.0.4
+ resolution: "@types/dom4@npm:2.0.4"
+ checksum: 10/f64228429058eb26d728baa923dd353ce9dd5fd64f391e6619f6d2a3cfbecd0566730278c81d241b936f71961d3f1fd9a7932d7081f1232f1d6a218af89ea658
+ languageName: node
+ linkType: hard
+
"@types/domhandler@npm:2.4.1":
version: 2.4.1
resolution: "@types/domhandler@npm:2.4.1"
@@ -10953,6 +11209,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/json5@npm:^0.0.29":
+ version: 0.0.29
+ resolution: "@types/json5@npm:0.0.29"
+ checksum: 10/4e5aed58cabb2bbf6f725da13421aa50a49abb6bc17bfab6c31b8774b073fa7b50d557c61f961a09a85f6056151190f8ac95f13f5b48136ba5841f7d4484ec56
+ languageName: node
+ linkType: hard
+
"@types/keyv@npm:^3.1.1, @types/keyv@npm:^3.1.4":
version: 3.1.4
resolution: "@types/keyv@npm:3.1.4"
@@ -11076,6 +11339,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/node@npm:^17.0.10":
+ version: 17.0.45
+ resolution: "@types/node@npm:17.0.45"
+ checksum: 10/b45fff7270b5e81be19ef91a66b764a8b21473a97a8d211218a52e3426b79ad48f371819ab9153370756b33ba284e5c875463de4d2cf48a472e9098d7f09e8a2
+ languageName: node
+ linkType: hard
+
"@types/normalize-package-data@npm:^2.4.0":
version: 2.4.1
resolution: "@types/normalize-package-data@npm:2.4.1"
@@ -11141,6 +11411,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/react-beautiful-dnd@npm:^13.1.2":
+ version: 13.1.8
+ resolution: "@types/react-beautiful-dnd@npm:13.1.8"
+ dependencies:
+ "@types/react": "npm:*"
+ checksum: 10/cb8a182ed0ea6f680c7c343fcb4e54237437ca90dc88c2a70f4a203ec8ad0740e389e3ab7772c8cc1479f05e5a046bccbc33d54055b94e0fe5b22be030ab23d2
+ languageName: node
+ linkType: hard
+
"@types/react-dom@npm:<18.0.0, @types/react-dom@npm:^17.0.16":
version: 17.0.20
resolution: "@types/react-dom@npm:17.0.20"
@@ -11472,6 +11751,23 @@ __metadata:
languageName: node
linkType: hard
+"@typescript-eslint/parser@npm:^5.21.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/parser@npm:5.62.0"
+ dependencies:
+ "@typescript-eslint/scope-manager": "npm:5.62.0"
+ "@typescript-eslint/types": "npm:5.62.0"
+ "@typescript-eslint/typescript-estree": "npm:5.62.0"
+ debug: "npm:^4.3.4"
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10/b6ca629d8f4e6283ff124501731cc886703eb4ce2c7d38b3e4110322ea21452b9d9392faf25be6bd72f54b89de7ffc72a40d9b159083ac54345a3d04b4fa5394
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/parser@npm:^6.3.0":
version: 6.7.2
resolution: "@typescript-eslint/parser@npm:6.7.2"
@@ -11490,6 +11786,16 @@ __metadata:
languageName: node
linkType: hard
+"@typescript-eslint/scope-manager@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/scope-manager@npm:5.62.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:5.62.0"
+ "@typescript-eslint/visitor-keys": "npm:5.62.0"
+ checksum: 10/e827770baa202223bc0387e2fd24f630690809e460435b7dc9af336c77322290a770d62bd5284260fa881c86074d6a9fd6c97b07382520b115f6786b8ed499da
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/scope-manager@npm:6.7.2":
version: 6.7.2
resolution: "@typescript-eslint/scope-manager@npm:6.7.2"
@@ -11517,6 +11823,13 @@ __metadata:
languageName: node
linkType: hard
+"@typescript-eslint/types@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/types@npm:5.62.0"
+ checksum: 10/24e8443177be84823242d6729d56af2c4b47bfc664dd411a1d730506abf2150d6c31bdefbbc6d97c8f91043e3a50e0c698239dcb145b79bb6b0c34469aaf6c45
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/types@npm:6.7.2":
version: 6.7.2
resolution: "@typescript-eslint/types@npm:6.7.2"
@@ -11524,6 +11837,24 @@ __metadata:
languageName: node
linkType: hard
+"@typescript-eslint/typescript-estree@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/typescript-estree@npm:5.62.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:5.62.0"
+ "@typescript-eslint/visitor-keys": "npm:5.62.0"
+ debug: "npm:^4.3.4"
+ globby: "npm:^11.1.0"
+ is-glob: "npm:^4.0.3"
+ semver: "npm:^7.3.7"
+ tsutils: "npm:^3.21.0"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10/06c975eb5f44b43bd19fadc2e1023c50cf87038fe4c0dd989d4331c67b3ff509b17fa60a3251896668ab4d7322bdc56162a9926971218d2e1a1874d2bef9a52e
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/typescript-estree@npm:6.7.2":
version: 6.7.2
resolution: "@typescript-eslint/typescript-estree@npm:6.7.2"
@@ -11559,6 +11890,16 @@ __metadata:
languageName: node
linkType: hard
+"@typescript-eslint/visitor-keys@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/visitor-keys@npm:5.62.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:5.62.0"
+ eslint-visitor-keys: "npm:^3.3.0"
+ checksum: 10/dc613ab7569df9bbe0b2ca677635eb91839dfb2ca2c6fa47870a5da4f160db0b436f7ec0764362e756d4164e9445d49d5eb1ff0b87f4c058946ae9d8c92eb388
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/visitor-keys@npm:6.7.2":
version: 6.7.2
resolution: "@typescript-eslint/visitor-keys@npm:6.7.2"
@@ -11569,6 +11910,13 @@ __metadata:
languageName: node
linkType: hard
+"@ungap/structured-clone@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "@ungap/structured-clone@npm:1.2.0"
+ checksum: 10/c6fe89a505e513a7592e1438280db1c075764793a2397877ff1351721fe8792a966a5359769e30242b3cd023f2efb9e63ca2ca88019d73b564488cc20e3eab12
+ languageName: node
+ linkType: hard
+
"@universal-middleware/express@npm:^0.0.2":
version: 0.0.2
resolution: "@universal-middleware/express@npm:0.0.2"
@@ -12410,7 +12758,7 @@ __metadata:
languageName: node
linkType: hard
-"acorn-jsx@npm:^5.0.0":
+"acorn-jsx@npm:^5.0.0, acorn-jsx@npm:^5.3.2":
version: 5.3.2
resolution: "acorn-jsx@npm:5.3.2"
peerDependencies:
@@ -12478,6 +12826,15 @@ __metadata:
languageName: node
linkType: hard
+"acorn@npm:^8.9.0":
+ version: 8.12.1
+ resolution: "acorn@npm:8.12.1"
+ bin:
+ acorn: bin/acorn
+ checksum: 10/d08c2d122bba32d0861e0aa840b2ee25946c286d5dc5990abca991baf8cdbfbe199b05aacb221b979411a2fea36f83e26b5ac4f6b4e0ce49038c62316c1848f0
+ languageName: node
+ linkType: hard
+
"affine-hull@npm:^1.0.0":
version: 1.0.0
resolution: "affine-hull@npm:1.0.0"
@@ -12840,7 +13197,7 @@ __metadata:
languageName: node
linkType: hard
-"aria-query@npm:5.1.3":
+"aria-query@npm:5.1.3, aria-query@npm:~5.1.3":
version: 5.1.3
resolution: "aria-query@npm:5.1.3"
dependencies:
@@ -12859,6 +13216,16 @@ __metadata:
languageName: node
linkType: hard
+"array-buffer-byte-length@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "array-buffer-byte-length@npm:1.0.1"
+ dependencies:
+ call-bind: "npm:^1.0.5"
+ is-array-buffer: "npm:^3.0.4"
+ checksum: 10/53524e08f40867f6a9f35318fafe467c32e45e9c682ba67b11943e167344d2febc0f6977a17e699b05699e805c3e8f073d876f8bbf1b559ed494ad2cd0fae09e
+ languageName: node
+ linkType: hard
+
"array-find-index@npm:^1.0.1":
version: 1.0.2
resolution: "array-find-index@npm:1.0.2"
@@ -12880,6 +13247,20 @@ __metadata:
languageName: node
linkType: hard
+"array-includes@npm:^3.1.6, array-includes@npm:^3.1.7, array-includes@npm:^3.1.8":
+ version: 3.1.8
+ resolution: "array-includes@npm:3.1.8"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.2"
+ es-object-atoms: "npm:^1.0.0"
+ get-intrinsic: "npm:^1.2.4"
+ is-string: "npm:^1.0.7"
+ checksum: 10/290b206c9451f181fb2b1f79a3bf1c0b66bb259791290ffbada760c79b284eef6f5ae2aeb4bcff450ebc9690edd25732c4c73a3c2b340fcc0f4563aed83bf488
+ languageName: node
+ linkType: hard
+
"array-union@npm:^2.1.0":
version: 2.1.0
resolution: "array-union@npm:2.1.0"
@@ -12887,6 +13268,58 @@ __metadata:
languageName: node
linkType: hard
+"array.prototype.findlast@npm:^1.2.5":
+ version: 1.2.5
+ resolution: "array.prototype.findlast@npm:1.2.5"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.2"
+ es-errors: "npm:^1.3.0"
+ es-object-atoms: "npm:^1.0.0"
+ es-shim-unscopables: "npm:^1.0.2"
+ checksum: 10/7dffcc665aa965718ad6de7e17ac50df0c5e38798c0a5bf9340cf24feb8594df6ec6f3fcbe714c1577728a1b18b5704b15669474b27bceeca91ef06ce2a23c31
+ languageName: node
+ linkType: hard
+
+"array.prototype.findlastindex@npm:^1.2.3":
+ version: 1.2.5
+ resolution: "array.prototype.findlastindex@npm:1.2.5"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.2"
+ es-errors: "npm:^1.3.0"
+ es-object-atoms: "npm:^1.0.0"
+ es-shim-unscopables: "npm:^1.0.2"
+ checksum: 10/7c5c821f357cd53ab6cc305de8086430dd8d7a2485db87b13f843e868055e9582b1fd338f02338f67fc3a1603ceaf9610dd2a470b0b506f9d18934780f95b246
+ languageName: node
+ linkType: hard
+
+"array.prototype.flat@npm:^1.3.1, array.prototype.flat@npm:^1.3.2":
+ version: 1.3.2
+ resolution: "array.prototype.flat@npm:1.3.2"
+ dependencies:
+ call-bind: "npm:^1.0.2"
+ define-properties: "npm:^1.2.0"
+ es-abstract: "npm:^1.22.1"
+ es-shim-unscopables: "npm:^1.0.0"
+ checksum: 10/d9d2f6f27584de92ec7995bc931103e6de722cd2498bdbfc4cba814fc3e52f056050a93be883018811f7c0a35875f5056584a0e940603a5e5934f0279896aebe
+ languageName: node
+ linkType: hard
+
+"array.prototype.flatmap@npm:^1.3.2":
+ version: 1.3.2
+ resolution: "array.prototype.flatmap@npm:1.3.2"
+ dependencies:
+ call-bind: "npm:^1.0.2"
+ define-properties: "npm:^1.2.0"
+ es-abstract: "npm:^1.22.1"
+ es-shim-unscopables: "npm:^1.0.0"
+ checksum: 10/33f20006686e0cbe844fde7fd290971e8366c6c5e3380681c2df15738b1df766dd02c7784034aeeb3b037f65c496ee54de665388288edb323a2008bb550f77ea
+ languageName: node
+ linkType: hard
+
"array.prototype.reduce@npm:^1.0.6":
version: 1.0.6
resolution: "array.prototype.reduce@npm:1.0.6"
@@ -12900,6 +13333,31 @@ __metadata:
languageName: node
linkType: hard
+"array.prototype.toreversed@npm:^1.1.2":
+ version: 1.1.2
+ resolution: "array.prototype.toreversed@npm:1.1.2"
+ dependencies:
+ call-bind: "npm:^1.0.2"
+ define-properties: "npm:^1.2.0"
+ es-abstract: "npm:^1.22.1"
+ es-shim-unscopables: "npm:^1.0.0"
+ checksum: 10/b4076d687ddc22c191863ce105d320cc4b0e1435bfda9ffeeff681682fe88fa6fe30e0d2ae94fa4b2d7fad901e1954ea4f75c1cab217db4848da84a2b5889192
+ languageName: node
+ linkType: hard
+
+"array.prototype.tosorted@npm:^1.1.4":
+ version: 1.1.4
+ resolution: "array.prototype.tosorted@npm:1.1.4"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.3"
+ es-errors: "npm:^1.3.0"
+ es-shim-unscopables: "npm:^1.0.2"
+ checksum: 10/874694e5d50e138894ff5b853e639c29b0aa42bbd355acda8e8e9cd337f1c80565f21edc15e8c727fa4c0877fd9d8783c575809e440cc4d2d19acaa048bf967d
+ languageName: node
+ linkType: hard
+
"arraybuffer.prototype.slice@npm:^1.0.2":
version: 1.0.2
resolution: "arraybuffer.prototype.slice@npm:1.0.2"
@@ -12915,6 +13373,22 @@ __metadata:
languageName: node
linkType: hard
+"arraybuffer.prototype.slice@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "arraybuffer.prototype.slice@npm:1.0.3"
+ dependencies:
+ array-buffer-byte-length: "npm:^1.0.1"
+ call-bind: "npm:^1.0.5"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.22.3"
+ es-errors: "npm:^1.2.1"
+ get-intrinsic: "npm:^1.2.3"
+ is-array-buffer: "npm:^3.0.4"
+ is-shared-array-buffer: "npm:^1.0.2"
+ checksum: 10/0221f16c1e3ec7b67da870ee0e1f12b825b5f9189835392b59a22990f715827561a4f4cd5330dc7507de272d8df821be6cd4b0cb569babf5ea4be70e365a2f3d
+ languageName: node
+ linkType: hard
+
"arrify@npm:^1.0.1":
version: 1.0.1
resolution: "arrify@npm:1.0.1"
@@ -12965,6 +13439,13 @@ __metadata:
languageName: node
linkType: hard
+"ast-types-flow@npm:^0.0.8":
+ version: 0.0.8
+ resolution: "ast-types-flow@npm:0.0.8"
+ checksum: 10/85a1c24af4707871c27cfe456bd2ff7fcbe678f3d1c878ac968c9557735a171a17bdcc8c8f903ceab3fc3c49d5b3da2194e6ab0a6be7fec0e133fa028f21ba1b
+ languageName: node
+ linkType: hard
+
"astring@npm:^1.8.0":
version: 1.8.6
resolution: "astring@npm:1.8.6"
@@ -13114,6 +13595,13 @@ __metadata:
languageName: node
linkType: hard
+"axe-core@npm:^4.9.1":
+ version: 4.9.1
+ resolution: "axe-core@npm:4.9.1"
+ checksum: 10/9d4944f6d3289428e1c6b41a80516f6558a960889f59c3c00f0fb88b955eda81edf9ca377c2cbc2a775f4003596d2aeaa35acca5aad3e1fc6b3d1e26e82b02cc
+ languageName: node
+ linkType: hard
+
"axios@npm:^0.25.0":
version: 0.25.0
resolution: "axios@npm:0.25.0"
@@ -13123,6 +13611,16 @@ __metadata:
languageName: node
linkType: hard
+"axios@npm:^0.27.2":
+ version: 0.27.2
+ resolution: "axios@npm:0.27.2"
+ dependencies:
+ follow-redirects: "npm:^1.14.9"
+ form-data: "npm:^4.0.0"
+ checksum: 10/2efaf18dd0805f7bc772882bc86f004abd92d51007b54c5081f74db0d08ce3593e2c010261896d25a14318eeaa2e966fd825e34f810e8a3339dc64b9d177cf70
+ languageName: node
+ linkType: hard
+
"axios@npm:^1.4.0":
version: 1.6.8
resolution: "axios@npm:1.6.8"
@@ -13145,6 +13643,15 @@ __metadata:
languageName: node
linkType: hard
+"axobject-query@npm:~3.1.1":
+ version: 3.1.1
+ resolution: "axobject-query@npm:3.1.1"
+ dependencies:
+ deep-equal: "npm:^2.0.5"
+ checksum: 10/3a3931bc419219e78d6438bc457c191e4c972caddae2be7eaa94615269209f1d283aaaece706a69742e5bcf27df99cc75eee97a5e366a06a9f2bdab1a79748c7
+ languageName: node
+ linkType: hard
+
"babel-jest@npm:^27.4.6, babel-jest@npm:^27.5.1":
version: 27.5.1
resolution: "babel-jest@npm:27.5.1"
@@ -13906,7 +14413,7 @@ __metadata:
languageName: node
linkType: hard
-"call-bind@npm:^1.0.5, call-bind@npm:^1.0.7":
+"call-bind@npm:^1.0.5, call-bind@npm:^1.0.6, call-bind@npm:^1.0.7":
version: 1.0.7
resolution: "call-bind@npm:1.0.7"
dependencies:
@@ -14318,20 +14825,13 @@ __metadata:
languageName: node
linkType: hard
-"chroma-js@npm:^2.4.2||^3.0.0":
+"chroma-js@npm:^2.4.2||^3.0.0, chroma-js@npm:^3.0.0":
version: 3.1.2
resolution: "chroma-js@npm:3.1.2"
checksum: 10/ea09b27d04b477a8fdc3314bfa6dc8de05feab47999ff1acdeba6cf3c32c76338baa5b4562d949d33d8adeca57754e5ea591c15b9985d65583c8771e7e07c2ef
languageName: node
linkType: hard
-"chroma-js@npm:^3.0.0":
- version: 3.1.1
- resolution: "chroma-js@npm:3.1.1"
- checksum: 10/71018790cef594904ee7d765ef22e45c781f2019d3aa878616a49a3c5e0d85179c5ceaab418d75f48e0089b597b57e99264320cdf3ac60deb2a067a9e5067f12
- languageName: node
- linkType: hard
-
"chrome-trace-event@npm:^1.0.2, chrome-trace-event@npm:^1.0.3":
version: 1.0.3
resolution: "chrome-trace-event@npm:1.0.3"
@@ -15267,6 +15767,15 @@ __metadata:
languageName: node
linkType: hard
+"cross-fetch@npm:^3.0.6, cross-fetch@npm:^3.1.5":
+ version: 3.1.8
+ resolution: "cross-fetch@npm:3.1.8"
+ dependencies:
+ node-fetch: "npm:^2.6.12"
+ checksum: 10/ac8c4ca87d2ac0e17a19b6a293a67ee8934881aee5ec9a5a8323c30e9a9a60a0f5291d3c0d633ec2a2f970cbc60978d628804dfaf03add92d7e720b6d37f392c
+ languageName: node
+ linkType: hard
+
"cross-fetch@npm:^4.0.0":
version: 4.0.0
resolution: "cross-fetch@npm:4.0.0"
@@ -15276,7 +15785,7 @@ __metadata:
languageName: node
linkType: hard
-"cross-spawn@npm:7.0.3, cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.3":
+"cross-spawn@npm:7.0.3, cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3":
version: 7.0.3
resolution: "cross-spawn@npm:7.0.3"
dependencies:
@@ -15318,6 +15827,15 @@ __metadata:
languageName: node
linkType: hard
+"css-box-model@npm:^1.2.0":
+ version: 1.2.1
+ resolution: "css-box-model@npm:1.2.1"
+ dependencies:
+ tiny-invariant: "npm:^1.0.6"
+ checksum: 10/54778883733e59058b5de983cf442b9db6c1494543d4d84a3defd05b51b991a1865f59e4ae424e733af2aa1fdb6e0bd905cb73db0e7e548fbd89853859fedc81
+ languageName: node
+ linkType: hard
+
"css-color-names@npm:0.0.4, css-color-names@npm:^0.0.4":
version: 0.0.4
resolution: "css-color-names@npm:0.0.4"
@@ -16285,6 +16803,13 @@ __metadata:
languageName: node
linkType: hard
+"damerau-levenshtein@npm:^1.0.8":
+ version: 1.0.8
+ resolution: "damerau-levenshtein@npm:1.0.8"
+ checksum: 10/f4eba1c90170f96be25d95fa3857141b5f81e254f7e4d530da929217b19990ea9a0390fc53d3c1cafac9152fda78e722ea4894f765cf6216be413b5af1fbf821
+ languageName: node
+ linkType: hard
+
"dargs@npm:^4.0.1":
version: 4.1.0
resolution: "dargs@npm:4.1.0"
@@ -16321,6 +16846,39 @@ __metadata:
languageName: node
linkType: hard
+"data-view-buffer@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "data-view-buffer@npm:1.0.1"
+ dependencies:
+ call-bind: "npm:^1.0.6"
+ es-errors: "npm:^1.3.0"
+ is-data-view: "npm:^1.0.1"
+ checksum: 10/5919a39a18ee919573336158fd162fdf8ada1bc23a139f28543fd45fac48e0ea4a3ad3bfde91de124d4106e65c4a7525f6a84c20ba0797ec890a77a96d13a82a
+ languageName: node
+ linkType: hard
+
+"data-view-byte-length@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "data-view-byte-length@npm:1.0.1"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ es-errors: "npm:^1.3.0"
+ is-data-view: "npm:^1.0.1"
+ checksum: 10/f33c65e58d8d0432ad79761f2e8a579818d724b5dc6dc4e700489b762d963ab30873c0f1c37d8f2ed12ef51c706d1195f64422856d25f067457aeec50cc40aac
+ languageName: node
+ linkType: hard
+
+"data-view-byte-offset@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "data-view-byte-offset@npm:1.0.0"
+ dependencies:
+ call-bind: "npm:^1.0.6"
+ es-errors: "npm:^1.3.0"
+ is-data-view: "npm:^1.0.1"
+ checksum: 10/96f34f151bf02affb7b9f98762fb7aca1dd5f4553cb57b80bce750ca609c15d33ca659568ef1d422f7e35680736cbccb893a3d4b012760c758c1446bbdc4c6db
+ languageName: node
+ linkType: hard
+
"date-fns-tz@npm:^2.0.0":
version: 2.0.1
resolution: "date-fns-tz@npm:2.0.1"
@@ -16376,7 +16934,7 @@ __metadata:
languageName: node
linkType: hard
-"debug@npm:^3.0.1, debug@npm:^3.1.0":
+"debug@npm:^3.0.1, debug@npm:^3.1.0, debug@npm:^3.2.7":
version: 3.2.7
resolution: "debug@npm:3.2.7"
dependencies:
@@ -16476,6 +17034,20 @@ __metadata:
languageName: node
linkType: hard
+"deep-equal@npm:^1.1.1":
+ version: 1.1.2
+ resolution: "deep-equal@npm:1.1.2"
+ dependencies:
+ is-arguments: "npm:^1.1.1"
+ is-date-object: "npm:^1.0.5"
+ is-regex: "npm:^1.1.4"
+ object-is: "npm:^1.1.5"
+ object-keys: "npm:^1.1.1"
+ regexp.prototype.flags: "npm:^1.5.1"
+ checksum: 10/c9d2ed2a0d93a2ee286bdb320cd51c78cd4c310b2161d1ede6476b67ca1d73860e7ff63b10927830aa4b9eca2a48073cfa54c8c4a1b2246397bda618c2138e97
+ languageName: node
+ linkType: hard
+
"deep-equal@npm:^2.0.5":
version: 2.2.2
resolution: "deep-equal@npm:2.2.2"
@@ -16535,7 +17107,7 @@ __metadata:
languageName: node
linkType: hard
-"deep-is@npm:~0.1.3":
+"deep-is@npm:^0.1.3, deep-is@npm:~0.1.3":
version: 0.1.4
resolution: "deep-is@npm:0.1.4"
checksum: 10/ec12d074aef5ae5e81fa470b9317c313142c9e8e2afe3f8efa124db309720db96d1d222b82b84c834e5f87e7a614b44a4684b6683583118b87c833b3be40d4d8
@@ -16627,7 +17199,7 @@ __metadata:
languageName: node
linkType: hard
-"define-properties@npm:^1.1.3, define-properties@npm:^1.1.4, define-properties@npm:^1.2.0":
+"define-properties@npm:^1.1.3, define-properties@npm:^1.1.4, define-properties@npm:^1.2.0, define-properties@npm:^1.2.1":
version: 1.2.1
resolution: "define-properties@npm:1.2.1"
dependencies:
@@ -16821,6 +17393,24 @@ __metadata:
languageName: node
linkType: hard
+"doctrine@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "doctrine@npm:2.1.0"
+ dependencies:
+ esutils: "npm:^2.0.2"
+ checksum: 10/555684f77e791b17173ea86e2eea45ef26c22219cb64670669c4f4bebd26dbc95cd90ec1f4159e9349a6bb9eb892ce4dde8cd0139e77bedd8bf4518238618474
+ languageName: node
+ linkType: hard
+
+"doctrine@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "doctrine@npm:3.0.0"
+ dependencies:
+ esutils: "npm:^2.0.2"
+ checksum: 10/b4b28f1df5c563f7d876e7461254a4597b8cabe915abe94d7c5d1633fed263fcf9a85e8d3836591fc2d040108e822b0d32758e5ec1fe31c590dc7e08086e3e48
+ languageName: node
+ linkType: hard
+
"dom-accessibility-api@npm:^0.5.9":
version: 0.5.16
resolution: "dom-accessibility-api@npm:0.5.16"
@@ -16884,6 +17474,13 @@ __metadata:
languageName: node
linkType: hard
+"dom4@npm:^2.1.5":
+ version: 2.1.6
+ resolution: "dom4@npm:2.1.6"
+ checksum: 10/9f49eb82dc013016d5dae8371d5c77c3a28e213be4d813c1e3f94d9c8af57d6130d3063af7214d594a127cd5c61c16f6f6d15acb0069fae01b5e70266fa958b9
+ languageName: node
+ linkType: hard
+
"domelementtype@npm:1, domelementtype@npm:^1.3.1":
version: 1.3.1
resolution: "domelementtype@npm:1.3.1"
@@ -17392,6 +17989,60 @@ __metadata:
languageName: node
linkType: hard
+"es-abstract@npm:^1.17.5, es-abstract@npm:^1.22.3, es-abstract@npm:^1.23.0, es-abstract@npm:^1.23.1, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3":
+ version: 1.23.3
+ resolution: "es-abstract@npm:1.23.3"
+ dependencies:
+ array-buffer-byte-length: "npm:^1.0.1"
+ arraybuffer.prototype.slice: "npm:^1.0.3"
+ available-typed-arrays: "npm:^1.0.7"
+ call-bind: "npm:^1.0.7"
+ data-view-buffer: "npm:^1.0.1"
+ data-view-byte-length: "npm:^1.0.1"
+ data-view-byte-offset: "npm:^1.0.0"
+ es-define-property: "npm:^1.0.0"
+ es-errors: "npm:^1.3.0"
+ es-object-atoms: "npm:^1.0.0"
+ es-set-tostringtag: "npm:^2.0.3"
+ es-to-primitive: "npm:^1.2.1"
+ function.prototype.name: "npm:^1.1.6"
+ get-intrinsic: "npm:^1.2.4"
+ get-symbol-description: "npm:^1.0.2"
+ globalthis: "npm:^1.0.3"
+ gopd: "npm:^1.0.1"
+ has-property-descriptors: "npm:^1.0.2"
+ has-proto: "npm:^1.0.3"
+ has-symbols: "npm:^1.0.3"
+ hasown: "npm:^2.0.2"
+ internal-slot: "npm:^1.0.7"
+ is-array-buffer: "npm:^3.0.4"
+ is-callable: "npm:^1.2.7"
+ is-data-view: "npm:^1.0.1"
+ is-negative-zero: "npm:^2.0.3"
+ is-regex: "npm:^1.1.4"
+ is-shared-array-buffer: "npm:^1.0.3"
+ is-string: "npm:^1.0.7"
+ is-typed-array: "npm:^1.1.13"
+ is-weakref: "npm:^1.0.2"
+ object-inspect: "npm:^1.13.1"
+ object-keys: "npm:^1.1.1"
+ object.assign: "npm:^4.1.5"
+ regexp.prototype.flags: "npm:^1.5.2"
+ safe-array-concat: "npm:^1.1.2"
+ safe-regex-test: "npm:^1.0.3"
+ string.prototype.trim: "npm:^1.2.9"
+ string.prototype.trimend: "npm:^1.0.8"
+ string.prototype.trimstart: "npm:^1.0.8"
+ typed-array-buffer: "npm:^1.0.2"
+ typed-array-byte-length: "npm:^1.0.1"
+ typed-array-byte-offset: "npm:^1.0.2"
+ typed-array-length: "npm:^1.0.6"
+ unbox-primitive: "npm:^1.0.2"
+ which-typed-array: "npm:^1.1.15"
+ checksum: 10/2da795a6a1ac5fc2c452799a409acc2e3692e06dc6440440b076908617188899caa562154d77263e3053bcd9389a07baa978ab10ac3b46acc399bd0c77be04cb
+ languageName: node
+ linkType: hard
+
"es-array-method-boxes-properly@npm:^1.0.0":
version: 1.0.0
resolution: "es-array-method-boxes-properly@npm:1.0.0"
@@ -17408,7 +18059,7 @@ __metadata:
languageName: node
linkType: hard
-"es-errors@npm:^1.3.0":
+"es-errors@npm:^1.2.1, es-errors@npm:^1.3.0":
version: 1.3.0
resolution: "es-errors@npm:1.3.0"
checksum: 10/96e65d640156f91b707517e8cdc454dd7d47c32833aa3e85d79f24f9eb7ea85f39b63e36216ef0114996581969b59fe609a94e30316b08f5f4df1d44134cf8d5
@@ -17432,6 +18083,28 @@ __metadata:
languageName: node
linkType: hard
+"es-iterator-helpers@npm:^1.0.19":
+ version: 1.0.19
+ resolution: "es-iterator-helpers@npm:1.0.19"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.3"
+ es-errors: "npm:^1.3.0"
+ es-set-tostringtag: "npm:^2.0.3"
+ function-bind: "npm:^1.1.2"
+ get-intrinsic: "npm:^1.2.4"
+ globalthis: "npm:^1.0.3"
+ has-property-descriptors: "npm:^1.0.2"
+ has-proto: "npm:^1.0.3"
+ has-symbols: "npm:^1.0.3"
+ internal-slot: "npm:^1.0.7"
+ iterator.prototype: "npm:^1.1.2"
+ safe-array-concat: "npm:^1.1.2"
+ checksum: 10/980a8081cf6798fe17fcea193b0448d784d72d76aca7240b10813207c67e3dc0d8a23992263870c4fc291da5a946935b0c56dec4fa1a9de8fee0165e4fa1fc58
+ languageName: node
+ linkType: hard
+
"es-module-lexer@npm:^1.0.0":
version: 1.4.1
resolution: "es-module-lexer@npm:1.4.1"
@@ -17446,6 +18119,15 @@ __metadata:
languageName: node
linkType: hard
+"es-object-atoms@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "es-object-atoms@npm:1.0.0"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ checksum: 10/f8910cf477e53c0615f685c5c96210591841850871b81924fcf256bfbaa68c254457d994a4308c60d15b20805e7f61ce6abc669375e01a5349391a8c1767584f
+ languageName: node
+ linkType: hard
+
"es-set-tostringtag@npm:^2.0.1":
version: 2.0.1
resolution: "es-set-tostringtag@npm:2.0.1"
@@ -17457,6 +18139,26 @@ __metadata:
languageName: node
linkType: hard
+"es-set-tostringtag@npm:^2.0.3":
+ version: 2.0.3
+ resolution: "es-set-tostringtag@npm:2.0.3"
+ dependencies:
+ get-intrinsic: "npm:^1.2.4"
+ has-tostringtag: "npm:^1.0.2"
+ hasown: "npm:^2.0.1"
+ checksum: 10/7227fa48a41c0ce83e0377b11130d324ac797390688135b8da5c28994c0165be8b252e15cd1de41e1325e5a5412511586960213e88f9ab4a5e7d028895db5129
+ languageName: node
+ linkType: hard
+
+"es-shim-unscopables@npm:^1.0.0, es-shim-unscopables@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "es-shim-unscopables@npm:1.0.2"
+ dependencies:
+ hasown: "npm:^2.0.0"
+ checksum: 10/6d3bf91f658a27cc7217cd32b407a0d714393a84d125ad576319b9e83a893bea165cf41270c29e9ceaa56d3cf41608945d7e2a2c31fd51c0009b0c31402b91c7
+ languageName: node
+ linkType: hard
+
"es-to-primitive@npm:^1.2.1":
version: 1.2.1
resolution: "es-to-primitive@npm:1.2.1"
@@ -18054,6 +18756,159 @@ __metadata:
languageName: node
linkType: hard
+"eslint-config-next@npm:^12.0.8":
+ version: 12.3.4
+ resolution: "eslint-config-next@npm:12.3.4"
+ dependencies:
+ "@next/eslint-plugin-next": "npm:12.3.4"
+ "@rushstack/eslint-patch": "npm:^1.1.3"
+ "@typescript-eslint/parser": "npm:^5.21.0"
+ eslint-import-resolver-node: "npm:^0.3.6"
+ eslint-import-resolver-typescript: "npm:^2.7.1"
+ eslint-plugin-import: "npm:^2.26.0"
+ eslint-plugin-jsx-a11y: "npm:^6.5.1"
+ eslint-plugin-react: "npm:^7.31.7"
+ eslint-plugin-react-hooks: "npm:^4.5.0"
+ peerDependencies:
+ eslint: ^7.23.0 || ^8.0.0
+ typescript: ">=3.3.1"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10/53cd24d7b764fe382812a5e76571083fe59e892ac88ac5ccddf171e261f5a3ea36cb1c34283f97569c97a4bae51ece5252d5aa71fd130d31ada94310dc4147ee
+ languageName: node
+ linkType: hard
+
+"eslint-import-resolver-node@npm:^0.3.6, eslint-import-resolver-node@npm:^0.3.9":
+ version: 0.3.9
+ resolution: "eslint-import-resolver-node@npm:0.3.9"
+ dependencies:
+ debug: "npm:^3.2.7"
+ is-core-module: "npm:^2.13.0"
+ resolve: "npm:^1.22.4"
+ checksum: 10/d52e08e1d96cf630957272e4f2644dcfb531e49dcfd1edd2e07e43369eb2ec7a7d4423d417beee613201206ff2efa4eb9a582b5825ee28802fc7c71fcd53ca83
+ languageName: node
+ linkType: hard
+
+"eslint-import-resolver-typescript@npm:^2.7.1":
+ version: 2.7.1
+ resolution: "eslint-import-resolver-typescript@npm:2.7.1"
+ dependencies:
+ debug: "npm:^4.3.4"
+ glob: "npm:^7.2.0"
+ is-glob: "npm:^4.0.3"
+ resolve: "npm:^1.22.0"
+ tsconfig-paths: "npm:^3.14.1"
+ peerDependencies:
+ eslint: "*"
+ eslint-plugin-import: "*"
+ checksum: 10/4a688440395673492b2e28347ba2173542dcec0bc597065469191be213e30f65b316697a950abf492f4191365626fb13231080c6ca326044df087f57d163e6c6
+ languageName: node
+ linkType: hard
+
+"eslint-module-utils@npm:^2.8.0":
+ version: 2.8.1
+ resolution: "eslint-module-utils@npm:2.8.1"
+ dependencies:
+ debug: "npm:^3.2.7"
+ peerDependenciesMeta:
+ eslint:
+ optional: true
+ checksum: 10/3e7892c0a984c963632da56b30ccf8254c29b535467138f91086c2ecdb2ebd10e2be61b54e553f30e5abf1d14d47a7baa0dac890e3a658fd3cd07dca63afbe6d
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-import@npm:^2.26.0":
+ version: 2.29.1
+ resolution: "eslint-plugin-import@npm:2.29.1"
+ dependencies:
+ array-includes: "npm:^3.1.7"
+ array.prototype.findlastindex: "npm:^1.2.3"
+ array.prototype.flat: "npm:^1.3.2"
+ array.prototype.flatmap: "npm:^1.3.2"
+ debug: "npm:^3.2.7"
+ doctrine: "npm:^2.1.0"
+ eslint-import-resolver-node: "npm:^0.3.9"
+ eslint-module-utils: "npm:^2.8.0"
+ hasown: "npm:^2.0.0"
+ is-core-module: "npm:^2.13.1"
+ is-glob: "npm:^4.0.3"
+ minimatch: "npm:^3.1.2"
+ object.fromentries: "npm:^2.0.7"
+ object.groupby: "npm:^1.0.1"
+ object.values: "npm:^1.1.7"
+ semver: "npm:^6.3.1"
+ tsconfig-paths: "npm:^3.15.0"
+ peerDependencies:
+ eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
+ checksum: 10/5865f05c38552145423c535326ec9a7113ab2305c7614c8b896ff905cfabc859c8805cac21e979c9f6f742afa333e6f62f812eabf891a7e8f5f0b853a32593c1
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-jsx-a11y@npm:^6.5.1":
+ version: 6.9.0
+ resolution: "eslint-plugin-jsx-a11y@npm:6.9.0"
+ dependencies:
+ aria-query: "npm:~5.1.3"
+ array-includes: "npm:^3.1.8"
+ array.prototype.flatmap: "npm:^1.3.2"
+ ast-types-flow: "npm:^0.0.8"
+ axe-core: "npm:^4.9.1"
+ axobject-query: "npm:~3.1.1"
+ damerau-levenshtein: "npm:^1.0.8"
+ emoji-regex: "npm:^9.2.2"
+ es-iterator-helpers: "npm:^1.0.19"
+ hasown: "npm:^2.0.2"
+ jsx-ast-utils: "npm:^3.3.5"
+ language-tags: "npm:^1.0.9"
+ minimatch: "npm:^3.1.2"
+ object.fromentries: "npm:^2.0.8"
+ safe-regex-test: "npm:^1.0.3"
+ string.prototype.includes: "npm:^2.0.0"
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
+ checksum: 10/00a854a1a1a7ca52c216e83a574d5a65fc150243afcababfbf1657c5ffff1f076b9bd3d87029bb6432bfaa36d23e16c1e8b59671d0580bbb72e14860ee1bec9a
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-react-hooks@npm:^4.5.0":
+ version: 4.6.2
+ resolution: "eslint-plugin-react-hooks@npm:4.6.2"
+ peerDependencies:
+ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
+ checksum: 10/5a0680941f34e70cf505bcb6082df31a3e445d193ee95a88ff3483041eb944f4cefdaf7e81b0eb1feb4eeceee8c7c6ddb8a2a6e8c4c0388514a42e16ac7b7a69
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-react@npm:^7.31.7":
+ version: 7.34.4
+ resolution: "eslint-plugin-react@npm:7.34.4"
+ dependencies:
+ array-includes: "npm:^3.1.8"
+ array.prototype.findlast: "npm:^1.2.5"
+ array.prototype.flatmap: "npm:^1.3.2"
+ array.prototype.toreversed: "npm:^1.1.2"
+ array.prototype.tosorted: "npm:^1.1.4"
+ doctrine: "npm:^2.1.0"
+ es-iterator-helpers: "npm:^1.0.19"
+ estraverse: "npm:^5.3.0"
+ hasown: "npm:^2.0.2"
+ jsx-ast-utils: "npm:^2.4.1 || ^3.0.0"
+ minimatch: "npm:^3.1.2"
+ object.entries: "npm:^1.1.8"
+ object.fromentries: "npm:^2.0.8"
+ object.values: "npm:^1.2.0"
+ prop-types: "npm:^15.8.1"
+ resolve: "npm:^2.0.0-next.5"
+ semver: "npm:^6.3.1"
+ string.prototype.matchall: "npm:^4.0.11"
+ string.prototype.repeat: "npm:^1.0.0"
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
+ checksum: 10/9ad948a109bcb5b1f2f3a8099fa9eab3bee3eb996786f783d1f17208f44c8e3dcbc4f9dab84aa70062c03a053a48a333ca03fee21d406d5732291d204e43d9ca
+ languageName: node
+ linkType: hard
+
"eslint-scope@npm:5.1.1":
version: 5.1.1
resolution: "eslint-scope@npm:5.1.1"
@@ -18064,13 +18919,82 @@ __metadata:
languageName: node
linkType: hard
-"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1":
+"eslint-scope@npm:^7.2.2":
+ version: 7.2.2
+ resolution: "eslint-scope@npm:7.2.2"
+ dependencies:
+ esrecurse: "npm:^4.3.0"
+ estraverse: "npm:^5.2.0"
+ checksum: 10/5c660fb905d5883ad018a6fea2b49f3cb5b1cbf2cd4bd08e98646e9864f9bc2c74c0839bed2d292e90a4a328833accc197c8f0baed89cbe8d605d6f918465491
+ languageName: node
+ linkType: hard
+
+"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3":
version: 3.4.3
resolution: "eslint-visitor-keys@npm:3.4.3"
checksum: 10/3f357c554a9ea794b094a09bd4187e5eacd1bc0d0653c3adeb87962c548e6a1ab8f982b86963ae1337f5d976004146536dcee5d0e2806665b193fbfbf1a9231b
languageName: node
linkType: hard
+"eslint@npm:^8.7.0":
+ version: 8.57.0
+ resolution: "eslint@npm:8.57.0"
+ dependencies:
+ "@eslint-community/eslint-utils": "npm:^4.2.0"
+ "@eslint-community/regexpp": "npm:^4.6.1"
+ "@eslint/eslintrc": "npm:^2.1.4"
+ "@eslint/js": "npm:8.57.0"
+ "@humanwhocodes/config-array": "npm:^0.11.14"
+ "@humanwhocodes/module-importer": "npm:^1.0.1"
+ "@nodelib/fs.walk": "npm:^1.2.8"
+ "@ungap/structured-clone": "npm:^1.2.0"
+ ajv: "npm:^6.12.4"
+ chalk: "npm:^4.0.0"
+ cross-spawn: "npm:^7.0.2"
+ debug: "npm:^4.3.2"
+ doctrine: "npm:^3.0.0"
+ escape-string-regexp: "npm:^4.0.0"
+ eslint-scope: "npm:^7.2.2"
+ eslint-visitor-keys: "npm:^3.4.3"
+ espree: "npm:^9.6.1"
+ esquery: "npm:^1.4.2"
+ esutils: "npm:^2.0.2"
+ fast-deep-equal: "npm:^3.1.3"
+ file-entry-cache: "npm:^6.0.1"
+ find-up: "npm:^5.0.0"
+ glob-parent: "npm:^6.0.2"
+ globals: "npm:^13.19.0"
+ graphemer: "npm:^1.4.0"
+ ignore: "npm:^5.2.0"
+ imurmurhash: "npm:^0.1.4"
+ is-glob: "npm:^4.0.0"
+ is-path-inside: "npm:^3.0.3"
+ js-yaml: "npm:^4.1.0"
+ json-stable-stringify-without-jsonify: "npm:^1.0.1"
+ levn: "npm:^0.4.1"
+ lodash.merge: "npm:^4.6.2"
+ minimatch: "npm:^3.1.2"
+ natural-compare: "npm:^1.4.0"
+ optionator: "npm:^0.9.3"
+ strip-ansi: "npm:^6.0.1"
+ text-table: "npm:^0.2.0"
+ bin:
+ eslint: bin/eslint.js
+ checksum: 10/00496e218b23747a7a9817bf58b522276d0dc1f2e546dceb4eea49f9871574088f72f1f069a6b560ef537efa3a75261b8ef70e51ef19033da1cc4c86a755ef15
+ languageName: node
+ linkType: hard
+
+"espree@npm:^9.6.0, espree@npm:^9.6.1":
+ version: 9.6.1
+ resolution: "espree@npm:9.6.1"
+ dependencies:
+ acorn: "npm:^8.9.0"
+ acorn-jsx: "npm:^5.3.2"
+ eslint-visitor-keys: "npm:^3.4.1"
+ checksum: 10/255ab260f0d711a54096bdeda93adff0eadf02a6f9b92f02b323e83a2b7fc258797919437ad331efec3930475feb0142c5ecaaf3cdab4befebd336d47d3f3134
+ languageName: node
+ linkType: hard
+
"esprima@npm:^3.1.3":
version: 3.1.3
resolution: "esprima@npm:3.1.3"
@@ -18091,6 +19015,15 @@ __metadata:
languageName: node
linkType: hard
+"esquery@npm:^1.4.2":
+ version: 1.6.0
+ resolution: "esquery@npm:1.6.0"
+ dependencies:
+ estraverse: "npm:^5.1.0"
+ checksum: 10/c587fb8ec9ed83f2b1bc97cf2f6854cc30bf784a79d62ba08c6e358bf22280d69aee12827521cf38e69ae9761d23fb7fde593ce315610f85655c139d99b05e5a
+ languageName: node
+ linkType: hard
+
"esrecurse@npm:^4.3.0":
version: 4.3.0
resolution: "esrecurse@npm:4.3.0"
@@ -18107,7 +19040,7 @@ __metadata:
languageName: node
linkType: hard
-"estraverse@npm:^5.2.0":
+"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0":
version: 5.3.0
resolution: "estraverse@npm:5.3.0"
checksum: 10/37cbe6e9a68014d34dbdc039f90d0baf72436809d02edffcc06ba3c2a12eb298048f877511353b130153e532aac8d68ba78430c0dd2f44806ebc7c014b01585e
@@ -18567,7 +19500,7 @@ __metadata:
languageName: node
linkType: hard
-"fast-levenshtein@npm:~2.0.6":
+"fast-levenshtein@npm:^2.0.6, fast-levenshtein@npm:~2.0.6":
version: 2.0.6
resolution: "fast-levenshtein@npm:2.0.6"
checksum: 10/eb7e220ecf2bab5159d157350b81d01f75726a4382f5a9266f42b9150c4523b9795f7f5d9fbbbeaeac09a441b2369f05ee02db48ea938584205530fe5693cfe1
@@ -18699,6 +19632,15 @@ __metadata:
languageName: node
linkType: hard
+"file-entry-cache@npm:^6.0.1":
+ version: 6.0.1
+ resolution: "file-entry-cache@npm:6.0.1"
+ dependencies:
+ flat-cache: "npm:^3.0.4"
+ checksum: 10/099bb9d4ab332cb93c48b14807a6918a1da87c45dce91d4b61fd40e6505d56d0697da060cb901c729c90487067d93c9243f5da3dc9c41f0358483bfdebca736b
+ languageName: node
+ linkType: hard
+
"file-loader@npm:^6.2.0":
version: 6.2.0
resolution: "file-loader@npm:6.2.0"
@@ -18836,6 +19778,16 @@ __metadata:
languageName: node
linkType: hard
+"find-up@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "find-up@npm:5.0.0"
+ dependencies:
+ locate-path: "npm:^6.0.0"
+ path-exists: "npm:^4.0.0"
+ checksum: 10/07955e357348f34660bde7920783204ff5a26ac2cafcaa28bace494027158a97b9f56faaf2d89a6106211a8174db650dd9f503f9c0d526b1202d5554a00b9095
+ languageName: node
+ linkType: hard
+
"find-versions@npm:^3.0.0":
version: 3.2.0
resolution: "find-versions@npm:3.2.0"
@@ -18854,6 +19806,17 @@ __metadata:
languageName: node
linkType: hard
+"flat-cache@npm:^3.0.4":
+ version: 3.2.0
+ resolution: "flat-cache@npm:3.2.0"
+ dependencies:
+ flatted: "npm:^3.2.9"
+ keyv: "npm:^4.5.3"
+ rimraf: "npm:^3.0.2"
+ checksum: 10/02381c6ece5e9fa5b826c9bbea481d7fd77645d96e4b0b1395238124d581d10e56f17f723d897b6d133970f7a57f0fab9148cbbb67237a0a0ffe794ba60c0c70
+ languageName: node
+ linkType: hard
+
"flat@npm:^5.0.2":
version: 5.0.2
resolution: "flat@npm:5.0.2"
@@ -18863,6 +19826,13 @@ __metadata:
languageName: node
linkType: hard
+"flatted@npm:^3.2.9":
+ version: 3.3.1
+ resolution: "flatted@npm:3.3.1"
+ checksum: 10/7b8376061d5be6e0d3658bbab8bde587647f68797cf6bfeae9dea0e5137d9f27547ab92aaff3512dd9d1299086a6d61be98e9d48a56d17531b634f77faadbc49
+ languageName: node
+ linkType: hard
+
"flush-write-stream@npm:^1.0.0":
version: 1.1.1
resolution: "flush-write-stream@npm:1.1.1"
@@ -18892,7 +19862,7 @@ __metadata:
languageName: node
linkType: hard
-"follow-redirects@npm:^1.14.7":
+"follow-redirects@npm:^1.14.7, follow-redirects@npm:^1.14.9":
version: 1.15.3
resolution: "follow-redirects@npm:1.15.3"
peerDependenciesMeta:
@@ -19154,7 +20124,7 @@ __metadata:
languageName: node
linkType: hard
-"function.prototype.name@npm:^1.1.6":
+"function.prototype.name@npm:^1.1.5, function.prototype.name@npm:^1.1.6":
version: 1.1.6
resolution: "function.prototype.name@npm:1.1.6"
dependencies:
@@ -19334,7 +20304,7 @@ __metadata:
languageName: node
linkType: hard
-"get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.4":
+"get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4":
version: 1.2.4
resolution: "get-intrinsic@npm:1.2.4"
dependencies:
@@ -19457,6 +20427,17 @@ __metadata:
languageName: node
linkType: hard
+"get-symbol-description@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "get-symbol-description@npm:1.0.2"
+ dependencies:
+ call-bind: "npm:^1.0.5"
+ es-errors: "npm:^1.3.0"
+ get-intrinsic: "npm:^1.2.4"
+ checksum: 10/e1cb53bc211f9dbe9691a4f97a46837a553c4e7caadd0488dc24ac694db8a390b93edd412b48dcdd0b4bbb4c595de1709effc75fc87c0839deedc6968f5bd973
+ languageName: node
+ linkType: hard
+
"get-tsconfig@npm:^4.7.5":
version: 4.7.5
resolution: "get-tsconfig@npm:4.7.5"
@@ -19544,7 +20525,7 @@ __metadata:
languageName: node
linkType: hard
-"glob-parent@npm:^6.0.1":
+"glob-parent@npm:^6.0.1, glob-parent@npm:^6.0.2":
version: 6.0.2
resolution: "glob-parent@npm:6.0.2"
dependencies:
@@ -19560,6 +20541,20 @@ __metadata:
languageName: node
linkType: hard
+"glob@npm:7.1.7":
+ version: 7.1.7
+ resolution: "glob@npm:7.1.7"
+ dependencies:
+ fs.realpath: "npm:^1.0.0"
+ inflight: "npm:^1.0.4"
+ inherits: "npm:2"
+ minimatch: "npm:^3.0.4"
+ once: "npm:^1.3.0"
+ path-is-absolute: "npm:^1.0.0"
+ checksum: 10/ff5aab0386e9cace92b0550d42085b71013c5ea382982dd7fdded998a559635f61413b8ba6fb7294eef289c83b52f4e64136f888300ac8afc4f3e5623182d6c8
+ languageName: node
+ linkType: hard
+
"glob@npm:^10.2.2":
version: 10.3.6
resolution: "glob@npm:10.3.6"
@@ -19575,7 +20570,7 @@ __metadata:
languageName: node
linkType: hard
-"glob@npm:^7.0.0, glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.2.3":
+"glob@npm:^7.0.0, glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.2.0, glob@npm:^7.2.3":
version: 7.2.3
resolution: "glob@npm:7.2.3"
dependencies:
@@ -19615,6 +20610,15 @@ __metadata:
languageName: node
linkType: hard
+"globals@npm:^13.19.0":
+ version: 13.24.0
+ resolution: "globals@npm:13.24.0"
+ dependencies:
+ type-fest: "npm:^0.20.2"
+ checksum: 10/62c5b1997d06674fc7191d3e01e324d3eda4d65ac9cc4e78329fa3b5c4fd42a0e1c8722822497a6964eee075255ce21ccf1eec2d83f92ef3f06653af4d0ee28e
+ languageName: node
+ linkType: hard
+
"globals@npm:^13.2.0":
version: 13.22.0
resolution: "globals@npm:13.22.0"
@@ -19777,6 +20781,13 @@ __metadata:
languageName: node
linkType: hard
+"gud@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "gud@npm:1.0.0"
+ checksum: 10/3e2eb37cf794364077c18f036d6aa259c821c7fd188f2b7935cb00d589d82a41e0ebb1be809e1a93679417f62f1ad0513e745c3cf5329596e489aef8c5e5feae
+ languageName: node
+ linkType: hard
+
"gzip-size@npm:^3.0.0":
version: 3.0.0
resolution: "gzip-size@npm:3.0.0"
@@ -19941,6 +20952,13 @@ __metadata:
languageName: node
linkType: hard
+"has-proto@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "has-proto@npm:1.0.3"
+ checksum: 10/0b67c2c94e3bea37db3e412e3c41f79d59259875e636ba471e94c009cdfb1fa82bf045deeffafc7dbb9c148e36cae6b467055aaa5d9fad4316e11b41e3ba551a
+ languageName: node
+ linkType: hard
+
"has-symbols@npm:^1.0.1, has-symbols@npm:^1.0.2, has-symbols@npm:^1.0.3":
version: 1.0.3
resolution: "has-symbols@npm:1.0.3"
@@ -19989,7 +21007,7 @@ __metadata:
languageName: node
linkType: hard
-"hasown@npm:^2.0.0":
+"hasown@npm:^2.0.0, hasown@npm:^2.0.1, hasown@npm:^2.0.2":
version: 2.0.2
resolution: "hasown@npm:2.0.2"
dependencies:
@@ -20886,6 +21904,17 @@ __metadata:
languageName: node
linkType: hard
+"internal-slot@npm:^1.0.7":
+ version: 1.0.7
+ resolution: "internal-slot@npm:1.0.7"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ hasown: "npm:^2.0.0"
+ side-channel: "npm:^1.0.4"
+ checksum: 10/3e66720508831153ecf37d13def9f6856f9f2960989ec8a0a0476c98f887fca9eff0163127466485cb825c900c2d6fc601aa9117b7783b90ffce23a71ea5d053
+ languageName: node
+ linkType: hard
+
"internmap@npm:1 - 2":
version: 2.0.3
resolution: "internmap@npm:2.0.3"
@@ -21037,6 +22066,16 @@ __metadata:
languageName: node
linkType: hard
+"is-array-buffer@npm:^3.0.4":
+ version: 3.0.4
+ resolution: "is-array-buffer@npm:3.0.4"
+ dependencies:
+ call-bind: "npm:^1.0.2"
+ get-intrinsic: "npm:^1.2.1"
+ checksum: 10/34a26213d981d58b30724ef37a1e0682f4040d580fa9ff58fdfdd3cefcb2287921718c63971c1c404951e7b747c50fdc7caf6e867e951353fa71b369c04c969b
+ languageName: node
+ linkType: hard
+
"is-arrayish@npm:^0.2.1":
version: 0.2.1
resolution: "is-arrayish@npm:0.2.1"
@@ -21051,6 +22090,15 @@ __metadata:
languageName: node
linkType: hard
+"is-async-function@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "is-async-function@npm:2.0.0"
+ dependencies:
+ has-tostringtag: "npm:^1.0.0"
+ checksum: 10/2cf336fbf8cba3badcf526aa3d10384c30bab32615ac4831b74492eb4e843ccb7d8439a119c27f84bcf217d72024e611b1373f870f433b48f3fa57d3d1b863f1
+ languageName: node
+ linkType: hard
+
"is-bigint@npm:^1.0.1":
version: 1.0.4
resolution: "is-bigint@npm:1.0.4"
@@ -21152,6 +22200,24 @@ __metadata:
languageName: node
linkType: hard
+"is-core-module@npm:^2.13.1":
+ version: 2.15.0
+ resolution: "is-core-module@npm:2.15.0"
+ dependencies:
+ hasown: "npm:^2.0.2"
+ checksum: 10/70e962543e5d3a97c07cb29144a86792d545a21f28e67da5401d85878a0193d46fbab8d97bc3ca680e2778705dca66e7b6ca840c493497a27ca0e8c5f3ac3d1d
+ languageName: node
+ linkType: hard
+
+"is-data-view@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "is-data-view@npm:1.0.1"
+ dependencies:
+ is-typed-array: "npm:^1.1.13"
+ checksum: 10/4ba4562ac2b2ec005fefe48269d6bd0152785458cd253c746154ffb8a8ab506a29d0cfb3b74af87513843776a88e4981ae25c89457bf640a33748eab1a7216b5
+ languageName: node
+ linkType: hard
+
"is-date-object@npm:^1.0.1, is-date-object@npm:^1.0.5":
version: 1.0.5
resolution: "is-date-object@npm:1.0.5"
@@ -21214,6 +22280,15 @@ __metadata:
languageName: node
linkType: hard
+"is-finalizationregistry@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "is-finalizationregistry@npm:1.0.2"
+ dependencies:
+ call-bind: "npm:^1.0.2"
+ checksum: 10/1b8e9e1bf2075e862315ef9d38ce6d39c43ca9d81d46f73b34473506992f4b0fbaadb47ec9b420a5e76afe3f564d9f1f0d9b552ef272cc2395e0f21d743c9c29
+ languageName: node
+ linkType: hard
+
"is-fullwidth-code-point@npm:^1.0.0":
version: 1.0.0
resolution: "is-fullwidth-code-point@npm:1.0.0"
@@ -21251,7 +22326,7 @@ __metadata:
languageName: node
linkType: hard
-"is-generator-function@npm:^1.0.7":
+"is-generator-function@npm:^1.0.10, is-generator-function@npm:^1.0.7":
version: 1.0.10
resolution: "is-generator-function@npm:1.0.10"
dependencies:
@@ -21260,7 +22335,7 @@ __metadata:
languageName: node
linkType: hard
-"is-glob@npm:^4.0.1, is-glob@npm:^4.0.3, is-glob@npm:~4.0.1":
+"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3, is-glob@npm:~4.0.1":
version: 4.0.3
resolution: "is-glob@npm:4.0.3"
dependencies:
@@ -21349,6 +22424,13 @@ __metadata:
languageName: node
linkType: hard
+"is-negative-zero@npm:^2.0.3":
+ version: 2.0.3
+ resolution: "is-negative-zero@npm:2.0.3"
+ checksum: 10/8fe5cffd8d4fb2ec7b49d657e1691889778d037494c6f40f4d1a524cadd658b4b53ad7b6b73a59bcb4b143ae9a3d15829af864b2c0f9d65ac1e678c4c80f17e5
+ languageName: node
+ linkType: hard
+
"is-npm@npm:^1.0.0":
version: 1.0.0
resolution: "is-npm@npm:1.0.0"
@@ -21395,6 +22477,13 @@ __metadata:
languageName: node
linkType: hard
+"is-path-inside@npm:^3.0.3":
+ version: 3.0.3
+ resolution: "is-path-inside@npm:3.0.3"
+ checksum: 10/abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9
+ languageName: node
+ linkType: hard
+
"is-plain-obj@npm:^1.1.0":
version: 1.1.0
resolution: "is-plain-obj@npm:1.1.0"
@@ -21504,6 +22593,15 @@ __metadata:
languageName: node
linkType: hard
+"is-shared-array-buffer@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "is-shared-array-buffer@npm:1.0.3"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ checksum: 10/bc5402900dc62b96ebb2548bf5b0a0bcfacc2db122236fe3ab3b3e3c884293a0d5eb777e73f059bcbf8dc8563bb65eae972fee0fb97e38a9ae27c8678f62bcfe
+ languageName: node
+ linkType: hard
+
"is-stream@npm:^1.0.0, is-stream@npm:^1.0.1, is-stream@npm:^1.1.0":
version: 1.1.0
resolution: "is-stream@npm:1.1.0"
@@ -21561,6 +22659,15 @@ __metadata:
languageName: node
linkType: hard
+"is-typed-array@npm:^1.1.13":
+ version: 1.1.13
+ resolution: "is-typed-array@npm:1.1.13"
+ dependencies:
+ which-typed-array: "npm:^1.1.14"
+ checksum: 10/f850ba08286358b9a11aee6d93d371a45e3c59b5953549ee1c1a9a55ba5c1dd1bd9952488ae194ad8f32a9cf5e79c8fa5f0cc4d78c00720aa0bbcf238b38062d
+ languageName: node
+ linkType: hard
+
"is-typedarray@npm:^1.0.0, is-typedarray@npm:~1.0.0":
version: 1.0.0
resolution: "is-typedarray@npm:1.0.0"
@@ -21736,6 +22843,19 @@ __metadata:
languageName: node
linkType: hard
+"iterator.prototype@npm:^1.1.2":
+ version: 1.1.2
+ resolution: "iterator.prototype@npm:1.1.2"
+ dependencies:
+ define-properties: "npm:^1.2.1"
+ get-intrinsic: "npm:^1.2.1"
+ has-symbols: "npm:^1.0.3"
+ reflect.getprototypeof: "npm:^1.0.4"
+ set-function-name: "npm:^2.0.1"
+ checksum: 10/b5013967ad8f28c9ca1be8e159eb10f591b8e46deae87476fe39d668c04374fe9158c815e8b6d2f45885b0a3fd842a8ba13f497ec762b3a0eff49bec278670b1
+ languageName: node
+ linkType: hard
+
"jackspeak@npm:^2.0.3":
version: 2.3.3
resolution: "jackspeak@npm:2.3.3"
@@ -22461,6 +23581,13 @@ __metadata:
languageName: node
linkType: hard
+"json-stable-stringify-without-jsonify@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "json-stable-stringify-without-jsonify@npm:1.0.1"
+ checksum: 10/12786c2e2f22c27439e6db0532ba321f1d0617c27ad8cb1c352a0e9249a50182fd1ba8b52a18899291604b0c32eafa8afd09e51203f19109a0537f68db2b652d
+ languageName: node
+ linkType: hard
+
"json-stable-stringify@npm:^1.0.2":
version: 1.1.1
resolution: "json-stable-stringify@npm:1.1.1"
@@ -22480,7 +23607,7 @@ __metadata:
languageName: node
linkType: hard
-"json5@npm:^1.0.1":
+"json5@npm:^1.0.1, json5@npm:^1.0.2":
version: 1.0.2
resolution: "json5@npm:1.0.2"
dependencies:
@@ -22563,6 +23690,18 @@ __metadata:
languageName: node
linkType: hard
+"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.5":
+ version: 3.3.5
+ resolution: "jsx-ast-utils@npm:3.3.5"
+ dependencies:
+ array-includes: "npm:^3.1.6"
+ array.prototype.flat: "npm:^1.3.1"
+ object.assign: "npm:^4.1.4"
+ object.values: "npm:^1.1.6"
+ checksum: 10/b61d44613687dfe4cc8ad4b4fbf3711bf26c60b8d5ed1f494d723e0808415c59b24a7c0ed8ab10736a40ff84eef38cbbfb68b395e05d31117b44ffc59d31edfc
+ languageName: node
+ linkType: hard
+
"kdbush@npm:^4.0.1, kdbush@npm:^4.0.2":
version: 4.0.2
resolution: "kdbush@npm:4.0.2"
@@ -22579,6 +23718,15 @@ __metadata:
languageName: node
linkType: hard
+"keyv@npm:^4.5.3":
+ version: 4.5.4
+ resolution: "keyv@npm:4.5.4"
+ dependencies:
+ json-buffer: "npm:3.0.1"
+ checksum: 10/167eb6ef64cc84b6fa0780ee50c9de456b422a1e18802209234f7c2cf7eae648c7741f32e50d7e24ccb22b24c13154070b01563d642755b156c357431a191e75
+ languageName: node
+ linkType: hard
+
"kind-of@npm:^6.0.0, kind-of@npm:^6.0.2, kind-of@npm:^6.0.3":
version: 6.0.3
resolution: "kind-of@npm:6.0.3"
@@ -22673,6 +23821,22 @@ __metadata:
languageName: node
linkType: hard
+"language-subtag-registry@npm:^0.3.20":
+ version: 0.3.23
+ resolution: "language-subtag-registry@npm:0.3.23"
+ checksum: 10/fe13ed74ab9f862db8e5747b98cc9aa08d52a19f85b5cdb4975cd364c8539bd2da3380e4560d2dbbd728ec33dff8a4b4421fcb2e5b1b1bdaa21d16f91a54d0d4
+ languageName: node
+ linkType: hard
+
+"language-tags@npm:^1.0.9":
+ version: 1.0.9
+ resolution: "language-tags@npm:1.0.9"
+ dependencies:
+ language-subtag-registry: "npm:^0.3.20"
+ checksum: 10/d3a7c14b694e67f519153d6df6cb200681648d38d623c3bfa9d6a66a5ec5493628acb88e9df5aceef3cf1902ab263a205e7d59ee4cf1d6bb67e707b83538bd6d
+ languageName: node
+ linkType: hard
+
"latest-version@npm:^3.0.0":
version: 3.1.0
resolution: "latest-version@npm:3.1.0"
@@ -22727,6 +23891,16 @@ __metadata:
languageName: node
linkType: hard
+"levn@npm:^0.4.1":
+ version: 0.4.1
+ resolution: "levn@npm:0.4.1"
+ dependencies:
+ prelude-ls: "npm:^1.2.1"
+ type-check: "npm:~0.4.0"
+ checksum: 10/2e4720ff79f21ae08d42374b0a5c2f664c5be8b6c8f565bb4e1315c96ed3a8acaa9de788ffed82d7f2378cf36958573de07ef92336cb5255ed74d08b8318c9ee
+ languageName: node
+ linkType: hard
+
"levn@npm:~0.3.0":
version: 0.3.0
resolution: "levn@npm:0.3.0"
@@ -23281,6 +24455,15 @@ __metadata:
languageName: node
linkType: hard
+"locate-path@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "locate-path@npm:6.0.0"
+ dependencies:
+ p-locate: "npm:^5.0.0"
+ checksum: 10/72eb661788a0368c099a184c59d2fee760b3831c9c1c33955e8a19ae4a21b4116e53fa736dc086cdeb9fce9f7cc508f2f92d2d3aae516f133e16a2bb59a39f5a
+ languageName: node
+ linkType: hard
+
"lock-verify@npm:^2.0.2, lock-verify@npm:^2.1.0, lock-verify@npm:^2.2.2":
version: 2.2.2
resolution: "lock-verify@npm:2.2.2"
@@ -23855,7 +25038,7 @@ __metadata:
languageName: node
linkType: hard
-"mapbox-gl@npm:^2.15.0":
+"mapbox-gl@npm:^2.15.0, mapbox-gl@npm:^2.8.2":
version: 2.15.0
resolution: "mapbox-gl@npm:2.15.0"
dependencies:
@@ -24192,7 +25375,7 @@ __metadata:
languageName: node
linkType: hard
-"memoize-one@npm:>=3.1.1 <6, memoize-one@npm:^5.0.0":
+"memoize-one@npm:>=3.1.1 <6, memoize-one@npm:^5.0.0, memoize-one@npm:^5.1.1":
version: 5.2.1
resolution: "memoize-one@npm:5.2.1"
checksum: 10/b7141dc148b5c6fdd51e77ecf0421fd2581681eb8756e0b3dfbd4fe765b5e2b5a6bc90214bb6f19a96b6aed44de17eda3407142a7be9e24ccd0774bbd9874d1b
@@ -24840,7 +26023,7 @@ __metadata:
languageName: node
linkType: hard
-"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
+"minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
version: 3.1.2
resolution: "minimatch@npm:3.1.2"
dependencies:
@@ -26137,6 +27320,41 @@ __metadata:
languageName: node
linkType: hard
+"object.assign@npm:^4.1.5":
+ version: 4.1.5
+ resolution: "object.assign@npm:4.1.5"
+ dependencies:
+ call-bind: "npm:^1.0.5"
+ define-properties: "npm:^1.2.1"
+ has-symbols: "npm:^1.0.3"
+ object-keys: "npm:^1.1.1"
+ checksum: 10/dbb22da4cda82e1658349ea62b80815f587b47131b3dd7a4ab7f84190ab31d206bbd8fe7e26ae3220c55b65725ac4529825f6142154211220302aa6b1518045d
+ languageName: node
+ linkType: hard
+
+"object.entries@npm:^1.1.8":
+ version: 1.1.8
+ resolution: "object.entries@npm:1.1.8"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-object-atoms: "npm:^1.0.0"
+ checksum: 10/2301918fbd1ee697cf6ff7cd94f060c738c0a7d92b22fd24c7c250e9b593642c9707ad2c44d339303c1439c5967d8964251cdfc855f7f6ec55db2dd79e8dc2a7
+ languageName: node
+ linkType: hard
+
+"object.fromentries@npm:^2.0.7, object.fromentries@npm:^2.0.8":
+ version: 2.0.8
+ resolution: "object.fromentries@npm:2.0.8"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.2"
+ es-object-atoms: "npm:^1.0.0"
+ checksum: 10/5b2e80f7af1778b885e3d06aeb335dcc86965e39464671adb7167ab06ac3b0f5dd2e637a90d8ebd7426d69c6f135a4753ba3dd7d0fe2a7030cf718dcb910fd92
+ languageName: node
+ linkType: hard
+
"object.getownpropertydescriptors@npm:^2.0.3, object.getownpropertydescriptors@npm:^2.1.0":
version: 2.1.7
resolution: "object.getownpropertydescriptors@npm:2.1.7"
@@ -26150,6 +27368,17 @@ __metadata:
languageName: node
linkType: hard
+"object.groupby@npm:^1.0.1":
+ version: 1.0.3
+ resolution: "object.groupby@npm:1.0.3"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.2"
+ checksum: 10/44cb86dd2c660434be65f7585c54b62f0425b0c96b5c948d2756be253ef06737da7e68d7106e35506ce4a44d16aa85a413d11c5034eb7ce5579ec28752eb42d0
+ languageName: node
+ linkType: hard
+
"object.values@npm:^1.1.0":
version: 1.1.7
resolution: "object.values@npm:1.1.7"
@@ -26161,6 +27390,17 @@ __metadata:
languageName: node
linkType: hard
+"object.values@npm:^1.1.6, object.values@npm:^1.1.7, object.values@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "object.values@npm:1.2.0"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-object-atoms: "npm:^1.0.0"
+ checksum: 10/db2e498019c354428c5dd30d02980d920ac365b155fce4dcf63eb9433f98ccf0f72624309e182ce7cc227c95e45d474e1d483418e60de2293dd23fa3ebe34903
+ languageName: node
+ linkType: hard
+
"obuf@npm:^1.0.0, obuf@npm:^1.1.2":
version: 1.1.2
resolution: "obuf@npm:1.1.2"
@@ -26290,6 +27530,20 @@ __metadata:
languageName: node
linkType: hard
+"optionator@npm:^0.9.3":
+ version: 0.9.4
+ resolution: "optionator@npm:0.9.4"
+ dependencies:
+ deep-is: "npm:^0.1.3"
+ fast-levenshtein: "npm:^2.0.6"
+ levn: "npm:^0.4.1"
+ prelude-ls: "npm:^1.2.1"
+ type-check: "npm:^0.4.0"
+ word-wrap: "npm:^1.2.5"
+ checksum: 10/a8398559c60aef88d7f353a4f98dcdff6090a4e70f874c827302bf1213d9106a1c4d5fcb68dacb1feb3c30a04c4102f41047aa55d4c576b863d6fc876e001af6
+ languageName: node
+ linkType: hard
+
"ordered-binary@npm:^1.4.0":
version: 1.4.1
resolution: "ordered-binary@npm:1.4.1"
@@ -26393,6 +27647,15 @@ __metadata:
languageName: node
linkType: hard
+"p-limit@npm:^3.0.2":
+ version: 3.1.0
+ resolution: "p-limit@npm:3.1.0"
+ dependencies:
+ yocto-queue: "npm:^0.1.0"
+ checksum: 10/7c3690c4dbf62ef625671e20b7bdf1cbc9534e83352a2780f165b0d3ceba21907e77ad63401708145ca4e25bfc51636588d89a8c0aeb715e6c37d1c066430360
+ languageName: node
+ linkType: hard
+
"p-limit@npm:^5.0.0":
version: 5.0.0
resolution: "p-limit@npm:5.0.0"
@@ -26429,6 +27692,15 @@ __metadata:
languageName: node
linkType: hard
+"p-locate@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "p-locate@npm:5.0.0"
+ dependencies:
+ p-limit: "npm:^3.0.2"
+ checksum: 10/1623088f36cf1cbca58e9b61c4e62bf0c60a07af5ae1ca99a720837356b5b6c5ba3eb1b2127e47a06865fee59dd0453cad7cc844cda9d5a62ac1a5a51b7c86d3
+ languageName: node
+ linkType: hard
+
"p-map@npm:^2.0.0":
version: 2.1.0
resolution: "p-map@npm:2.1.0"
@@ -27031,6 +28303,13 @@ __metadata:
languageName: node
linkType: hard
+"popper.js@npm:^1.14.4, popper.js@npm:^1.16.1":
+ version: 1.16.1
+ resolution: "popper.js@npm:1.16.1"
+ checksum: 10/71338c86faf9b66ce60c3cdd7fb2ed742944e5d2765a188f269239fee2980aa6223b77b41302d1b6eb7d724e611092f9a2576d0048ac2071b605291abc72c0cf
+ languageName: node
+ linkType: hard
+
"possible-typed-array-names@npm:^1.0.0":
version: 1.0.0
resolution: "possible-typed-array-names@npm:1.0.0"
@@ -28017,6 +29296,13 @@ __metadata:
languageName: node
linkType: hard
+"prelude-ls@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "prelude-ls@npm:1.2.1"
+ checksum: 10/0b9d2c76801ca652a7f64892dd37b7e3fab149a37d2424920099bf894acccc62abb4424af2155ab36dea8744843060a2d8ddc983518d0b1e22265a22324b72ed
+ languageName: node
+ linkType: hard
+
"prelude-ls@npm:~1.1.2":
version: 1.1.2
resolution: "prelude-ls@npm:1.1.2"
@@ -28503,6 +29789,13 @@ __metadata:
languageName: node
linkType: hard
+"raf-schd@npm:^4.0.2":
+ version: 4.0.3
+ resolution: "raf-schd@npm:4.0.3"
+ checksum: 10/45514041c5ad31fa96aef3bb3c572a843b92da2f2cd1cb4a47c9ad58e48761d3a4126e18daa32b2bfa0bc2551a42d8f324a0e40e536cb656969929602b4e8b58
+ languageName: node
+ linkType: hard
+
"raf@npm:^3.1.0":
version: 3.4.1
resolution: "raf@npm:3.4.1"
@@ -28629,6 +29922,24 @@ __metadata:
languageName: node
linkType: hard
+"react-beautiful-dnd@npm:^13.1.0":
+ version: 13.1.1
+ resolution: "react-beautiful-dnd@npm:13.1.1"
+ dependencies:
+ "@babel/runtime": "npm:^7.9.2"
+ css-box-model: "npm:^1.2.0"
+ memoize-one: "npm:^5.1.1"
+ raf-schd: "npm:^4.0.2"
+ react-redux: "npm:^7.2.0"
+ redux: "npm:^4.0.4"
+ use-memo-one: "npm:^1.1.1"
+ peerDependencies:
+ react: ^16.8.5 || ^17.0.0 || ^18.0.0
+ react-dom: ^16.8.5 || ^17.0.0 || ^18.0.0
+ checksum: 10/2de8162a74f7fc78294e5a928b92d3fff02c579d137a25d53b1ab4313abeb108709bb7281512f7f94d18257de3122b8c85cb5a8375113cb8657088b1a9bda65b
+ languageName: node
+ linkType: hard
+
"react-clientside-effect@npm:^1.2.6":
version: 1.2.6
resolution: "react-clientside-effect@npm:1.2.6"
@@ -29092,6 +30403,23 @@ __metadata:
languageName: node
linkType: hard
+"react-popper@npm:^1.3.11":
+ version: 1.3.11
+ resolution: "react-popper@npm:1.3.11"
+ dependencies:
+ "@babel/runtime": "npm:^7.1.2"
+ "@hypnosphi/create-react-context": "npm:^0.3.1"
+ deep-equal: "npm:^1.1.1"
+ popper.js: "npm:^1.14.4"
+ prop-types: "npm:^15.6.1"
+ typed-styles: "npm:^0.0.7"
+ warning: "npm:^4.0.2"
+ peerDependencies:
+ react: 0.14.x || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 10/1f7115da1dd0fdca1fc266d2cefa79ed00eca560f72399a9149e9a8a4bc3e9d9fe4e2955bbbe2e3326607ceb3bd4a971e501fb0d6bbf57bf492c0072ae39c2c6
+ languageName: node
+ linkType: hard
+
"react-popper@npm:^2.2.5, react-popper@npm:^2.3.0":
version: 2.3.0
resolution: "react-popper@npm:2.3.0"
@@ -29848,7 +31176,7 @@ __metadata:
languageName: node
linkType: hard
-"redux@npm:^4.0.0, redux@npm:^4.0.5, redux@npm:^4.1.1":
+"redux@npm:^4.0.0, redux@npm:^4.0.4, redux@npm:^4.0.5, redux@npm:^4.1.1":
version: 4.2.1
resolution: "redux@npm:4.2.1"
dependencies:
@@ -29864,6 +31192,21 @@ __metadata:
languageName: node
linkType: hard
+"reflect.getprototypeof@npm:^1.0.4":
+ version: 1.0.6
+ resolution: "reflect.getprototypeof@npm:1.0.6"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.1"
+ es-errors: "npm:^1.3.0"
+ get-intrinsic: "npm:^1.2.4"
+ globalthis: "npm:^1.0.3"
+ which-builtin-type: "npm:^1.1.3"
+ checksum: 10/518f6457e4bb470c9b317d239c62d4b4a05678b7eae4f1c3f4332fad379b3ea6d2d8999bfad448547fdba8fb77e4725cfe8c6440d0168ff387f16b4f19f759ad
+ languageName: node
+ linkType: hard
+
"refractor@npm:^3.6.0":
version: 3.6.0
resolution: "refractor@npm:3.6.0"
@@ -29939,6 +31282,18 @@ __metadata:
languageName: node
linkType: hard
+"regexp.prototype.flags@npm:^1.5.2":
+ version: 1.5.2
+ resolution: "regexp.prototype.flags@npm:1.5.2"
+ dependencies:
+ call-bind: "npm:^1.0.6"
+ define-properties: "npm:^1.2.1"
+ es-errors: "npm:^1.3.0"
+ set-function-name: "npm:^2.0.1"
+ checksum: 10/9fffc01da9c4e12670ff95bc5204364615fcc12d86fc30642765af908675678ebb0780883c874b2dbd184505fb52fa603d80073ecf69f461ce7f56b15d10be9c
+ languageName: node
+ linkType: hard
+
"regexpu-core@npm:^5.3.1":
version: 5.3.2
resolution: "regexpu-core@npm:5.3.2"
@@ -30279,7 +31634,7 @@ __metadata:
languageName: node
linkType: hard
-"resolve@npm:^1.1.5":
+"resolve@npm:^1.1.5, resolve@npm:^1.22.0, resolve@npm:^1.22.4":
version: 1.22.8
resolution: "resolve@npm:1.22.8"
dependencies:
@@ -30305,6 +31660,19 @@ __metadata:
languageName: node
linkType: hard
+"resolve@npm:^2.0.0-next.5":
+ version: 2.0.0-next.5
+ resolution: "resolve@npm:2.0.0-next.5"
+ dependencies:
+ is-core-module: "npm:^2.13.0"
+ path-parse: "npm:^1.0.7"
+ supports-preserve-symlinks-flag: "npm:^1.0.0"
+ bin:
+ resolve: bin/resolve
+ checksum: 10/2d6fd28699f901744368e6f2032b4268b4c7b9185fd8beb64f68c93ac6b22e52ae13560ceefc96241a665b985edf9ffd393ae26d2946a7d3a07b7007b7d51e79
+ languageName: node
+ linkType: hard
+
"resolve@patch:resolve@npm%3A1.17.0#optional!builtin":
version: 1.17.0
resolution: "resolve@patch:resolve@npm%3A1.17.0#optional!builtin::version=1.17.0&hash=c3c19d"
@@ -30314,7 +31682,7 @@ __metadata:
languageName: node
linkType: hard
-"resolve@patch:resolve@npm%3A^1.1.5#optional!builtin":
+"resolve@patch:resolve@npm%3A^1.1.5#optional!builtin, resolve@patch:resolve@npm%3A^1.22.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin":
version: 1.22.8
resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d"
dependencies:
@@ -30340,6 +31708,19 @@ __metadata:
languageName: node
linkType: hard
+"resolve@patch:resolve@npm%3A^2.0.0-next.5#optional!builtin":
+ version: 2.0.0-next.5
+ resolution: "resolve@patch:resolve@npm%3A2.0.0-next.5#optional!builtin::version=2.0.0-next.5&hash=c3c19d"
+ dependencies:
+ is-core-module: "npm:^2.13.0"
+ path-parse: "npm:^1.0.7"
+ supports-preserve-symlinks-flag: "npm:^1.0.0"
+ bin:
+ resolve: bin/resolve
+ checksum: 10/05fa778de9d0347c8b889eb7a18f1f06bf0f801b0eb4610b4871a4b2f22e220900cf0ad525e94f990bb8d8921c07754ab2122c0c225ab4cdcea98f36e64fa4c2
+ languageName: node
+ linkType: hard
+
"responselike@npm:^2.0.0":
version: 2.0.1
resolution: "responselike@npm:2.0.1"
@@ -30908,6 +32289,18 @@ __metadata:
languageName: node
linkType: hard
+"safe-array-concat@npm:^1.1.2":
+ version: 1.1.2
+ resolution: "safe-array-concat@npm:1.1.2"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ get-intrinsic: "npm:^1.2.4"
+ has-symbols: "npm:^1.0.3"
+ isarray: "npm:^2.0.5"
+ checksum: 10/a54f8040d7cb696a1ee38d19cc71ab3cfb654b9b81bae00c6459618cfad8214ece7e6666592f9c925aafef43d0a20c5e6fbb3413a2b618e1ce9d516a2e6dcfc5
+ languageName: node
+ linkType: hard
+
"safe-buffer@npm:5.1.2, safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1":
version: 5.1.2
resolution: "safe-buffer@npm:5.1.2"
@@ -30940,6 +32333,17 @@ __metadata:
languageName: node
linkType: hard
+"safe-regex-test@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "safe-regex-test@npm:1.0.3"
+ dependencies:
+ call-bind: "npm:^1.0.6"
+ es-errors: "npm:^1.3.0"
+ is-regex: "npm:^1.1.4"
+ checksum: 10/b04de61114b10274d92e25b6de7ccb5de07f11ea15637ff636de4b5190c0f5cd8823fe586dde718504cf78055437d70fd8804976894df502fcf5a210c970afb3
+ languageName: node
+ linkType: hard
+
"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0, safer-buffer@npm:^2.0.2, safer-buffer@npm:^2.1.0, safer-buffer@npm:^2.1.2, safer-buffer@npm:~2.1.0":
version: 2.1.2
resolution: "safer-buffer@npm:2.1.2"
@@ -30947,175 +32351,175 @@ __metadata:
languageName: node
linkType: hard
-"sass-embedded-android-arm64@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-android-arm64@npm:1.79.1"
+"sass-embedded-android-arm64@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-android-arm64@npm:1.80.6"
conditions: os=android & cpu=arm64
languageName: node
linkType: hard
-"sass-embedded-android-arm@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-android-arm@npm:1.79.1"
+"sass-embedded-android-arm@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-android-arm@npm:1.80.6"
conditions: os=android & cpu=arm
languageName: node
linkType: hard
-"sass-embedded-android-ia32@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-android-ia32@npm:1.79.1"
+"sass-embedded-android-ia32@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-android-ia32@npm:1.80.6"
conditions: os=android & cpu=ia32
languageName: node
linkType: hard
-"sass-embedded-android-riscv64@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-android-riscv64@npm:1.79.1"
+"sass-embedded-android-riscv64@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-android-riscv64@npm:1.80.6"
conditions: os=android & cpu=riscv64
languageName: node
linkType: hard
-"sass-embedded-android-x64@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-android-x64@npm:1.79.1"
+"sass-embedded-android-x64@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-android-x64@npm:1.80.6"
conditions: os=android & cpu=x64
languageName: node
linkType: hard
-"sass-embedded-darwin-arm64@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-darwin-arm64@npm:1.79.1"
+"sass-embedded-darwin-arm64@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-darwin-arm64@npm:1.80.6"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
-"sass-embedded-darwin-x64@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-darwin-x64@npm:1.79.1"
+"sass-embedded-darwin-x64@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-darwin-x64@npm:1.80.6"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
-"sass-embedded-linux-arm64@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-linux-arm64@npm:1.79.1"
+"sass-embedded-linux-arm64@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-linux-arm64@npm:1.80.6"
conditions: os=linux & cpu=arm64
languageName: node
linkType: hard
-"sass-embedded-linux-arm@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-linux-arm@npm:1.79.1"
+"sass-embedded-linux-arm@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-linux-arm@npm:1.80.6"
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
-"sass-embedded-linux-ia32@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-linux-ia32@npm:1.79.1"
+"sass-embedded-linux-ia32@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-linux-ia32@npm:1.80.6"
conditions: os=linux & cpu=ia32
languageName: node
linkType: hard
-"sass-embedded-linux-musl-arm64@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-linux-musl-arm64@npm:1.79.1"
+"sass-embedded-linux-musl-arm64@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-linux-musl-arm64@npm:1.80.6"
conditions: os=linux & cpu=arm64
languageName: node
linkType: hard
-"sass-embedded-linux-musl-arm@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-linux-musl-arm@npm:1.79.1"
+"sass-embedded-linux-musl-arm@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-linux-musl-arm@npm:1.80.6"
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
-"sass-embedded-linux-musl-ia32@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-linux-musl-ia32@npm:1.79.1"
+"sass-embedded-linux-musl-ia32@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-linux-musl-ia32@npm:1.80.6"
conditions: os=linux & cpu=ia32
languageName: node
linkType: hard
-"sass-embedded-linux-musl-riscv64@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-linux-musl-riscv64@npm:1.79.1"
+"sass-embedded-linux-musl-riscv64@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-linux-musl-riscv64@npm:1.80.6"
conditions: os=linux & cpu=riscv64
languageName: node
linkType: hard
-"sass-embedded-linux-musl-x64@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-linux-musl-x64@npm:1.79.1"
+"sass-embedded-linux-musl-x64@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-linux-musl-x64@npm:1.80.6"
conditions: os=linux & cpu=x64
languageName: node
linkType: hard
-"sass-embedded-linux-riscv64@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-linux-riscv64@npm:1.79.1"
+"sass-embedded-linux-riscv64@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-linux-riscv64@npm:1.80.6"
conditions: os=linux & cpu=riscv64
languageName: node
linkType: hard
-"sass-embedded-linux-x64@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-linux-x64@npm:1.79.1"
+"sass-embedded-linux-x64@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-linux-x64@npm:1.80.6"
conditions: os=linux & cpu=x64
languageName: node
linkType: hard
-"sass-embedded-win32-arm64@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-win32-arm64@npm:1.79.1"
+"sass-embedded-win32-arm64@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-win32-arm64@npm:1.80.6"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
-"sass-embedded-win32-ia32@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-win32-ia32@npm:1.79.1"
+"sass-embedded-win32-ia32@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-win32-ia32@npm:1.80.6"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
-"sass-embedded-win32-x64@npm:1.79.1":
- version: 1.79.1
- resolution: "sass-embedded-win32-x64@npm:1.79.1"
+"sass-embedded-win32-x64@npm:1.80.6":
+ version: 1.80.6
+ resolution: "sass-embedded-win32-x64@npm:1.80.6"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
"sass-embedded@npm:^1.79.1":
- version: 1.79.1
- resolution: "sass-embedded@npm:1.79.1"
+ version: 1.80.6
+ resolution: "sass-embedded@npm:1.80.6"
dependencies:
"@bufbuild/protobuf": "npm:^2.0.0"
buffer-builder: "npm:^0.2.0"
colorjs.io: "npm:^0.5.0"
immutable: "npm:^4.0.0"
rxjs: "npm:^7.4.0"
- sass-embedded-android-arm: "npm:1.79.1"
- sass-embedded-android-arm64: "npm:1.79.1"
- sass-embedded-android-ia32: "npm:1.79.1"
- sass-embedded-android-riscv64: "npm:1.79.1"
- sass-embedded-android-x64: "npm:1.79.1"
- sass-embedded-darwin-arm64: "npm:1.79.1"
- sass-embedded-darwin-x64: "npm:1.79.1"
- sass-embedded-linux-arm: "npm:1.79.1"
- sass-embedded-linux-arm64: "npm:1.79.1"
- sass-embedded-linux-ia32: "npm:1.79.1"
- sass-embedded-linux-musl-arm: "npm:1.79.1"
- sass-embedded-linux-musl-arm64: "npm:1.79.1"
- sass-embedded-linux-musl-ia32: "npm:1.79.1"
- sass-embedded-linux-musl-riscv64: "npm:1.79.1"
- sass-embedded-linux-musl-x64: "npm:1.79.1"
- sass-embedded-linux-riscv64: "npm:1.79.1"
- sass-embedded-linux-x64: "npm:1.79.1"
- sass-embedded-win32-arm64: "npm:1.79.1"
- sass-embedded-win32-ia32: "npm:1.79.1"
- sass-embedded-win32-x64: "npm:1.79.1"
+ sass-embedded-android-arm: "npm:1.80.6"
+ sass-embedded-android-arm64: "npm:1.80.6"
+ sass-embedded-android-ia32: "npm:1.80.6"
+ sass-embedded-android-riscv64: "npm:1.80.6"
+ sass-embedded-android-x64: "npm:1.80.6"
+ sass-embedded-darwin-arm64: "npm:1.80.6"
+ sass-embedded-darwin-x64: "npm:1.80.6"
+ sass-embedded-linux-arm: "npm:1.80.6"
+ sass-embedded-linux-arm64: "npm:1.80.6"
+ sass-embedded-linux-ia32: "npm:1.80.6"
+ sass-embedded-linux-musl-arm: "npm:1.80.6"
+ sass-embedded-linux-musl-arm64: "npm:1.80.6"
+ sass-embedded-linux-musl-ia32: "npm:1.80.6"
+ sass-embedded-linux-musl-riscv64: "npm:1.80.6"
+ sass-embedded-linux-musl-x64: "npm:1.80.6"
+ sass-embedded-linux-riscv64: "npm:1.80.6"
+ sass-embedded-linux-x64: "npm:1.80.6"
+ sass-embedded-win32-arm64: "npm:1.80.6"
+ sass-embedded-win32-ia32: "npm:1.80.6"
+ sass-embedded-win32-x64: "npm:1.80.6"
supports-color: "npm:^8.1.1"
varint: "npm:^6.0.0"
dependenciesMeta:
@@ -31161,7 +32565,7 @@ __metadata:
optional: true
bin:
sass: dist/bin/sass.js
- checksum: 10/e276ef14414dbac30007b46e2ef7ad7b0a7756005b1df9ae9224cd7db39b5ec42c2e6a742daa737d861f0eac898f18d934d45b1d675038fb4218b98432042e5d
+ checksum: 10/e779d6d7f4b80611af2812bd9dfd08d230b311dc6966ce8727e371b8cc8bd88c38a3c1c93cbf2aa7499ff7b9ebf504190a113d0a1cd029d6fbb44bf10500a89e
languageName: node
linkType: hard
@@ -31371,7 +32775,7 @@ __metadata:
languageName: node
linkType: hard
-"semver@npm:^7.1.2, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4":
+"semver@npm:^7.1.2, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4":
version: 7.5.4
resolution: "semver@npm:7.5.4"
dependencies:
@@ -31500,6 +32904,18 @@ __metadata:
languageName: node
linkType: hard
+"set-function-name@npm:^2.0.1, set-function-name@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "set-function-name@npm:2.0.2"
+ dependencies:
+ define-data-property: "npm:^1.1.4"
+ es-errors: "npm:^1.3.0"
+ functions-have-names: "npm:^1.2.3"
+ has-property-descriptors: "npm:^1.0.2"
+ checksum: 10/c7614154a53ebf8c0428a6c40a3b0b47dac30587c1a19703d1b75f003803f73cdfa6a93474a9ba678fa565ef5fbddc2fae79bca03b7d22ab5fd5163dbe571a74
+ languageName: node
+ linkType: hard
+
"setimmediate@npm:^1.0.5":
version: 1.0.5
resolution: "setimmediate@npm:1.0.5"
@@ -32351,6 +33767,36 @@ __metadata:
languageName: node
linkType: hard
+"string.prototype.includes@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "string.prototype.includes@npm:2.0.0"
+ dependencies:
+ define-properties: "npm:^1.1.3"
+ es-abstract: "npm:^1.17.5"
+ checksum: 10/34c1e71ac5cab469bef52a4f3d983d141ca61c43b9fe8859574c8829822aad0a61fce1dddfaf8a48ad7ac5032a1730c19f1fb2d09715f57025cd138b1ad4b0e4
+ languageName: node
+ linkType: hard
+
+"string.prototype.matchall@npm:^4.0.11":
+ version: 4.0.11
+ resolution: "string.prototype.matchall@npm:4.0.11"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.2"
+ es-errors: "npm:^1.3.0"
+ es-object-atoms: "npm:^1.0.0"
+ get-intrinsic: "npm:^1.2.4"
+ gopd: "npm:^1.0.1"
+ has-symbols: "npm:^1.0.3"
+ internal-slot: "npm:^1.0.7"
+ regexp.prototype.flags: "npm:^1.5.2"
+ set-function-name: "npm:^2.0.2"
+ side-channel: "npm:^1.0.6"
+ checksum: 10/a902ff4500f909f2a08e55cc5ab1ffbbc905f603b36837674370ee3921058edd0392147e15891910db62a2f31ace2adaf065eaa3bc6e9810bdbc8ca48e05a7b5
+ languageName: node
+ linkType: hard
+
"string.prototype.matchall@npm:^4.0.6":
version: 4.0.10
resolution: "string.prototype.matchall@npm:4.0.10"
@@ -32379,6 +33825,16 @@ __metadata:
languageName: node
linkType: hard
+"string.prototype.repeat@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "string.prototype.repeat@npm:1.0.0"
+ dependencies:
+ define-properties: "npm:^1.1.3"
+ es-abstract: "npm:^1.17.5"
+ checksum: 10/4b1bd91b75fa8fdf0541625184ebe80e445a465ce4253c19c3bccd633898005dadae0f74b85ae72662a53aafb8035bf48f8f5c0755aec09bc106a7f13959d05e
+ languageName: node
+ linkType: hard
+
"string.prototype.trim@npm:^1.2.8":
version: 1.2.8
resolution: "string.prototype.trim@npm:1.2.8"
@@ -32390,6 +33846,18 @@ __metadata:
languageName: node
linkType: hard
+"string.prototype.trim@npm:^1.2.9":
+ version: 1.2.9
+ resolution: "string.prototype.trim@npm:1.2.9"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.0"
+ es-object-atoms: "npm:^1.0.0"
+ checksum: 10/b2170903de6a2fb5a49bb8850052144e04b67329d49f1343cdc6a87cb24fb4e4b8ad00d3e273a399b8a3d8c32c89775d93a8f43cb42fbff303f25382079fb58a
+ languageName: node
+ linkType: hard
+
"string.prototype.trimend@npm:^1.0.7":
version: 1.0.7
resolution: "string.prototype.trimend@npm:1.0.7"
@@ -32401,6 +33869,17 @@ __metadata:
languageName: node
linkType: hard
+"string.prototype.trimend@npm:^1.0.8":
+ version: 1.0.8
+ resolution: "string.prototype.trimend@npm:1.0.8"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-object-atoms: "npm:^1.0.0"
+ checksum: 10/c2e862ae724f95771da9ea17c27559d4eeced9208b9c20f69bbfcd1b9bc92375adf8af63a103194dba17c4cc4a5cb08842d929f415ff9d89c062d44689c8761b
+ languageName: node
+ linkType: hard
+
"string.prototype.trimstart@npm:^1.0.7":
version: 1.0.7
resolution: "string.prototype.trimstart@npm:1.0.7"
@@ -32412,6 +33891,17 @@ __metadata:
languageName: node
linkType: hard
+"string.prototype.trimstart@npm:^1.0.8":
+ version: 1.0.8
+ resolution: "string.prototype.trimstart@npm:1.0.8"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-object-atoms: "npm:^1.0.0"
+ checksum: 10/160167dfbd68e6f7cb9f51a16074eebfce1571656fc31d40c3738ca9e30e35496f2c046fe57b6ad49f65f238a152be8c86fd9a2dd58682b5eba39dad995b3674
+ languageName: node
+ linkType: hard
+
"string_decoder@npm:^1.1.1":
version: 1.3.0
resolution: "string_decoder@npm:1.3.0"
@@ -33175,6 +34665,13 @@ __metadata:
languageName: node
linkType: hard
+"tiny-invariant@npm:^1.0.6":
+ version: 1.3.3
+ resolution: "tiny-invariant@npm:1.3.3"
+ checksum: 10/5e185c8cc2266967984ce3b352a4e57cb89dad5a8abb0dea21468a6ecaa67cd5bb47a3b7a85d08041008644af4f667fb8b6575ba38ba5fb00b3b5068306e59fe
+ languageName: node
+ linkType: hard
+
"tiny-relative-date@npm:^1.3.0":
version: 1.3.0
resolution: "tiny-relative-date@npm:1.3.0"
@@ -33506,6 +35003,18 @@ __metadata:
languageName: node
linkType: hard
+"tsconfig-paths@npm:^3.14.1, tsconfig-paths@npm:^3.15.0":
+ version: 3.15.0
+ resolution: "tsconfig-paths@npm:3.15.0"
+ dependencies:
+ "@types/json5": "npm:^0.0.29"
+ json5: "npm:^1.0.2"
+ minimist: "npm:^1.2.6"
+ strip-bom: "npm:^3.0.0"
+ checksum: 10/2041beaedc6c271fc3bedd12e0da0cc553e65d030d4ff26044b771fac5752d0460944c0b5e680f670c2868c95c664a256cec960ae528888db6ded83524e33a14
+ languageName: node
+ linkType: hard
+
"tslib@npm:2.0.1":
version: 2.0.1
resolution: "tslib@npm:2.0.1"
@@ -33513,6 +35022,13 @@ __metadata:
languageName: node
linkType: hard
+"tslib@npm:^1.8.1":
+ version: 1.14.1
+ resolution: "tslib@npm:1.14.1"
+ checksum: 10/7dbf34e6f55c6492637adb81b555af5e3b4f9cc6b998fb440dac82d3b42bdc91560a35a5fb75e20e24a076c651438234da6743d139e4feabf0783f3cdfe1dddb
+ languageName: node
+ linkType: hard
+
"tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:~2.6.2":
version: 2.6.2
resolution: "tslib@npm:2.6.2"
@@ -33527,6 +35043,24 @@ __metadata:
languageName: node
linkType: hard
+"tslib@npm:~2.5.0":
+ version: 2.5.3
+ resolution: "tslib@npm:2.5.3"
+ checksum: 10/d507e60ebe2480af4efc1655dfdb2762bb6ca57d76c4ba680375af801493648c2e97808bbd7e54691eb40e33a7e2e793cdef9c24ce6a8539b03cac8b26e09a61
+ languageName: node
+ linkType: hard
+
+"tsutils@npm:^3.21.0":
+ version: 3.21.0
+ resolution: "tsutils@npm:3.21.0"
+ dependencies:
+ tslib: "npm:^1.8.1"
+ peerDependencies:
+ typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+ checksum: 10/ea036bec1dd024e309939ffd49fda7a351c0e87a1b8eb049570dd119d447250e2c56e0e6c00554e8205760e7417793fdebff752a46e573fbe07d4f375502a5b2
+ languageName: node
+ linkType: hard
+
"tsx@npm:^4.11.2":
version: 4.11.2
resolution: "tsx@npm:4.11.2"
@@ -33659,6 +35193,15 @@ __metadata:
languageName: node
linkType: hard
+"type-check@npm:^0.4.0, type-check@npm:~0.4.0":
+ version: 0.4.0
+ resolution: "type-check@npm:0.4.0"
+ dependencies:
+ prelude-ls: "npm:^1.2.1"
+ checksum: 10/14687776479d048e3c1dbfe58a2409e00367810d6960c0f619b33793271ff2a27f81b52461f14a162f1f89a9b1d8da1b237fc7c99b0e1fdcec28ec63a86b1fec
+ languageName: node
+ linkType: hard
+
"type-check@npm:~0.3.2":
version: 0.3.2
resolution: "type-check@npm:0.3.2"
@@ -33738,6 +35281,17 @@ __metadata:
languageName: node
linkType: hard
+"typed-array-buffer@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "typed-array-buffer@npm:1.0.2"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ es-errors: "npm:^1.3.0"
+ is-typed-array: "npm:^1.1.13"
+ checksum: 10/02ffc185d29c6df07968272b15d5319a1610817916ec8d4cd670ded5d1efe72901541ff2202fcc622730d8a549c76e198a2f74e312eabbfb712ed907d45cbb0b
+ languageName: node
+ linkType: hard
+
"typed-array-byte-length@npm:^1.0.0":
version: 1.0.0
resolution: "typed-array-byte-length@npm:1.0.0"
@@ -33750,6 +35304,19 @@ __metadata:
languageName: node
linkType: hard
+"typed-array-byte-length@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "typed-array-byte-length@npm:1.0.1"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ for-each: "npm:^0.3.3"
+ gopd: "npm:^1.0.1"
+ has-proto: "npm:^1.0.3"
+ is-typed-array: "npm:^1.1.13"
+ checksum: 10/e4a38329736fe6a73b52a09222d4a9e8de14caaa4ff6ad8e55217f6705b017d9815b7284c85065b3b8a7704e226ccff1372a72b78c2a5b6b71b7bf662308c903
+ languageName: node
+ linkType: hard
+
"typed-array-byte-offset@npm:^1.0.0":
version: 1.0.0
resolution: "typed-array-byte-offset@npm:1.0.0"
@@ -33763,6 +35330,20 @@ __metadata:
languageName: node
linkType: hard
+"typed-array-byte-offset@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "typed-array-byte-offset@npm:1.0.2"
+ dependencies:
+ available-typed-arrays: "npm:^1.0.7"
+ call-bind: "npm:^1.0.7"
+ for-each: "npm:^0.3.3"
+ gopd: "npm:^1.0.1"
+ has-proto: "npm:^1.0.3"
+ is-typed-array: "npm:^1.1.13"
+ checksum: 10/ac26d720ebb2aacbc45e231347c359e6649f52e0cfe0e76e62005912f8030d68e4cb7b725b1754e8fdd48e433cb68df5a8620a3e420ad1457d666e8b29bf9150
+ languageName: node
+ linkType: hard
+
"typed-array-length@npm:^1.0.4":
version: 1.0.4
resolution: "typed-array-length@npm:1.0.4"
@@ -33774,6 +35355,27 @@ __metadata:
languageName: node
linkType: hard
+"typed-array-length@npm:^1.0.6":
+ version: 1.0.6
+ resolution: "typed-array-length@npm:1.0.6"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ for-each: "npm:^0.3.3"
+ gopd: "npm:^1.0.1"
+ has-proto: "npm:^1.0.3"
+ is-typed-array: "npm:^1.1.13"
+ possible-typed-array-names: "npm:^1.0.0"
+ checksum: 10/05e96cf4ff836743ebfc593d86133b8c30e83172cb5d16c56814d7bacfed57ce97e87ada9c4b2156d9aaa59f75cdef01c25bd9081c7826e0b869afbefc3e8c39
+ languageName: node
+ linkType: hard
+
+"typed-styles@npm:^0.0.7":
+ version: 0.0.7
+ resolution: "typed-styles@npm:0.0.7"
+ checksum: 10/24704459dd5119729a5c20d156f60a1a74489e0a6a57fc6bc93a0d167c805675cc3cadd42ae5d99d7906762e951a44bca9558101353c9d37bedbe8b1e6bf6e51
+ languageName: node
+ linkType: hard
+
"typedarray-to-buffer@npm:^3.1.5":
version: 3.1.5
resolution: "typedarray-to-buffer@npm:3.1.5"
@@ -33806,7 +35408,7 @@ __metadata:
languageName: node
linkType: hard
-"typescript@npm:^4.1.3":
+"typescript@npm:^4.1.3, typescript@npm:^4.5.4":
version: 4.9.5
resolution: "typescript@npm:4.9.5"
bin:
@@ -33836,7 +35438,7 @@ __metadata:
languageName: node
linkType: hard
-"typescript@patch:typescript@npm%3A^4.1.3#optional!builtin":
+"typescript@patch:typescript@npm%3A^4.1.3#optional!builtin, typescript@patch:typescript@npm%3A^4.5.4#optional!builtin":
version: 4.9.5
resolution: "typescript@patch:typescript@npm%3A4.9.5#optional!builtin::version=4.9.5&hash=289587"
bin:
@@ -34396,6 +35998,15 @@ __metadata:
languageName: node
linkType: hard
+"use-memo-one@npm:^1.1.1":
+ version: 1.1.3
+ resolution: "use-memo-one@npm:1.1.3"
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ checksum: 10/8f08eba26d69406b61bb4b8dacdd5a92bd6aef5b53d346dfe87954f7330ee10ecabc937cc7854635155d46053828e85c10b5a5aff7a04720e6a97b9f42999bac
+ languageName: node
+ linkType: hard
+
"use-react-router-breadcrumbs@npm:^3.2.1":
version: 3.2.1
resolution: "use-react-router-breadcrumbs@npm:3.2.1"
@@ -34434,21 +36045,21 @@ __metadata:
languageName: node
linkType: hard
-"use-sync-external-store@npm:1.2.2, use-sync-external-store@npm:^1.2.0":
- version: 1.2.2
- resolution: "use-sync-external-store@npm:1.2.2"
+"use-sync-external-store@npm:1.2.0, use-sync-external-store@npm:^1.0.0":
+ version: 1.2.0
+ resolution: "use-sync-external-store@npm:1.2.0"
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
- checksum: 10/671e9c190aab9a8374a5d468c6ba17f52c38b6fae970110bc196fc1e2b57204149aea9619be49a1bb5207fb6e51d8afd19c3bcb94afe61813fed039821461dc0
+ checksum: 10/a676216affc203876bd47981103f201f28c2731361bb186367e12d287a7566763213a8816910c6eb88265eccd4c230426eb783d64c373c4a180905be8820ed8e
languageName: node
linkType: hard
-"use-sync-external-store@npm:^1.0.0":
- version: 1.2.0
- resolution: "use-sync-external-store@npm:1.2.0"
+"use-sync-external-store@npm:^1.2.0":
+ version: 1.2.2
+ resolution: "use-sync-external-store@npm:1.2.2"
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
- checksum: 10/a676216affc203876bd47981103f201f28c2731361bb186367e12d287a7566763213a8816910c6eb88265eccd4c230426eb783d64c373c4a180905be8820ed8e
+ checksum: 10/671e9c190aab9a8374a5d468c6ba17f52c38b6fae970110bc196fc1e2b57204149aea9619be49a1bb5207fb6e51d8afd19c3bcb94afe61813fed039821461dc0
languageName: node
linkType: hard
@@ -34674,8 +36285,8 @@ __metadata:
linkType: hard
"vike@npm:^0.4.199":
- version: 0.4.200
- resolution: "vike@npm:0.4.200"
+ version: 0.4.201
+ resolution: "vike@npm:0.4.201"
dependencies:
"@brillout/import": "npm:^0.2.3"
"@brillout/json-serializer": "npm:^0.5.13"
@@ -34697,7 +36308,7 @@ __metadata:
optional: true
bin:
vike: node/cli/bin-entry.js
- checksum: 10/169aef59d4e683501414b10390169307c191fd43041782179e77d0633b8de6705161617f2e62c328fd294467d530ecffe2118307acc114cd0d52566eb7385e72
+ checksum: 10/c392207bc6fce32f6cc9e96b1afb5d2bef58fc79436d67ee6eeb2215f9dbdb5fd87924887478d439fda3d3c3e6fdfbb09955a6d50e6050e32d47f1186330ea32
languageName: node
linkType: hard
@@ -35061,7 +36672,7 @@ __metadata:
languageName: node
linkType: hard
-"warning@npm:^4.0.2":
+"warning@npm:^4.0.2, warning@npm:^4.0.3":
version: 4.0.3
resolution: "warning@npm:4.0.3"
dependencies:
@@ -35416,6 +37027,26 @@ __metadata:
languageName: node
linkType: hard
+"which-builtin-type@npm:^1.1.3":
+ version: 1.1.3
+ resolution: "which-builtin-type@npm:1.1.3"
+ dependencies:
+ function.prototype.name: "npm:^1.1.5"
+ has-tostringtag: "npm:^1.0.0"
+ is-async-function: "npm:^2.0.0"
+ is-date-object: "npm:^1.0.5"
+ is-finalizationregistry: "npm:^1.0.2"
+ is-generator-function: "npm:^1.0.10"
+ is-regex: "npm:^1.1.4"
+ is-weakref: "npm:^1.0.2"
+ isarray: "npm:^2.0.5"
+ which-boxed-primitive: "npm:^1.0.2"
+ which-collection: "npm:^1.0.1"
+ which-typed-array: "npm:^1.1.9"
+ checksum: 10/d7823c4a6aa4fc8183eb572edd9f9ee2751e5f3ba2ccd5b298cc163f720df0f02ee1a5291d18ca8a41d48144ef40007ff6a64e6f5e7c506527086c7513a5f673
+ languageName: node
+ linkType: hard
+
"which-collection@npm:^1.0.1":
version: 1.0.1
resolution: "which-collection@npm:1.0.1"
@@ -35448,7 +37079,7 @@ __metadata:
languageName: node
linkType: hard
-"which-typed-array@npm:^1.1.13":
+"which-typed-array@npm:^1.1.13, which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15":
version: 1.1.15
resolution: "which-typed-array@npm:1.1.15"
dependencies:
@@ -35543,7 +37174,7 @@ __metadata:
languageName: node
linkType: hard
-"word-wrap@npm:~1.2.3":
+"word-wrap@npm:^1.2.5, word-wrap@npm:~1.2.3":
version: 1.2.5
resolution: "word-wrap@npm:1.2.5"
checksum: 10/1ec6f6089f205f83037be10d0c4b34c9183b0b63fca0834a5b3cee55dd321429d73d40bb44c8fc8471b5203d6e8f8275717f49a8ff4b2b0ab41d7e1b563e0854
@@ -35915,6 +37546,13 @@ __metadata:
languageName: node
linkType: hard
+"yocto-queue@npm:^0.1.0":
+ version: 0.1.0
+ resolution: "yocto-queue@npm:0.1.0"
+ checksum: 10/f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700
+ languageName: node
+ linkType: hard
+
"yocto-queue@npm:^1.0.0":
version: 1.0.0
resolution: "yocto-queue@npm:1.0.0"
@@ -35930,10 +37568,10 @@ __metadata:
linkType: hard
"zustand@npm:^4.5.1":
- version: 4.5.5
- resolution: "zustand@npm:4.5.5"
+ version: 4.5.1
+ resolution: "zustand@npm:4.5.1"
dependencies:
- use-sync-external-store: "npm:1.2.2"
+ use-sync-external-store: "npm:1.2.0"
peerDependencies:
"@types/react": ">=16.8"
immer: ">=9.0.6"
@@ -35945,7 +37583,28 @@ __metadata:
optional: true
react:
optional: true
- checksum: 10/481b8210187b69678074a1ca51107654c2379688e90407bfcb7961e0803a259742bfd0d77171c3f07e290896ad55fe9659b3863f30d34cb2572650ead1249f25
+ checksum: 10/c5dcd734ddcc393bc1febcf1811d606222c6d40cb4cf0e4d605be6cfa1855c8b09b6725ab6b73a395f1e020f8f617b605c800c1f19301b240c45d5042e1b2a10
+ languageName: node
+ linkType: hard
+
+"zustand@npm:^5.0.1":
+ version: 5.0.1
+ resolution: "zustand@npm:5.0.1"
+ peerDependencies:
+ "@types/react": ">=18.0.0"
+ immer: ">=9.0.6"
+ react: ">=18.0.0"
+ use-sync-external-store: ">=1.2.0"
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ immer:
+ optional: true
+ react:
+ optional: true
+ use-sync-external-store:
+ optional: true
+ checksum: 10/9ee5b2483213157c519be2647e873fb21962b4e6e521031916e8969552379dd03348057c9dfd030eb1e7ef98a945a1f99f9aa9badda5d9673eb4004e354dc2dc
languageName: node
linkType: hard