diff --git a/packages/column-builder/package.json b/packages/column-builder/package.json index 19e982e17..bb7957d84 100644 --- a/packages/column-builder/package.json +++ b/packages/column-builder/package.json @@ -18,12 +18,12 @@ "@macrostrat/form-components": "^0.2.2", "@macrostrat/hyper": "^3.0.6", "@macrostrat/ui-components": "^4.1.2", - "@mapbox/mapbox-gl-draw": "^1.3.0", + "@mapbox/mapbox-gl-draw": "^1.5.0", "@supabase/postgrest-js": "^1.18.1", "@types/mapbox__mapbox-gl-draw": "^1.2.3", "axios": "^1.7.9", "cross-fetch": "^3.1.5", - "mapbox-gl": "^3.0.0", + "mapbox-gl": "^3.13.0", "react": "^18", "react-beautiful-dnd": "^13.1.0", "react-color": "^2.19.3" diff --git a/packages/column-footprint-editor/.dockerignore b/packages/column-footprint-editor/.dockerignore new file mode 100644 index 000000000..91b9c5556 --- /dev/null +++ b/packages/column-footprint-editor/.dockerignore @@ -0,0 +1,6 @@ +.git +Dockerfile +package-lock.json +/node_modules/* +/dist/* +/.parcel-cache/* \ No newline at end of file diff --git a/packages/column-footprint-editor/.env.example b/packages/column-footprint-editor/.env.example new file mode 100644 index 000000000..4da50be1a --- /dev/null +++ b/packages/column-footprint-editor/.env.example @@ -0,0 +1,5 @@ +## .env file must go in the frontend directory + +API_BASE=http://geologic_map_api/ +MAPBOX_TOKEN=mapbox_access_token +## https://docs.mapbox.com/help/getting-started/access-tokens/ diff --git a/packages/column-footprint-editor/.gitignore b/packages/column-footprint-editor/.gitignore new file mode 100644 index 000000000..28277d9da --- /dev/null +++ b/packages/column-footprint-editor/.gitignore @@ -0,0 +1,6 @@ +node_modules +package-lock.json +.parcel-cache +Dockerfile.dev +dist +__pychache__ \ No newline at end of file diff --git a/packages/column-footprint-editor/.parcelrc b/packages/column-footprint-editor/.parcelrc new file mode 100644 index 000000000..bf814fdf8 --- /dev/null +++ b/packages/column-footprint-editor/.parcelrc @@ -0,0 +1,8 @@ +{ + "extends": "@parcel/config-default", + "transformers": { + "jsx:*.svg": [ + "@parcel/transformer-svg-react" + ] + } +} diff --git a/packages/column-footprint-editor/Dockerfile b/packages/column-footprint-editor/Dockerfile new file mode 100644 index 000000000..2fabe3a91 --- /dev/null +++ b/packages/column-footprint-editor/Dockerfile @@ -0,0 +1,16 @@ +FROM node:14 + +WORKDIR /app +ENV PATH /app/node_modules/.bin:$PATH + + +COPY package*.json ./ + +RUN npm install + +COPY . . + +RUN npm run build +WORKDIR /app/dist + +ENTRYPOINT ["npx", "serve", "-p", "1235"] \ No newline at end of file diff --git a/packages/column-footprint-editor/package.json b/packages/column-footprint-editor/package.json new file mode 100644 index 000000000..08cf747f3 --- /dev/null +++ b/packages/column-footprint-editor/package.json @@ -0,0 +1,27 @@ +{ + "name": "@macrostrat/column-footprint-editor", + "private": true, + "main": "src/index.tsx", + "scripts": { + "start": "ENV=development parcel serve -p 1235 ./src/index.html", + "build": "ENV=production parcel build --public-url /column-topology/ ./src/index.html" + }, + "dependencies": { + "@blueprintjs/core": "^5.10.2", + "@blueprintjs/popover2": "^1.4.1", + "@blueprintjs/select": "^5.1.4", + "@macrostrat/ui-components": "^4.4.4", + "@mapbox/mapbox-gl-draw": "^1.5.0", + "@turf/nearest-point-on-line": "^5.1.5", + "@types/mapbox__mapbox-gl-draw": "^1.2.4", + "axios": "^1.11.0", + "mapbox-gl": "^3.13.0", + "mapbox-gl-draw-snap-mode": "^0.4.0", + "react": "^18.3.0", + "react-color": "^2.19.3", + "react-dom": "^18.3.0", + "react-loading-overlay": "^1.0.1", + "react-router-dom": "^5.3.0", + "topojson-client": "^3.1.0" + } +} diff --git a/packages/column-footprint-editor/src/assets/12-side.svg b/packages/column-footprint-editor/src/assets/12-side.svg new file mode 100644 index 000000000..f0227a61c --- /dev/null +++ b/packages/column-footprint-editor/src/assets/12-side.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/packages/column-footprint-editor/src/assets/16-side.svg b/packages/column-footprint-editor/src/assets/16-side.svg new file mode 100644 index 000000000..93c7248b2 --- /dev/null +++ b/packages/column-footprint-editor/src/assets/16-side.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/packages/column-footprint-editor/src/assets/20-side.svg b/packages/column-footprint-editor/src/assets/20-side.svg new file mode 100644 index 000000000..9e878ed74 --- /dev/null +++ b/packages/column-footprint-editor/src/assets/20-side.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/packages/column-footprint-editor/src/assets/24-side.svg b/packages/column-footprint-editor/src/assets/24-side.svg new file mode 100644 index 000000000..3066d844b --- /dev/null +++ b/packages/column-footprint-editor/src/assets/24-side.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/packages/column-footprint-editor/src/assets/4-side.svg b/packages/column-footprint-editor/src/assets/4-side.svg new file mode 100644 index 000000000..a21bf90d2 --- /dev/null +++ b/packages/column-footprint-editor/src/assets/4-side.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/packages/column-footprint-editor/src/assets/8-side.svg b/packages/column-footprint-editor/src/assets/8-side.svg new file mode 100644 index 000000000..e878863a4 --- /dev/null +++ b/packages/column-footprint-editor/src/assets/8-side.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/packages/column-footprint-editor/src/components/blueprint/buttons.tsx b/packages/column-footprint-editor/src/components/blueprint/buttons.tsx new file mode 100644 index 000000000..d5c9cfb06 --- /dev/null +++ b/packages/column-footprint-editor/src/components/blueprint/buttons.tsx @@ -0,0 +1,54 @@ +import React from "react"; +import { Button } from "@blueprintjs/core"; +import { useAPIResult } from "@macrostrat/ui-components"; +import { base } from "../../context/env"; + +function SaveButton(props) { + const { onClick, minimal, disabled } = props; + + return ( + + ); +} + +function downloadObjectAsJson(exportObj, exportName) { + var dataStr = "data:text/csv;charset=utf-8," + encodeURIComponent(exportObj); + var downloadAnchorNode = document.createElement("a"); + downloadAnchorNode.setAttribute("href", dataStr); + downloadAnchorNode.setAttribute("download", exportName + ".csv"); + document.body.appendChild(downloadAnchorNode); // required for firefox + downloadAnchorNode.click(); + downloadAnchorNode.remove(); +} + +function DownloadButton(props) { + const { project_id } = props; + let data = []; + if (project_id) { + data = useAPIResult(base + `${project_id}/csv`); + } + + const onClick = () => { + downloadObjectAsJson(data, "columns"); + }; + return ( + + ); +} + +export { SaveButton, DownloadButton }; diff --git a/packages/column-footprint-editor/src/components/blueprint/dialog.tsx b/packages/column-footprint-editor/src/components/blueprint/dialog.tsx new file mode 100644 index 000000000..1fb327f07 --- /dev/null +++ b/packages/column-footprint-editor/src/components/blueprint/dialog.tsx @@ -0,0 +1,89 @@ +import React, { useState, useEffect } from "react"; +import { Overlay, Button, Card } from "@blueprintjs/core"; +import "./main.css"; + +function OverlayBox(props) { + const { + open, + children, + closeOpen, + HeaderComponent, + className = "overlay", + closeButton = true, + cardStyles = {}, + } = props; + + const [state, setState] = useState({ top: 100, left: 20 }); + 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); + document.addEventListener("mouseup", onMouseUp); + return () => { + document.removeEventListener("mouseup", onMouseUp); + document.removeEventListener("mousemove", onMouseMove); + }; + }, [dragging]); + + const onMouseDown = (e) => { + if (e.button !== 0) return; + setDragging(true); + setOffset(getOffest(e)); + }; + + const onMouseUp = (e) => { + setDragging(false); + e.stopPropagation(); + e.preventDefault(); + }; + + const getOffest = (e) => { + const rel_x = e.pageX - state.left; + const rel_y = e.pageY - state.top; + return { rel_x, rel_y }; + }; + + const onMouseMove = (e) => { + 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_ }); + } + e.stopPropagation(); + e.preventDefault(); + }; + + const overlayProperties = { + autoFocus: true, + canEscapeKeyClose: true, + canOutsideClickClose: true, + enforceFocus: false, + hasBackdrop: false, + usePortal: true, + useTallContent: false, + }; + + const style = { top: `${state.top}px`, left: `${state.left}px` }; + + return ( + +
+ + + {children} + {closeButton ? ( + + ) : null} + +
+
+ ); +} + +export { OverlayBox }; diff --git a/packages/column-footprint-editor/src/components/blueprint/index.ts b/packages/column-footprint-editor/src/components/blueprint/index.ts new file mode 100644 index 000000000..a366ad0c9 --- /dev/null +++ b/packages/column-footprint-editor/src/components/blueprint/index.ts @@ -0,0 +1,5 @@ +export * from "./dialog"; +export * from "./navbar"; +export * from "./buttons"; +export * from "./toaster"; +export * from "./select"; diff --git a/packages/column-footprint-editor/src/components/blueprint/main.css b/packages/column-footprint-editor/src/components/blueprint/main.css new file mode 100644 index 000000000..66d350289 --- /dev/null +++ b/packages/column-footprint-editor/src/components/blueprint/main.css @@ -0,0 +1,62 @@ + +.overlay { + max-width: 500px; +} + +.drag-bar-top { + height: 50px; + width: 100%; + z-index: 22; +} + +.projects-drop-down { + display: flex; + align-items: flex-start; + flex-direction: column; + padding: 5px; + justify-content: flex-end; +} + +.projects-drop-more { + display: flex; + flex-direction: column; + padding: 5px; + justify-content: flex-end; +} + +.nav-contents { + display: flex; + align-items: center; + justify-content: space-between; + padding-top: 10px; +} + +.toolbar { + max-width: 300px; + margin-top: 5px; +} + +.nav-right, +.nav-left { + display: flex; + align-items: center; +} + +.panel-stack { + min-height: 500px; +} + +.main-dialog-header { + margin-top: 5px; + margin-left: 5px; +} + +.btn-holder { + float: right; + margin-top: -23px; + margin-right: -20px; +} + +.project-btns { + margin: 0px 5px 10px 0px; +} diff --git a/packages/column-footprint-editor/src/components/blueprint/navbar.tsx b/packages/column-footprint-editor/src/components/blueprint/navbar.tsx new file mode 100644 index 000000000..dbc5f1f64 --- /dev/null +++ b/packages/column-footprint-editor/src/components/blueprint/navbar.tsx @@ -0,0 +1,207 @@ +import React, { useContext } from "react"; +import { DownloadButton } from "."; +import { + Button, + Navbar, + Popover, + MenuItem, + Menu, + MenuDivider, + Icon, + IconName, +} from "@blueprintjs/core"; +import { AppContext } from "../../context"; +import { useAPIResult } from "@macrostrat/ui-components"; +import { base, MAP_MODES } from "../../context"; + +const projects_url = process.env.API_BASE + "projects"; + +function unwrapProjects(res) { + if (res.data) { + const { data } = res; + let projects = data.map((project) => { + return { + project_id: project.project_id, + name: project.name, + description: project.description, + }; + }); + return projects; + } else { + return []; + } +} + +function ProjectDropDown(props) { + const { projects } = props; + const { state, runAction } = useContext(AppContext); + const changeProjectId = (project) => { + runAction({ type: "change-project", payload: project }); + }; + + const openImportOverlay = () => { + runAction({ type: "import-overlay", payload: { open: true } }); + }; + + return ( + + {projects.map((project) => { + const { project_id: id, name } = project; + let iconName: IconName | undefined = + id == state.project.project_id ? "tick" : undefined; + return ( + changeProjectId(project)} + intent="primary" + labelElement={} + > + ); + })} + + + + + ); +} + +function NavBarModeBtns(props: { + changeMode: (mode: MAP_MODES) => void; + mode: MAP_MODES; +}) { + const { changeMode, mode } = props; + + return ( + + + + + + ); +} + +interface NavBarSaveBtnsProps { + onSave: () => void; + onCancel: () => void; + mode: MAP_MODES; + project_id: number | null; + polygons?: object[]; + changeSet?: object[]; +} + +function NavBarSaveBtns(props: NavBarSaveBtnsProps) { + const { + onSave, + onCancel, + project_id, + mode, + polygons = [], + changeSet = [], + } = props; + + const disabled = + (mode == MAP_MODES.voronoi && !polygons.length) || + (mode == MAP_MODES.topology && !changeSet.length); + return ( +
+ + + +
+ ); +} + +interface MapNavBarProps { + onSave: () => void; + onCancel: () => void; + changeMode: (mode: MAP_MODES) => void; + mode: MAP_MODES; + project_id: number | null; + polygons: object[]; + changeSet: object[]; +} + +function MapNavBar(props: MapNavBarProps) { + const { onSave, onCancel, mode, changeMode, project_id, ...rest } = props; + const { state, runAction } = useContext(AppContext); + + const openImportOverlay = () => { + runAction({ type: "import-overlay", payload: { open: true } }); + }; + + const projects = useAPIResult( + projects_url, + {}, + { unwrapResponse: unwrapProjects } + ); + if (!projects) return
; + + return ( +
+ +
+
+ + + + + + } + position="bottom" + minimal={true} + > + + + +
+
+ + + +
+
+
+
+ ); +} + +export { MapNavBar }; diff --git a/packages/column-footprint-editor/src/components/blueprint/select.tsx b/packages/column-footprint-editor/src/components/blueprint/select.tsx new file mode 100644 index 000000000..d81eeb81c --- /dev/null +++ b/packages/column-footprint-editor/src/components/blueprint/select.tsx @@ -0,0 +1,92 @@ +import { Suggest } from "@blueprintjs/select"; +import { Icon, MenuItem } from "@blueprintjs/core"; +import React, { useState, useEffect } from "react"; + +export function MySuggest(props) { + const { + items, + onChange, + onFilter = () => {}, + initialQuery, + createNew = true, + ...rest + } = props; + const [selectedItem, setSelectedItem] = useState({}); + const [query, setQuery] = useState(""); + + let itemz = [...items]; + + useEffect(() => { + if (initialQuery && initialQuery != "") { + setQuery(initialQuery); + itemz = [...itemz, { text: initialQuery }]; + setSelectedItem(initialQuery); + } + }, [initialQuery]); + + const itemRenderer = (item, itemProps) => { + const isSelected = item == selectedItem; + const { id, text } = item; + return ( + : null} + intent={isSelected ? "primary" : null} + text={text} + onClick={itemProps.handleClick} + active={isSelected ? "active" : itemProps.modifiers.active} + /> + ); + }; + + const onQueryChange = (query) => { + onFilter(query); + }; + + const itemPredicate = (query, item) => { + const { id, text } = item; + + return text.toLowerCase().indexOf(query.toLowerCase()) >= 0; + }; + + const onItemSelect = (item) => { + onChange(item); + setSelectedItem(item.text); + }; + + const createNewItemRenderer = (query, itemProps) => { + return ( + onChange(query)} + intent="success" + /> + ); + }; + + const createNewItemFromQuery = (query) => { + return query; + }; + + return ( +
+ item.text} + items={itemz} + popoverProps={{ + minimal: true, + popoverClassName: "my-suggest", + }} + query={query} + onItemSelect={onItemSelect} + onQueryChange={onQueryChange} + itemRenderer={itemRenderer} + itemPredicate={itemPredicate} + selectedItem + createNewItemRenderer={createNew ? createNewItemRenderer : null} + createNewItemFromQuery={createNew ? createNewItemFromQuery : null} + /> +
+ ); +} diff --git a/packages/column-footprint-editor/src/components/blueprint/toaster.tsx b/packages/column-footprint-editor/src/components/blueprint/toaster.tsx new file mode 100644 index 000000000..beb68ab95 --- /dev/null +++ b/packages/column-footprint-editor/src/components/blueprint/toaster.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import { Toaster, Icon, ProgressBar } from "@blueprintjs/core"; + +const AppToaster = Toaster.create({ + position: "top", + maxToasts: 1, +}); + +const SavingToast = ({ message = "Saving..." }) => { + return ( +
+

{message}

+ +
+ ); +}; + +const SuccessfullySaved = () => { + return ( +
+ +

Saved Successfully!

+
+ ); +}; + +const BadSaving = () => { + return ( +
+ + Error While Saving +
+ ); +}; + +export { AppToaster, SavingToast, SuccessfullySaved, BadSaving }; diff --git a/packages/column-footprint-editor/src/components/editor/column-groups/column-suggest.tsx b/packages/column-footprint-editor/src/components/editor/column-groups/column-suggest.tsx new file mode 100644 index 000000000..8df344ec6 --- /dev/null +++ b/packages/column-footprint-editor/src/components/editor/column-groups/column-suggest.tsx @@ -0,0 +1,93 @@ +import { Suggest } from "@blueprintjs/select"; +import { Icon, MenuItem } from "@blueprintjs/core"; +import React, { useState, useEffect } from "react"; + +export function ColumnSuggest(props) { + const { + items, + onChange, + onFilter = () => {}, + initialItem, + createNew = false, + ...rest + } = props; + const [selectedItem, setSelectedItem] = useState({}); + const [query, setQuery] = useState(""); + + let itemz = [...items]; + + let initialQuery = initialItem.col_group_name; + useEffect(() => { + if (initialQuery && initialQuery != "") { + setQuery(initialQuery); + itemz = [...itemz]; + setSelectedItem(initialQuery); + } + }, [initialQuery]); + + const itemRenderer = (item, itemProps) => { + const isSelected = item == selectedItem; + const { id, col_group, col_group_name } = item; + return ( + + ); + }; + + const onQueryChange = (query) => { + onFilter(query); + }; + + const itemPredicate = (query, item) => { + const { id, col_group_name } = item; + + return col_group_name.toLowerCase().indexOf(query.toLowerCase()) >= 0; + }; + + const onItemSelect = (item) => { + onChange(item); + setSelectedItem(item.col_group_name); + }; + + const createNewItemRenderer = (query, itemProps) => { + return ( + onChange(query)} + intent="success" + /> + ); + }; + + const createNewItemFromQuery = (query) => { + return query; + }; + + return ( +
+ item.col_group_name} + items={itemz} + popoverProps={{ + minimal: true, + }} + inputProps={{ fill: true, style: { minWidth: "350px" } }} + query={query} + onItemSelect={onItemSelect} + onQueryChange={onQueryChange} + itemRenderer={itemRenderer} + itemPredicate={itemPredicate} + selectedItem + createNewItemRenderer={createNew ? createNewItemRenderer : null} + createNewItemFromQuery={createNew ? createNewItemFromQuery : null} + /> +
+ ); +} diff --git a/packages/column-footprint-editor/src/components/editor/column-groups/editor.tsx b/packages/column-footprint-editor/src/components/editor/column-groups/editor.tsx new file mode 100644 index 000000000..630711676 --- /dev/null +++ b/packages/column-footprint-editor/src/components/editor/column-groups/editor.tsx @@ -0,0 +1,113 @@ +import React, { createContext, useContext, useState, useEffect } from "react"; +import { + Overlay, + Button, + Card, + Navbar, + FormGroup, + Collapse, +} from "@blueprintjs/core"; +import { useAPIResult, useModelEditor } from "@macrostrat/ui-components"; +import { ColumnSuggest } from "./column-suggest"; +import { NewColGroups } from "./new-column"; +import { AppContext } from "../../../context"; +import { base } from "../../../context/env"; +import { EditColGroup } from "."; + +function unwrapColumnGroups(res) { + const { data } = res; + return data; +} + +function ColumnGroup() { + const { model, isEditing, actions } = useModelEditor(); + const { state } = useContext(AppContext); + const [open, setOpen] = useState(false); + const [openEdit, setOpenEdit] = useState(false); + + const { project } = state; + const { project_id } = project; + + const data = useAPIResult( + base + `${project_id}/col-groups`, + {}, + { unwrapResponse: unwrapColumnGroups } + ); + + if (!data) return
; + + const { col_group, col_group_name, col_group_id } = model; + + const onChangeGroup = (e) => { + actions.updateState({ + model: { + col_group: { $set: e.col_group }, + col_group_id: { $set: e.id }, + col_group_name: { $set: e.col_group_name }, + }, + }); + }; + + const onCreateColGroup = (col_group_id, col_group, col_group_name) => { + setOpen(false); + actions.updateState({ + model: { + col_group: { $set: col_group }, + col_group_id: { $set: col_group_id }, + col_group_name: { $set: col_group_name }, + }, + }); + }; + + if (isEditing) { + return ( +
+ + + +
+
+ + +
+
+ +
+ +
+
+ +
+ +
+
+
+ ); + } + return ( +
+ {col_group_name} ({col_group}) +
+ ); +} + +export { ColumnGroup }; diff --git a/packages/column-footprint-editor/src/components/editor/column-groups/index.ts b/packages/column-footprint-editor/src/components/editor/column-groups/index.ts new file mode 100644 index 000000000..04019228c --- /dev/null +++ b/packages/column-footprint-editor/src/components/editor/column-groups/index.ts @@ -0,0 +1,3 @@ +export * from "./editor"; +export * from "./column-suggest"; +export * from "./new-column"; diff --git a/packages/column-footprint-editor/src/components/editor/column-groups/new-column.tsx b/packages/column-footprint-editor/src/components/editor/column-groups/new-column.tsx new file mode 100644 index 000000000..490e83209 --- /dev/null +++ b/packages/column-footprint-editor/src/components/editor/column-groups/new-column.tsx @@ -0,0 +1,127 @@ +import React, { useContext, useEffect, useState } from "react"; +import { + ModelEditor, + useModelEditor, + ModelEditButton, + EditableMultilineText, +} from "@macrostrat/ui-components"; +import { Popover2 } from "@blueprintjs/popover2"; +import { SaveButton } from "../../blueprint"; +import axios from "axios"; +import { ChromePicker } from "react-color"; + +import { AppContext } from "../../../context"; +import { base } from "../../../context/env"; +import { FormGroup, InputGroup } from "@blueprintjs/core"; + +function ColorPicker() { + const { model, isEditing, actions } = useModelEditor(); + const { color } = model; + + const onChangeColor = (color) => { + const { hex } = color; + actions.updateState({ model: { color: { $set: hex } } }); + }; + + if (!isEditing) return
; + return ( +
+ + } + > +
+
+
+ ); +} + +function EditComponents() { + const { actions, model } = useModelEditor(); + + const update = (field, value) => { + actions.updateState({ + model: { [field]: { $set: value } }, + }); + }; + return ( +
+ + update("col_group", e.target.value)} + value={model["col_group"]} + /> + + + update("col_group_name", e.target.value)} + value={model["col_group_name"]} + /> + + + + actions.persistChanges()} /> +
+ ); +} + +function NewColGroups(props) { + const { onCreate } = props; + let state = { + col_group: "", + col_group_name: "", + color: "", + }; + + const { state: appState } = useContext(AppContext); + const project_id = appState.project.project_id; + const persistChanges = async (updatedModel, changeset) => { + let route = base + `${project_id}/col-groups`; + let res = await axios.post(route, { updatedModel }); + const { + data: { col_group_id }, + } = res; + const { col_group, col_group_name } = updatedModel; + onCreate(col_group_id, col_group, col_group_name); + }; + + return ; +} + +function EditColGroup(props) { + const { onCreate, state } = props; + + const { state: appState } = useContext(AppContext); + const project_id = appState.project.project_id; + + const persistChanges = async (updatedModel, changeset) => { + console.log(updatedModel); + let route = base + `${project_id}/col-groups`; + let res = await axios.put(route, { updatedModel }); + const { + data: { id }, + } = res; + const { col_group, col_group_name } = updatedModel; + onCreate(id, col_group, col_group_name); + }; + + return ; +} + +function BaseColGroupEditor(props) { + const { state, persistChanges } = props; + + return ( + + + + ); +} + +export { NewColGroups, EditColGroup }; diff --git a/packages/column-footprint-editor/src/components/editor/editor.tsx b/packages/column-footprint-editor/src/components/editor/editor.tsx new file mode 100644 index 000000000..9674b55ca --- /dev/null +++ b/packages/column-footprint-editor/src/components/editor/editor.tsx @@ -0,0 +1,204 @@ +import React, { useContext } from "react"; +import { Navbar, InputGroup, FormGroup, TextArea } from "@blueprintjs/core"; +import { OverlayBox, SaveButton } from "../blueprint"; +import { + ModelEditor, + useModelEditor, + ModelEditButton, + EditableMultilineText, +} from "@macrostrat/ui-components"; +import axios from "axios"; +import { AppContext } from "../../context"; + +import { + AppToaster, + SavingToast, + SuccessfullySaved, + BadSaving, +} from "../blueprint"; + +import "./main.css"; + +import { ColumnGroup } from "./column-groups"; +import { base } from "../../context/env"; + +const canSave = (model): boolean => { + const { col_name = null, description = null, col_group_name = null } = model; + if (col_name && description && col_group_name) return true; + return false; +}; + +function ColumnNavBar({ onMouseDown }) { + const { model, isEditing, hasChanges, actions, ...rest } = useModelEditor(); + + const buttonText = isEditing ? "Cancel" : "Edit"; + const buttonIntent = isEditing ? "danger" : "success"; + + return ( +
+ +
+
+ Column ID: {model.col_id} + + Project ID: {model.project_id} +
+
+ { + actions.persistChanges(); + actions.toggleEditing(); + }} + > + + {buttonText} + +
+
+
+
+ ); +} + +function ColumnName() { + const { model, isEditing, actions } = useModelEditor(); + const { col_name } = model; + + const updateName = (name) => { + actions.updateState({ + model: { col_name: { $set: name.target.value } }, + }); + }; + + if (isEditing) { + return ( + + + + ); + } + return
{col_name}
; +} + +function ColumnDescription() { + const { model, isEditing, actions } = useModelEditor(); + let { description = "No description" } = model; + + const updateDescription = (e) => { + actions.updateState({ + model: { description: { $set: e.target.value } }, + }); + }; + + if (isEditing) { + return ( + +