From 28d4e9bbe7c6fd5375927d81bc9c888c2031083c Mon Sep 17 00:00:00 2001 From: Spencer Rose Date: Sat, 9 Mar 2024 12:46:17 -0800 Subject: [PATCH 1/8] Map feature module for v2.1 --- _init/files.init.sql | 3 +- _init/global.init.sql | 1 + _init/update.30112023.sql | 112 ++++++ _init/users.init.sql | 6 + .../toolkit.js => alignment/alignment.js} | 22 +- .../canvas/default.canvas.alignment.js} | 4 +- .../canvas/grid.canvas.alignment.js} | 2 +- .../canvas/magnifier.canvas.alignment.js} | 6 +- .../canvas/overlay.canvas.alignment.js} | 2 +- .../dialog.alignment.js} | 18 +- .../menu.alignment.js} | 8 +- .../panel/controller.panel.alignment.js} | 4 +- .../panel/info.panel.alignment.js} | 6 +- .../panel/init.panel.alignment.js} | 3 +- .../panel/menu.panel.alignment.js} | 6 +- .../panel/panel.alignment.js} | 38 +- .../panel/placeholder.panel.alignment.js} | 4 +- .../tools/comparator.alignment.js} | 16 +- .../tools/cropper.alignment.js} | 6 +- .../tools/downloader.alignment.js} | 4 +- .../tools/importer.alignment.js} | 13 +- .../tools/loader.alignment.js} | 14 +- .../tools/opener.alignment.js} | 8 +- .../tools/pointer.alignment.js} | 4 +- .../tools/register.alignment.js} | 10 +- .../tools/resizer.alignment.js} | 4 +- .../tools/scaler.alignment.js} | 2 +- .../tools/uploader.alignment.js} | 8 +- .../utils/align.utils.alignment.js} | 2 +- .../utils/loader.utils.alignment.js} | 14 +- .../utils/tiff.utils.alignment.js} | 2 +- client/src/_components/common/form.js | 87 ++-- client/src/_components/common/icon.js | 17 +- client/src/_components/common/message.js | 2 +- client/src/_components/common/singleselect.js | 62 +++ client/src/_components/common/slider.js | 4 +- client/src/_components/common/table.js | 117 +++--- client/src/_components/common/tree.js | 316 +++++++++++++++ .../{toolkit.help.js => alignment.help.js} | 50 +-- client/src/_components/content/editor.help.js | 25 +- .../src/_components/content/explorer.help.js | 16 +- client/src/_components/content/map.help.js | 299 ++++++++++++++ .../_components/editors/attached.editor.js | 3 +- .../src/_components/editors/default.editor.js | 18 +- .../_components/editors/dependents.editor.js | 10 +- client/src/_components/editors/map.editor.js | 315 +++++++++++++++ .../src/_components/editors/options.editor.js | 2 +- .../kml/Stn_1_Sanseverino_2016.kmz | Bin 730 -> 0 bytes client/src/_components/kml/example-2.kml | 85 ---- client/src/_components/menus/editor.menu.js | 47 ++- client/src/_components/menus/header.menu.js | 1 + client/src/_components/menus/viewer.menu.js | 9 +- .../_components/navigator/filter.navigator.js | 13 +- .../_components/navigator/map.navigator.js | 166 ++++++-- .../src/_components/navigator/map/base.map.js | 161 ++++++++ .../_components/navigator/tree.navigator.js | 10 +- .../_components/selectors/dialog.selector.js | 52 ++- .../_components/selectors/file.selector.js | 3 +- .../_components/selectors/input.selector.js | 76 ++-- .../src/_components/selectors/map.selector.js | 374 ++++++++++++++++++ .../_components/selectors/static.selector.js | 2 +- .../_components/styles/mapfeatures.module.css | 14 + client/src/_components/styles/tree.module.css | 18 + .../src/_components/tools/download.tools.js | 3 +- client/src/_components/tools/map.tools.js | 255 +++++++++--- client/src/_components/views/attached.view.js | 76 ++-- client/src/_components/views/capture.view.js | 22 +- client/src/_components/views/editor.view.js | 1 - client/src/_components/views/files.view.js | 5 +- client/src/_components/views/help.view.js | 35 +- client/src/_components/views/metadata.view.js | 25 +- ...client.js => alignment.provider.client.js} | 20 +- client/src/_providers/app.provider.client.js | 2 +- client/src/_providers/auth.provider.client.js | 27 +- client/src/_providers/data.provider.client.js | 5 +- client/src/_providers/nav.provider.client.js | 108 +++-- .../src/_providers/router.provider.client.js | 26 +- client/src/_services/api.services.client.js | 26 +- client/src/_utils/data.utils.client.js | 28 +- client/src/_utils/validator.utils.client.js | 23 ++ client/src/schema.js | 227 ++++++++++- package.json | 9 +- src/controllers/files.controller.js | 62 ++- src/controllers/maps.controller.js | 194 +++++++++ src/controllers/metadata.controller.js | 3 + src/controllers/model.controller.js | 6 +- src/controllers/nodes.controller.js | 18 +- src/lib/data.utils.js | 3 + src/lib/{date.js => date.utils.js} | 2 +- src/lib/file.utils.js | 10 + src/queries/comparisons.queries.js | 13 +- src/queries/files.queries.js | 87 +++- src/queries/index.queries.js | 5 +- src/queries/maps.queries.js | 146 +++++++ src/queries/schema.queries.js | 2 +- src/routes/files.routes.js | 19 +- src/routes/index.routes.js | 22 +- src/routes/main.routes.js | 4 +- src/routes/maps.routes.js | 61 +++ src/routes/metadata.routes.js | 12 +- src/routes/model.routes.js | 2 +- src/services/files.services.js | 83 +++- src/services/maps.services.js | 212 ++++++++++ src/services/metadata.services.js | 30 +- src/services/model.services.js | 1 + src/services/nodes.services.js | 3 +- src/services/schema.services.js | 16 +- 107 files changed, 3913 insertions(+), 752 deletions(-) create mode 100644 _init/update.30112023.sql rename client/src/_components/{toolkit/toolkit.js => alignment/alignment.js} (68%) rename client/src/_components/{toolkit/canvas/default.canvas.toolkit.js => alignment/canvas/default.canvas.alignment.js} (98%) rename client/src/_components/{toolkit/canvas/grid.canvas.toolkit.js => alignment/canvas/grid.canvas.alignment.js} (98%) rename client/src/_components/{toolkit/canvas/magnifier.canvas.toolkit.js => alignment/canvas/magnifier.canvas.alignment.js} (98%) rename client/src/_components/{toolkit/canvas/overlay.canvas.toolkit.js => alignment/canvas/overlay.canvas.alignment.js} (98%) rename client/src/_components/{toolkit/dialog.toolkit.js => alignment/dialog.alignment.js} (92%) rename client/src/_components/{toolkit/menu.toolkit.js => alignment/menu.alignment.js} (96%) rename client/src/_components/{toolkit/panel/controller.panel.toolkit.js => alignment/panel/controller.panel.alignment.js} (97%) rename client/src/_components/{toolkit/panel/info.panel.toolkit.js => alignment/panel/info.panel.alignment.js} (97%) rename client/src/_components/{toolkit/panel/init.panel.toolkit.js => alignment/panel/init.panel.alignment.js} (99%) rename client/src/_components/{toolkit/panel/menu.panel.toolkit.js => alignment/panel/menu.panel.alignment.js} (97%) rename client/src/_components/{toolkit/panel/panel.toolkit.js => alignment/panel/panel.alignment.js} (97%) rename client/src/_components/{toolkit/panel/placeholder.panel.toolkit.js => alignment/panel/placeholder.panel.alignment.js} (94%) rename client/src/_components/{toolkit/tools/comparator.toolkit.js => alignment/tools/comparator.alignment.js} (98%) rename client/src/_components/{toolkit/tools/cropper.toolkit.js => alignment/tools/cropper.alignment.js} (98%) rename client/src/_components/{toolkit/tools/downloader.toolkit.js => alignment/tools/downloader.alignment.js} (95%) rename client/src/_components/{toolkit/tools/importer.toolkit.js => alignment/tools/importer.alignment.js} (97%) rename client/src/_components/{toolkit/tools/loader.toolkit.js => alignment/tools/loader.alignment.js} (72%) rename client/src/_components/{toolkit/tools/opener.toolkit.js => alignment/tools/opener.alignment.js} (96%) rename client/src/_components/{toolkit/tools/pointer.toolkit.js => alignment/tools/pointer.alignment.js} (98%) rename client/src/_components/{toolkit/tools/register.toolkit.js => alignment/tools/register.alignment.js} (97%) rename client/src/_components/{toolkit/tools/resizer.toolkit.js => alignment/tools/resizer.alignment.js} (99%) rename client/src/_components/{toolkit/tools/scaler.toolkit.js => alignment/tools/scaler.alignment.js} (98%) rename client/src/_components/{toolkit/tools/uploader.toolkit.js => alignment/tools/uploader.alignment.js} (95%) rename client/src/_components/{toolkit/utils/align.utils.toolkit.js => alignment/utils/align.utils.alignment.js} (99%) rename client/src/_components/{toolkit/utils/loader.utils.toolkit.js => alignment/utils/loader.utils.alignment.js} (95%) rename client/src/_components/{toolkit/utils/tiff.utils.toolkit.js => alignment/utils/tiff.utils.alignment.js} (99%) create mode 100644 client/src/_components/common/singleselect.js create mode 100644 client/src/_components/common/tree.js rename client/src/_components/content/{toolkit.help.js => alignment.help.js} (93%) create mode 100644 client/src/_components/content/map.help.js create mode 100644 client/src/_components/editors/map.editor.js delete mode 100644 client/src/_components/kml/Stn_1_Sanseverino_2016.kmz delete mode 100644 client/src/_components/kml/example-2.kml create mode 100644 client/src/_components/navigator/map/base.map.js create mode 100644 client/src/_components/selectors/map.selector.js create mode 100644 client/src/_components/styles/mapfeatures.module.css create mode 100644 client/src/_components/styles/tree.module.css rename client/src/_providers/{toolkit.provider.client.js => alignment.provider.client.js} (95%) create mode 100644 src/controllers/maps.controller.js rename src/lib/{date.js => date.utils.js} (99%) create mode 100644 src/queries/maps.queries.js create mode 100644 src/routes/maps.routes.js create mode 100644 src/services/maps.services.js diff --git a/_init/files.init.sql b/_init/files.init.sql index 36be795b..3b06233e 100644 --- a/_init/files.init.sql +++ b/_init/files.init.sql @@ -500,7 +500,8 @@ create TABLE "public"."metadata_file_types" insert into "public"."metadata_file_types" (name, label) values ('ancillary', 'Ancillary Metadata'), - ('field_notes', 'Field Notes'); + ('field_notes', 'Field Notes'), + ('geographic_data', 'Geographic Map Data'); -- ------------------------------------------------------------- -- Metadata Files diff --git a/_init/global.init.sql b/_init/global.init.sql index 0d241093..630381ee 100644 --- a/_init/global.init.sql +++ b/_init/global.init.sql @@ -83,6 +83,7 @@ $$ 'search', 'tree', 'map', + 'overlay', 'refresh', 'logout', 'register', diff --git a/_init/update.30112023.sql b/_init/update.30112023.sql new file mode 100644 index 00000000..971be918 --- /dev/null +++ b/_init/update.30112023.sql @@ -0,0 +1,112 @@ + +-- ------------------------------------------------------------- +-- DB update to allow +-- ------------------------------------------------------------- + +-- Create new overlay view for nodes controller + +-- ALTER TYPE views ADD VALUE 'overlay'; +-- +-- -- Update user role permissions for new overlay view +-- +-- INSERT INTO user_permissions (view, role, created_at, updated_at) +-- VALUES ('overlay', 'visitor', now(), now()), +-- ('overlay', 'registered', now(), now()), +-- ('overlay', 'editor', now(), now()), +-- ('overlay', 'administrator', now(), now()), +-- ('overlay', 'super_administrator', now(), now()); + +-- Add new node type and relations for map objects/features data + +insert into "public"."node_types" (name, label) +values ('map_objects', 'Map Objects'), + ('map_features', 'Map Features'); + +insert into "node_relations" (dependent_type, owner_type) +values ('map_objects', null), ('map_features', 'map_objects'); + +-- Add metadata file relations for map node + +insert into "file_relations" (dependent_type, owner_type) +values ('metadata_files', 'map_objects'); + +-- insert into "file_relations" (dependent_type, owner_type) +-- values ('metadata_files', 'surveys'), +-- ('metadata_files', 'survey_seasons'); + +-- Add new metadata file type for KML geographic data + +insert into "public"."metadata_file_types" (name, label) +values ('geographic_data', 'Geographic Map Data'); + +-- Add map object types table + +create TABLE "public"."map_object_types" +( + id serial PRIMARY KEY, + name VARCHAR(40) UNIQUE NOT NULL, + label VARCHAR(40) UNIQUE NOT NULL +); + +insert into "public"."map_object_types" (name, label) +values ('nts', 'NTS Maps'), + ('boundary', 'Boundaries'), + ('other', 'Other Map Objects'); + +-- Add map feature types table + +create TABLE "public"."map_feature_types" +( + id serial PRIMARY KEY, + name VARCHAR(40) UNIQUE NOT NULL, + label VARCHAR(40) UNIQUE NOT NULL +); + +insert into "public"."map_feature_types" (name, label) +values ('mapsheet', 'NTS Mapsheet'), + ('boundary', 'Boundaries'), + ('marker', 'Marker'), + ('other', 'Other Map Feature'); + +-- Add map objects node table for geographic objects + +CREATE TABLE "public"."map_objects" ( + "nodes_id" integer primary key, + "name" character varying(255) NOT NULL, + "type" character varying(255) NOT NULL, + "description" text, + UNIQUE (name), + CONSTRAINT fk_nodes_id FOREIGN KEY (nodes_id) + REFERENCES nodes (id) ON DELETE CASCADE, + CONSTRAINT fk_map_object_types_id FOREIGN KEY (type) + REFERENCES map_object_types (name) ON DELETE SET NULL); + +-- Add map features node table as map object dependents + +CREATE TABLE "public"."map_features" ( + "nodes_id" integer primary key, + "owner_id" integer NOT NULL, + "name" character varying(255) NOT NULL, + "type" character varying(255), + "description" text, + "geometry" json, + UNIQUE (name), + CONSTRAINT fk_nodes_id FOREIGN KEY (nodes_id) + REFERENCES nodes (id) ON DELETE CASCADE, + CONSTRAINT fk_owner_id FOREIGN KEY (owner_id) + REFERENCES nodes (id) ON DELETE CASCADE, + CONSTRAINT fk_map_feature_types_id FOREIGN KEY (type) + REFERENCES map_feature_types (name) ON DELETE SET NULL); + +-- Add map objects type to metadata types + +insert into "public"."metadata_types" (name, label) +values ('map_object_types', 'Map Object Types'); + +-- Add map objects reference to maps table + +ALTER TABLE maps ADD COLUMN IF NOT EXISTS map_features_id integer; + +ALTER TABLE maps + ADD CONSTRAINT fk_map_features_id FOREIGN KEY (map_features_id) + REFERENCES map_features (nodes_id) ON UPDATE CASCADE ON DELETE SET NULL; \ No newline at end of file diff --git a/_init/users.init.sql b/_init/users.init.sql index afe8b0b5..009a9b7d 100644 --- a/_init/users.init.sql +++ b/_init/users.init.sql @@ -110,6 +110,12 @@ VALUES ('show', 'visitor', now(), now()), ('map', 'administrator', now(), now()), ('map', 'super_administrator', now(), now()), + ('overlay', 'visitor', now(), now()), + ('overlay', 'registered', now(), now()), + ('overlay', 'editor', now(), now()), + ('overlay', 'administrator', now(), now()), + ('overlay', 'super_administrator', now(), now()), + ('download', 'visitor', now(), now()), ('download', 'editor', now(), now()), ('download', 'administrator', now(), now()), diff --git a/client/src/_components/toolkit/toolkit.js b/client/src/_components/alignment/alignment.js similarity index 68% rename from client/src/_components/toolkit/toolkit.js rename to client/src/_components/alignment/alignment.js index 3455ccd4..043589d2 100644 --- a/client/src/_components/toolkit/toolkit.js +++ b/client/src/_components/alignment/alignment.js @@ -1,6 +1,6 @@ /*! - * MLE.Client.Toolkit - * File: toolkit.js + * MLE.Client.Alignment + * File: alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -8,7 +8,7 @@ * ---------- * Description * - * Main Alignment Tool component. The toolkit makes extensive use of the Canvas API + * Main Alignment Tool component. The alignment makes extensive use of the Canvas API * for image rendering and markup. Image transformations use the OpenCV.js * JavaScript libraries. * @@ -19,10 +19,10 @@ */ import {memo} from 'react'; -import PanelIat from './panel/panel.toolkit'; -import {MenuToolkit} from './menu.toolkit'; -import {DialogToolkit} from "./dialog.toolkit"; -import {useIat} from "../../_providers/toolkit.provider.client"; +import PanelIat from './panel/panel.alignment'; +import {MenuAlignment} from './menu.alignment'; +import {DialogAlignment} from "./dialog.alignment"; +import {useIat} from "../../_providers/alignment.provider.client"; import {UserMessage} from "../common/message"; import {useNav} from "../../_providers/nav.provider.client"; @@ -33,7 +33,7 @@ import {useNav} from "../../_providers/nav.provider.client"; * @public */ -const Toolkit = () => { +const Alignment = () => { const iat = useIat(); const nav = useNav(); @@ -44,16 +44,16 @@ const Toolkit = () => { } return
- + {iat.setMessage(null)}} />
- +
; }; -export default memo(Toolkit); +export default memo(Alignment); diff --git a/client/src/_components/toolkit/canvas/default.canvas.toolkit.js b/client/src/_components/alignment/canvas/default.canvas.alignment.js similarity index 98% rename from client/src/_components/toolkit/canvas/default.canvas.toolkit.js rename to client/src/_components/alignment/canvas/default.canvas.alignment.js index 16f8fb24..49c5bd34 100644 --- a/client/src/_components/toolkit/canvas/default.canvas.toolkit.js +++ b/client/src/_components/alignment/canvas/default.canvas.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Tools.Toolkit.Canvas - * File: default.canvas.toolkit.js + * File: default.canvas.alignment.js * Copyright(c) 2022 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -17,7 +17,7 @@ */ import React, {forwardRef, useRef, useImperativeHandle, useEffect} from 'react'; -import {CanvasToTIFF} from "../utils/tiff.utils.toolkit"; +import {CanvasToTIFF} from "../utils/tiff.utils.alignment"; /** * Image Analysis Toolkit: Canvas component diff --git a/client/src/_components/toolkit/canvas/grid.canvas.toolkit.js b/client/src/_components/alignment/canvas/grid.canvas.alignment.js similarity index 98% rename from client/src/_components/toolkit/canvas/grid.canvas.toolkit.js rename to client/src/_components/alignment/canvas/grid.canvas.alignment.js index b5dfb06a..b5eac357 100644 --- a/client/src/_components/toolkit/canvas/grid.canvas.toolkit.js +++ b/client/src/_components/alignment/canvas/grid.canvas.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Tools.Toolkit.Grid - * File: grid.canvas.toolkit.js + * File: grid.canvas.alignment.js * Copyright(c) 2022 Runtime Software Development Inc. * Version 2.0 * MIT Licensed diff --git a/client/src/_components/toolkit/canvas/magnifier.canvas.toolkit.js b/client/src/_components/alignment/canvas/magnifier.canvas.alignment.js similarity index 98% rename from client/src/_components/toolkit/canvas/magnifier.canvas.toolkit.js rename to client/src/_components/alignment/canvas/magnifier.canvas.alignment.js index 9f4066a6..8aefee27 100644 --- a/client/src/_components/toolkit/canvas/magnifier.canvas.toolkit.js +++ b/client/src/_components/alignment/canvas/magnifier.canvas.alignment.js @@ -1,14 +1,14 @@ /*! * MLE.Client.Tools.Toolkit.Magnifier - * File: magnifier.canvas.toolkit.js + * File: magnifier.canvas.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed */ import React, {forwardRef, useRef, useImperativeHandle } from 'react'; -import {getScale, inRange, scalePoint} from "../tools/scaler.toolkit"; -import {useIat} from "../../../_providers/toolkit.provider.client"; +import {getScale, inRange, scalePoint} from "../tools/scaler.alignment"; +import {useIat} from "../../../_providers/alignment.provider.client"; /** * Image Analysis Toolkit: Magnifier component diff --git a/client/src/_components/toolkit/canvas/overlay.canvas.toolkit.js b/client/src/_components/alignment/canvas/overlay.canvas.alignment.js similarity index 98% rename from client/src/_components/toolkit/canvas/overlay.canvas.toolkit.js rename to client/src/_components/alignment/canvas/overlay.canvas.alignment.js index eba11658..b0970c4f 100644 --- a/client/src/_components/toolkit/canvas/overlay.canvas.toolkit.js +++ b/client/src/_components/alignment/canvas/overlay.canvas.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Tools.Toolkit.Overlay - * File: overlay.canvas.toolkit.js + * File: overlay.canvas.alignment.js * Copyright(c) 2022 Runtime Software Development Inc. * Version 2.0 * MIT Licensed diff --git a/client/src/_components/toolkit/dialog.toolkit.js b/client/src/_components/alignment/dialog.alignment.js similarity index 92% rename from client/src/_components/toolkit/dialog.toolkit.js rename to client/src/_components/alignment/dialog.alignment.js index 44672be7..6c0caae7 100644 --- a/client/src/_components/toolkit/dialog.toolkit.js +++ b/client/src/_components/alignment/dialog.alignment.js @@ -1,6 +1,6 @@ /*! - * MLE.Client.Components.Toolkit.Dialog - * File: dialog.toolkit.js + * MLE.Client.Components.Lignment.Dialog + * File: dialog.alignment.js * Copyright(c) 2022 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -8,7 +8,7 @@ * ---------- * Description * - * Dialog modal component customized for image toolkit. + * Dialog modal component customized for image alignment. * * ------ * States @@ -20,13 +20,13 @@ import React from 'react'; import Dialog from '../common/dialog'; -import { ImageOpener } from './tools/opener.toolkit'; -import { SaveAs } from './tools/downloader.toolkit'; -import Resizer from './tools/resizer.toolkit'; +import { ImageOpener } from './tools/opener.alignment'; +import { SaveAs } from './tools/downloader.alignment'; +import Resizer from './tools/resizer.alignment'; import MetadataView from '../views/metadata.view'; -import { useIat } from '../../_providers/toolkit.provider.client'; +import { useIat } from '../../_providers/alignment.provider.client'; import {genID} from "../../_utils/data.utils.client"; -import {ComparatorTool} from "./tools/comparator.toolkit"; +import {ComparatorTool} from "./tools/comparator.alignment"; import Button from "../common/button"; /** @@ -43,7 +43,7 @@ const noop = () => { * @return {JSX.Element} */ -export const DialogToolkit = () => { +export const DialogAlignment = () => { // generate unique ID value for canvas inputs const menuID = genID(); diff --git a/client/src/_components/toolkit/menu.toolkit.js b/client/src/_components/alignment/menu.alignment.js similarity index 96% rename from client/src/_components/toolkit/menu.toolkit.js rename to client/src/_components/alignment/menu.alignment.js index 093f1357..4526c1f3 100644 --- a/client/src/_components/toolkit/menu.toolkit.js +++ b/client/src/_components/alignment/menu.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Components.Toolkit.Menu - * File: menu.toolkit.js + * File: menu.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -8,9 +8,9 @@ import React from 'react'; import Button from '../common/button'; -import { useIat } from '../../_providers/toolkit.provider.client'; +import { useIat } from '../../_providers/alignment.provider.client'; import Badge from "../common/badge"; -import {getTooltip} from "../content/toolkit.help"; +import {getTooltip} from "../content/alignment.help"; import {useUser} from "../../_providers/user.provider.client"; import {useNav} from "../../_providers/nav.provider.client"; import {useDialog} from "../../_providers/dialog.provider.client"; @@ -22,7 +22,7 @@ import {useDialog} from "../../_providers/dialog.provider.client"; * @return {JSX.Element} */ -export const MenuToolkit = () => { +export const MenuAlignment = () => { const iat = useIat(); const user = useUser(); diff --git a/client/src/_components/toolkit/panel/controller.panel.toolkit.js b/client/src/_components/alignment/panel/controller.panel.alignment.js similarity index 97% rename from client/src/_components/toolkit/panel/controller.panel.toolkit.js rename to client/src/_components/alignment/panel/controller.panel.alignment.js index 6c173001..2a9a0f4f 100644 --- a/client/src/_components/toolkit/panel/controller.panel.toolkit.js +++ b/client/src/_components/alignment/panel/controller.panel.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Components.Toolkit.Panel.Controller - * File: panel.controller.toolkit.js + * File: panel.controller.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -17,7 +17,7 @@ * - 09-07-2023 Major upgrade to Toolkit incl. UI and workflow improvements and OpenCV integration */ -import {useIat} from "../../../_providers/toolkit.provider.client"; +import {useIat} from "../../../_providers/alignment.provider.client"; /** * Image Analysis Toolkit: Canvas contol event hook diff --git a/client/src/_components/toolkit/panel/info.panel.toolkit.js b/client/src/_components/alignment/panel/info.panel.alignment.js similarity index 97% rename from client/src/_components/toolkit/panel/info.panel.toolkit.js rename to client/src/_components/alignment/panel/info.panel.alignment.js index 05242ca2..0c5b054a 100644 --- a/client/src/_components/toolkit/panel/info.panel.toolkit.js +++ b/client/src/_components/alignment/panel/info.panel.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Components.Toolkit.Panel.Info - * File: panel.info.toolkit.js + * File: panel.info.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -20,9 +20,9 @@ import { getModelLabel } from '../../../_services/schema.services.client'; import Button from '../../common/button'; import { sanitize } from '../../../_utils/data.utils.client'; import {useEffect, useState} from 'react'; -import { getScale, scalePoint } from '../tools/scaler.toolkit'; +import { getScale, scalePoint } from '../tools/scaler.alignment'; import { createNodeRoute } from '../../../_utils/paths.utils.client'; -import {useIat} from "../../../_providers/toolkit.provider.client"; +import {useIat} from "../../../_providers/alignment.provider.client"; import Accordion from "../../common/accordion"; import Icon from "../../common/icon"; diff --git a/client/src/_components/toolkit/panel/init.panel.toolkit.js b/client/src/_components/alignment/panel/init.panel.alignment.js similarity index 99% rename from client/src/_components/toolkit/panel/init.panel.toolkit.js rename to client/src/_components/alignment/panel/init.panel.alignment.js index 5d9db3d5..1c45aeaf 100644 --- a/client/src/_components/toolkit/panel/init.panel.toolkit.js +++ b/client/src/_components/alignment/panel/init.panel.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Toolkit.Initialization - * File: init.toolkit.js + * File: init.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -40,7 +40,6 @@ const openCvPath = `https://docs.opencv.org/${openCvVersion}/opencv.js`; */ export const initPanel = (panelID, panelLabel = '', inputData = null, user=null) => { - // Destructure input data const { file = {}, diff --git a/client/src/_components/toolkit/panel/menu.panel.toolkit.js b/client/src/_components/alignment/panel/menu.panel.alignment.js similarity index 97% rename from client/src/_components/toolkit/panel/menu.panel.toolkit.js rename to client/src/_components/alignment/panel/menu.panel.alignment.js index 43ff699a..d0896eda 100644 --- a/client/src/_components/toolkit/panel/menu.panel.toolkit.js +++ b/client/src/_components/alignment/panel/menu.panel.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Components.Toolkit.Panel.Menu - * File: menu.panel.toolkit.js + * File: menu.panel.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -8,11 +8,11 @@ import React, {memo} from 'react'; import Button from '../../common/button'; -import {useIat} from "../../../_providers/toolkit.provider.client"; +import {useIat} from "../../../_providers/alignment.provider.client"; import {useUser} from "../../../_providers/user.provider.client"; import {useNav} from "../../../_providers/nav.provider.client"; import {useDialog} from "../../../_providers/dialog.provider.client"; -import {getTooltip} from "../../content/toolkit.help"; +import {getTooltip} from "../../content/alignment.help"; /** * Control menu for IAT panel. diff --git a/client/src/_components/toolkit/panel/panel.toolkit.js b/client/src/_components/alignment/panel/panel.alignment.js similarity index 97% rename from client/src/_components/toolkit/panel/panel.toolkit.js rename to client/src/_components/alignment/panel/panel.alignment.js index 256e6bfe..e592547a 100644 --- a/client/src/_components/toolkit/panel/panel.toolkit.js +++ b/client/src/_components/alignment/panel/panel.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Components.Toolkit.Panel - * File: panel.toolkit.js + * File: panel.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -9,7 +9,7 @@ * Description * * Toolkit panel component is the main container for the canvas stack and integrates referenced DOM - * elements with panel state changes and user mouse and key events. The toolkit makes extensive + * elements with panel state changes and user mouse and key events. The alignment makes extensive * use of the Canvas API for image rendering and markup. Image transformations use the OpenCV.js * JavaScript libraries. * @@ -31,25 +31,25 @@ import {memo, useEffect, useRef, useState} from 'react'; import saveAs from 'file-saver'; -import PanelMenu from './menu.panel.toolkit'; -import PanelInfo from './info.panel.toolkit'; -import Register from '../tools/register.toolkit'; -import MagnifierTool from '../canvas/magnifier.canvas.toolkit'; +import PanelMenu from './menu.panel.alignment'; +import PanelInfo from './info.panel.alignment'; +import Register from '../tools/register.alignment'; +import MagnifierTool from '../canvas/magnifier.canvas.alignment'; import baseGrid from '../../svg/grid.svg'; -import CropTool, {cropImage} from '../tools/cropper.toolkit'; -import {useIat} from "../../../_providers/toolkit.provider.client"; -import Canvas from "../canvas/default.canvas.toolkit"; -import {getScale, inRange, scalePoint, scaleToFit} from "../tools/scaler.toolkit"; -import {loadImage} from "../utils/loader.utils.toolkit"; -import LoadButton from "./placeholder.panel.toolkit"; -import {useController} from "./controller.panel.toolkit"; -import Grid from "../canvas/grid.canvas.toolkit"; +import CropTool, {cropImage} from '../tools/cropper.alignment'; +import {useIat} from "../../../_providers/alignment.provider.client"; +import Canvas from "../canvas/default.canvas.alignment"; +import {getScale, inRange, scalePoint, scaleToFit} from "../tools/scaler.alignment"; +import {loadImage} from "../utils/loader.utils.alignment"; +import LoadButton from "./placeholder.panel.alignment"; +import {useController} from "./controller.panel.alignment"; +import Grid from "../canvas/grid.canvas.alignment"; import {UserMessage} from "../../common/message"; -import Overlay from "../canvas/overlay.canvas.toolkit"; +import Overlay from "../canvas/overlay.canvas.alignment"; import {getError} from "../../../_services/schema.services.client"; -import {getPos} from "../tools/pointer.toolkit"; +import {getPos} from "../tools/pointer.alignment"; import {useWindowSize} from "../../../_utils/events.utils.client"; -import {alignImages} from "../utils/align.utils.toolkit"; +import {alignImages} from "../utils/align.utils.alignment"; /** * IAT panel component. @@ -61,7 +61,7 @@ import {alignImages} from "../utils/align.utils.toolkit"; * @public */ -const PanelToolkit = ({id = null}) => { +const PanelAlignment = ({id = null}) => { const iat = useIat(); const panel = iat[id]; @@ -1219,4 +1219,4 @@ const PanelToolkit = ({id = null}) => { ; }; -export default memo(PanelToolkit); +export default memo(PanelAlignment); diff --git a/client/src/_components/toolkit/panel/placeholder.panel.toolkit.js b/client/src/_components/alignment/panel/placeholder.panel.alignment.js similarity index 94% rename from client/src/_components/toolkit/panel/placeholder.panel.toolkit.js rename to client/src/_components/alignment/panel/placeholder.panel.alignment.js index 5c547f70..5f8a07dc 100644 --- a/client/src/_components/toolkit/panel/placeholder.panel.toolkit.js +++ b/client/src/_components/alignment/panel/placeholder.panel.alignment.js @@ -1,13 +1,13 @@ /*! * MLE.Client.Components.Toolkit.LoadButton - * File: load_button.toolkit.js + * File: load_button.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed */ import {memo} from 'react'; -import {useIat} from "../../../_providers/toolkit.provider.client"; +import {useIat} from "../../../_providers/alignment.provider.client"; import Button from "../../common/button"; /** diff --git a/client/src/_components/toolkit/tools/comparator.toolkit.js b/client/src/_components/alignment/tools/comparator.alignment.js similarity index 98% rename from client/src/_components/toolkit/tools/comparator.toolkit.js rename to client/src/_components/alignment/tools/comparator.alignment.js index 2f3b76b2..fb609dd7 100644 --- a/client/src/_components/toolkit/tools/comparator.toolkit.js +++ b/client/src/_components/alignment/tools/comparator.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Tools.Toolkit.Comparator - * File: comparator.toolkit.js + * File: comparator.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -18,16 +18,16 @@ import React, {useEffect, useLayoutEffect, useRef, useState} from 'react'; import InputSelector from '../../selectors/input.selector'; -import {useIat} from "../../../_providers/toolkit.provider.client"; -import Canvas from "../canvas/default.canvas.toolkit"; -import {getScale, scalePoint, scaleToFit} from "./scaler.toolkit"; -import {getPos, usePointer} from "./pointer.toolkit"; +import {useIat} from "../../../_providers/alignment.provider.client"; +import Canvas from "../canvas/default.canvas.alignment"; +import {getScale, scalePoint, scaleToFit} from "./scaler.alignment"; +import {getPos, usePointer} from "./pointer.alignment"; import Button from "../../common/button"; import baseGrid from "../../svg/grid.svg"; -import Grid from "../canvas/grid.canvas.toolkit"; -import CropTool, {cropImage} from "./cropper.toolkit"; +import Grid from "../canvas/grid.canvas.alignment"; +import CropTool, {cropImage} from "./cropper.alignment"; import Badge from "../../common/badge"; -import Overlay from "../canvas/overlay.canvas.toolkit"; +import Overlay from "../canvas/overlay.canvas.alignment"; /** * Comparator component for comparing and overlaying Alignment Tool panel images diff --git a/client/src/_components/toolkit/tools/cropper.toolkit.js b/client/src/_components/alignment/tools/cropper.alignment.js similarity index 98% rename from client/src/_components/toolkit/tools/cropper.toolkit.js rename to client/src/_components/alignment/tools/cropper.alignment.js index c78b91ae..0f05dc22 100644 --- a/client/src/_components/toolkit/tools/cropper.toolkit.js +++ b/client/src/_components/alignment/tools/cropper.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Components.Toolkit.Cropper - * File: cropper.toolkit.js + * File: cropper.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -18,8 +18,8 @@ import React from 'react'; import InputSelector from '../../selectors/input.selector'; import Button from '../../common/button'; -import {getScale} from './scaler.toolkit'; -import {useIat} from "../../../_providers/toolkit.provider.client"; +import {getScale} from './scaler.alignment'; +import {useIat} from "../../../_providers/alignment.provider.client"; /** * Creates cropper control panel component. diff --git a/client/src/_components/toolkit/tools/downloader.toolkit.js b/client/src/_components/alignment/tools/downloader.alignment.js similarity index 95% rename from client/src/_components/toolkit/tools/downloader.toolkit.js rename to client/src/_components/alignment/tools/downloader.alignment.js index 1fae10c9..a78a758d 100644 --- a/client/src/_components/toolkit/tools/downloader.toolkit.js +++ b/client/src/_components/alignment/tools/downloader.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Toolkit.Loaders.Downloader - * File: downloader.toolkit.js + * File: downloader.alignment.js * Copyright(c) 2022 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -9,7 +9,7 @@ import React from 'react'; import Button from '../../common/button'; import InputSelector from '../../selectors/input.selector'; -import { useIat } from "../../../_providers/toolkit.provider.client"; +import { useIat } from "../../../_providers/alignment.provider.client"; /** * Defines download local file button. Expects callback to retrieve data diff --git a/client/src/_components/toolkit/tools/importer.toolkit.js b/client/src/_components/alignment/tools/importer.alignment.js similarity index 97% rename from client/src/_components/toolkit/tools/importer.toolkit.js rename to client/src/_components/alignment/tools/importer.alignment.js index f212c774..d8563c18 100644 --- a/client/src/_components/toolkit/tools/importer.toolkit.js +++ b/client/src/_components/alignment/tools/importer.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Components.Toolkit.Importer - * File: importer.toolkit.js + * File: importer.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -9,7 +9,7 @@ import React from 'react'; import {createRoute, redirect} from '../../../_utils/paths.utils.client'; import {useUser} from '../../../_providers/user.provider.client'; -import {useIat} from "../../../_providers/toolkit.provider.client"; +import {useIat} from "../../../_providers/alignment.provider.client"; import InputSelector from "../../selectors/input.selector"; import {UserMessage} from "../../common/message"; import {useRouter} from "../../../_providers/router.provider.client"; @@ -31,7 +31,7 @@ import Table from "../../common/table"; * @param callback */ -export const ImporterToolkit = ({ id = null, callback = () => {}, cancel = () => {} }) => { +export const ImporterAlignment = ({ id = null, callback = () => {}, cancel = () => {} }) => { const router = useRouter(); const nav = useNav(); @@ -114,14 +114,17 @@ export const ImporterToolkit = ({ id = null, callback = () => {}, cancel = () => const _handleSubmit = () => { const {file_type = '', id = ''} = selectedImage || {}; const params = selectedPanel === 'panel1' ? {file1: id, type1: file_type} : {file2: id, type2: file_type}; - callback(); + + console.log(params) // load image in Explorer Toolkit - // - if in toolkit mode, load directly to canvas + // - if in alignment mode, load directly to canvas // - otherwise, redirect with query params window.location.pathname === '/toolkit' ? iat.setInputParams(params) : redirect(createRoute('/toolkit', params)); + + callback(); }; // update selected image file for canvas loading diff --git a/client/src/_components/toolkit/tools/loader.toolkit.js b/client/src/_components/alignment/tools/loader.alignment.js similarity index 72% rename from client/src/_components/toolkit/tools/loader.toolkit.js rename to client/src/_components/alignment/tools/loader.alignment.js index 2d7bba3f..c80ca6d5 100644 --- a/client/src/_components/toolkit/tools/loader.toolkit.js +++ b/client/src/_components/alignment/tools/loader.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Components.Selectors.IAT - * File: loader.toolkit.js + * File: loader.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -8,8 +8,8 @@ import React from 'react'; import Tabs from "../../common/tabs"; -import {UploaderToolkit} from "./uploader.toolkit"; -import {ImporterToolkit} from "./importer.toolkit"; +import {UploaderAlignment} from "./uploader.alignment"; +import {ImporterAlignment} from "./importer.alignment"; import {useUser} from "../../../_providers/user.provider.client"; /** @@ -33,14 +33,14 @@ export const LoaderTool = ({id=null, model=null, callback = ()=>{}, cancel=()=>{ const user = useUser(); const _tabs = [{ - label: `Load in Toolkit`, - data: , + label: `Load in Alignment Tool`, + data: , }]; // Upload restricted to admin users if (user) _tabs.push({ - label: `Upload to Library`, - data: , + label: `Upload Image to Library`, + data: , }); return <> diff --git a/client/src/_components/toolkit/tools/opener.toolkit.js b/client/src/_components/alignment/tools/opener.alignment.js similarity index 96% rename from client/src/_components/toolkit/tools/opener.toolkit.js rename to client/src/_components/alignment/tools/opener.alignment.js index 20f89372..46d03025 100644 --- a/client/src/_components/toolkit/tools/opener.toolkit.js +++ b/client/src/_components/alignment/tools/opener.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Components.Toolkit.Opener - * File: opener.toolkit.js + * File: opener.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -22,11 +22,11 @@ import Accordion from '../../common/accordion'; import Button from '../../common/button'; import InputSelector from '../../selectors/input.selector'; import { UserMessage } from '../../common/message'; -import {useIat} from "../../../_providers/toolkit.provider.client"; -import {initPanel} from "../panel/init.panel.toolkit"; +import {useIat} from "../../../_providers/alignment.provider.client"; +import {initPanel} from "../panel/init.panel.alignment"; import {useDialog} from "../../../_providers/dialog.provider.client"; import {useNav} from "../../../_providers/nav.provider.client"; -import {getTooltip} from "../../content/toolkit.help"; +import {getTooltip} from "../../content/alignment.help"; import {useUser} from "../../../_providers/user.provider.client"; /** diff --git a/client/src/_components/toolkit/tools/pointer.toolkit.js b/client/src/_components/alignment/tools/pointer.alignment.js similarity index 98% rename from client/src/_components/toolkit/tools/pointer.toolkit.js rename to client/src/_components/alignment/tools/pointer.alignment.js index 160c70ac..b593ac59 100644 --- a/client/src/_components/toolkit/tools/pointer.toolkit.js +++ b/client/src/_components/alignment/tools/pointer.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Components.Toolkit.Pointer - * File: pointer.toolkit.js + * File: pointer.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -24,7 +24,7 @@ */ import {useState} from 'react'; -import {scalePoint} from "./scaler.toolkit"; +import {scalePoint} from "./scaler.alignment"; /** * Compute local mouse position on canvas. diff --git a/client/src/_components/toolkit/tools/register.toolkit.js b/client/src/_components/alignment/tools/register.alignment.js similarity index 97% rename from client/src/_components/toolkit/tools/register.toolkit.js rename to client/src/_components/alignment/tools/register.alignment.js index c2de92a1..06378e23 100644 --- a/client/src/_components/toolkit/tools/register.toolkit.js +++ b/client/src/_components/alignment/tools/register.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Components.Toolkit.Register - * File: register.toolkit.js + * File: register.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -9,7 +9,7 @@ * Description * * Toolkit panel component is the main container for the canvas stack and integrates referenced DOM - * elements with panel state changes and user mouse and key events. The toolkit makes extensive + * elements with panel state changes and user mouse and key events. The alignment makes extensive * use of the Canvas API for image rendering and markup. Image transformations use the OpenCV.js * JavaScript libraries. * @@ -33,10 +33,10 @@ import Button from '../../common/button'; import React, {useState} from 'react'; import Badge from '../../common/badge'; -import {useIat} from "../../../_providers/toolkit.provider.client"; +import {useIat} from "../../../_providers/alignment.provider.client"; import InputSelector from "../../selectors/input.selector"; -import {correlation} from "../utils/align.utils.toolkit"; -import {scalePoint} from "./scaler.toolkit"; +import {correlation} from "../utils/align.utils.alignment"; +import {scalePoint} from "./scaler.alignment"; /** * Show selected control points for image alignment/registration. Allows for editing and deletion of points. diff --git a/client/src/_components/toolkit/tools/resizer.toolkit.js b/client/src/_components/alignment/tools/resizer.alignment.js similarity index 99% rename from client/src/_components/toolkit/tools/resizer.toolkit.js rename to client/src/_components/alignment/tools/resizer.alignment.js index 42162be3..dd80be4a 100644 --- a/client/src/_components/toolkit/tools/resizer.toolkit.js +++ b/client/src/_components/alignment/tools/resizer.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Tools.Toolkit.Resizer - * File: resizer.toolkit.js + * File: resizer.alignment.js * Copyright(c) 2022 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -10,7 +10,7 @@ import React from 'react'; import Button from '../../common/button'; import { UserMessage } from '../../common/message'; import InputSelector from '../../selectors/input.selector'; -import {useIat} from "../../../_providers/toolkit.provider.client"; +import {useIat} from "../../../_providers/alignment.provider.client"; /** * Adjustments to layer dimensions. diff --git a/client/src/_components/toolkit/tools/scaler.toolkit.js b/client/src/_components/alignment/tools/scaler.alignment.js similarity index 98% rename from client/src/_components/toolkit/tools/scaler.toolkit.js rename to client/src/_components/alignment/tools/scaler.alignment.js index 30615186..82af860b 100644 --- a/client/src/_components/toolkit/tools/scaler.toolkit.js +++ b/client/src/_components/alignment/tools/scaler.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Toolkit.Transform - * File: scaler.toolkit.js + * File: scaler.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed diff --git a/client/src/_components/toolkit/tools/uploader.toolkit.js b/client/src/_components/alignment/tools/uploader.alignment.js similarity index 95% rename from client/src/_components/toolkit/tools/uploader.toolkit.js rename to client/src/_components/alignment/tools/uploader.alignment.js index 8d9af7be..17048f9f 100644 --- a/client/src/_components/toolkit/tools/uploader.toolkit.js +++ b/client/src/_components/alignment/tools/uploader.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Components.Toolkit.Uploader - * File: uploader.toolkit.js + * File: uploader.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -21,10 +21,10 @@ import Editor from '../../editors/default.editor'; import {genSchema} from '../../../_services/schema.services.client'; import {createNodeRoute} from '../../../_utils/paths.utils.client'; import { useUser } from '../../../_providers/user.provider.client'; -import {useIat} from "../../../_providers/toolkit.provider.client"; +import {useIat} from "../../../_providers/alignment.provider.client"; import InputSelector from "../../selectors/input.selector"; import {UserMessage} from "../../common/message"; -import Canvas from "../canvas/default.canvas.toolkit"; +import Canvas from "../canvas/default.canvas.alignment"; /** * Upload images from IAT canvas to MLP library. @@ -32,7 +32,7 @@ import Canvas from "../canvas/default.canvas.toolkit"; * @public */ -export const UploaderToolkit = ({ id=null, model=null, callback = () => {}, cancel = () => {} }) => { +export const UploaderAlignment = ({ id=null, model=null, callback = () => {}, cancel = () => {} }) => { const user = useUser(); const iat = useIat(); diff --git a/client/src/_components/toolkit/utils/align.utils.toolkit.js b/client/src/_components/alignment/utils/align.utils.alignment.js similarity index 99% rename from client/src/_components/toolkit/utils/align.utils.toolkit.js rename to client/src/_components/alignment/utils/align.utils.alignment.js index 0ef6142a..45060d40 100644 --- a/client/src/_components/toolkit/utils/align.utils.toolkit.js +++ b/client/src/_components/alignment/utils/align.utils.alignment.js @@ -222,7 +222,7 @@ export const alignImages = (cv = null, srcPanel, dstPanel, canvas, targetImage, /*! * MLE.Client.Toolkit.Utilities.Align - * File: align.utils.toolkit.js + * File: align.utils.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed diff --git a/client/src/_components/toolkit/utils/loader.utils.toolkit.js b/client/src/_components/alignment/utils/loader.utils.alignment.js similarity index 95% rename from client/src/_components/toolkit/utils/loader.utils.toolkit.js rename to client/src/_components/alignment/utils/loader.utils.alignment.js index b645f771..2ed130ca 100644 --- a/client/src/_components/toolkit/utils/loader.utils.toolkit.js +++ b/client/src/_components/alignment/utils/loader.utils.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Toolkit.Utilities.Loader - * File: loader.utils.toolkit.js + * File: loader.utils.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -93,6 +93,8 @@ export const loadImage = async (properties, callback) => { api: (id, selectRaw) => { + console.log(id, selectRaw) + /** * Update progress data. Progress data is updated until * uploading has completed. @@ -112,16 +114,16 @@ export const loadImage = async (properties, callback) => { // - converted to MB const { loaded = 0, total = 0 } = e || {}; - // const completedBytes = (loaded / 1000000).toFixed(2); - // const totalBytes = (total / 1000000).toFixed(2); - // const percent = (100 * (completedBytes / totalBytes)).toFixed(0); - // const notProgressive = total === 0; + const completedBytes = (loaded / 1000000).toFixed(2); + const totalBytes = (total / 1000000).toFixed(2); + const percent = (100 * (completedBytes / totalBytes)).toFixed(0); + const notProgressive = total === 0; const done = (total > 0 && loaded > 0 && total === loaded); // update progress state // if (!notProgressive) setMessage({msg: `${percent}%`, type: 'info'}); // else setMessage({msg: `${completedBytes}MB`, type: 'info'}); - //console.log(e, {msg: `${percent}%`, type: 'info'}); + console.log(e, {msg: `${percent}%`, type: 'info'}); // end loading if (done) { diff --git a/client/src/_components/toolkit/utils/tiff.utils.toolkit.js b/client/src/_components/alignment/utils/tiff.utils.alignment.js similarity index 99% rename from client/src/_components/toolkit/utils/tiff.utils.toolkit.js rename to client/src/_components/alignment/utils/tiff.utils.alignment.js index 5d84efc0..1e61f051 100644 --- a/client/src/_components/toolkit/utils/tiff.utils.toolkit.js +++ b/client/src/_components/alignment/utils/tiff.utils.alignment.js @@ -1,6 +1,6 @@ /*! * MLE.Client.Toolkit.Utilities.Align - * File: align.utils.toolkit.js + * File: align.utils.alignment.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed diff --git a/client/src/_components/common/form.js b/client/src/_components/common/form.js index df813709..0bcc89cc 100644 --- a/client/src/_components/common/form.js +++ b/client/src/_components/common/form.js @@ -18,7 +18,7 @@ * * --------- * Revisions - * + * - 30-11-2023 Fixed form reset to nullify form data in-component * */ @@ -36,6 +36,9 @@ import {getError} from "../../_services/schema.services.client"; // default form error const defaultError = {msg: getError(), type: 'error'}; +// default noop +const noop = async ()=>{}; + /** * Defines general form component. * @@ -57,12 +60,12 @@ const defaultError = {msg: getError(), type: 'error'}; const Form = ({ model, schema, - loader = null, + loader = noop, callback, messages={}, onChange = () => {}, onCancel = () => {}, - onReset = null, + onReset = () => {}, opts = null, allowEmpty = false, disabledInputs = {}, @@ -75,15 +78,15 @@ const Form = ({ // generate unique ID value for form inputs const formID = `_form_${model}_${view}_`; - const _isMounted = React.useRef(false); // initialize state for input parameters // const [data, setData] = React.useState({}); const [data, setData] = React.useState({}); const [loaded, setLoaded] = React.useState(false); + const [loading, setLoading] = React.useState(true); const [fieldsetSchema, setFieldsetSchema] = React.useState([]); const [modified, setModified] = React.useState(false); - const [isDisabled, setDisabled] = React.useState(false); + const [isDisabled, setDisabled] = React.useState(true); // create input error states / message state const [errors, setErrors] = React.useState({}); @@ -94,57 +97,42 @@ const Form = ({ // initialize fieldset schema on navigation change // - set fieldset schema to initial schema if not modified in form editor React.useEffect(() => { - _isMounted.current = true; - if (_isMounted.current) { - setLoaded(false); - if (fieldsets.length !== 0) { - // ensure fieldsets are initialized - setFieldsetSchema(fieldsets); - } + // setLoaded(false); + if (fieldsets.length !== 0) { + // ensure fieldsets are initialized + setFieldsetSchema(fieldsets); } - return () => { - _isMounted.current = false; - }; }, [fieldsets, nav]); // initialize fieldset schema // - set fieldset schema to initial schema if not modified in form editor React.useEffect(() => { - _isMounted.current = true; - if (_isMounted.current && !modified && fieldsets.length !== 0) { + if (!modified && fieldsets.length !== 0 && !loading) { // ensure fieldsets are initialized setFieldsetSchema(fieldsets); } - return () => { - _isMounted.current = false; - }; - }, [fieldsets, modified]); + }, [fieldsets, modified, loading]); + + + const _loadFormData = () => { + // load form data + loader() + .then(data => { + // set metadata in external state + setData(data); + setLoaded(true); + }) + .catch(err => { + console.error(err); + setMessage(data => ({ ...data, '0': defaultError})); + }) + .finally(() => {setLoading(false)}); + setLoading(false); + setDisabled(false); + } // update form data on dialog change - React.useEffect( () => { - _isMounted.current = true; - if (_isMounted.current && !loaded && loader) { - loader() - .then(data => { - if (_isMounted.current) { - // set metadata in external state - // console.log('Loader:', data) - setData(data); - setLoaded(true); - } - }) - .catch(err => { - if (_isMounted.current) { - console.error(err); - setMessage(data => ({ ...data, '0': defaultError})); - } - }); - } - else if (_isMounted.current) setLoaded(true); - return () => { - _isMounted.current = false; - }; - }, [loader, loaded]); + React.useEffect( _loadFormData, []); // update form data state const _handleChange = (name, value) => { @@ -158,6 +146,12 @@ const Form = ({ onCancel(); } + // handle form reset + const _handleReset = () => { + setData({}); + onReset(); + } + /** * Generate form data validation handlers. * @@ -298,6 +292,7 @@ const Form = ({ return callback(formData) .finally(() => { setDisabled(false); + _loadFormData(); }); } catch (err) { console.error(callback, err); @@ -467,7 +462,7 @@ const Form = ({ disabled={isDisabled} onSubmit={submit} onCancel={_handleCancel} - onReset={onReset} + onReset={_handleReset} /> { diff --git a/client/src/_components/common/icon.js b/client/src/_components/common/icon.js index 1c043725..0dc65a75 100644 --- a/client/src/_components/common/icon.js +++ b/client/src/_components/common/icon.js @@ -10,6 +10,10 @@ import React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { library } from '@fortawesome/fontawesome-svg-core'; import { + + faMapMarker, + faVectorSquare, + faLayerGroup, faPaperclip, faLocationArrow, faChartBar, @@ -113,7 +117,6 @@ import { * @public */ - export const facSurveyor = { prefix: 'fas', iconName: 'surveyor', @@ -137,6 +140,9 @@ export const facMLPWordmark = { */ library.add( + faMapMarker, + faVectorSquare, + faLayerGroup, faLocationArrow, faArrowsAltH, faChartBar, @@ -277,13 +283,17 @@ const getIconClass = (iconType) => { delete: 'trash-alt', import: 'file-import', export: 'file-export', + extract: 'file-export', attach: 'paperclip', scroll: 'location-arrow', externalLink: 'external-link-square-alt', align: 'crosshairs', - overlay: 'columns', + overlay: 'layer-group', + clustered: 'map-marker', + boundaries: 'vector-square', filter: 'filter', filterNavigation: 'filter', + list: 'list-alt', search: 'search', undo: 'undo', reset: 'undo', @@ -349,6 +359,8 @@ const getIconClass = (iconType) => { supplemental_images: 'image', locations: 'compass', glass_plate_listings: 'archive', + map_objects: 'map', + map_features: 'vector-square', maps: 'map', participants: 'users', participant_groups: 'users', @@ -365,6 +377,7 @@ const getIconClass = (iconType) => { raw: 'file-image', pdf: 'file-pdf', rtf: 'file-alt', + zip: 'file-archive', default: 'star', mlp: 'mlp_logo', wordmark: 'mlp_wordmark', diff --git a/client/src/_components/common/message.js b/client/src/_components/common/message.js index a15b93a3..e70a68dc 100644 --- a/client/src/_components/common/message.js +++ b/client/src/_components/common/message.js @@ -24,7 +24,7 @@ import Icon from './icon'; const Message = ({ closeable=true, - message='', + message=null, icon='info', timeout=false, className='', diff --git a/client/src/_components/common/singleselect.js b/client/src/_components/common/singleselect.js new file mode 100644 index 00000000..8cb0014e --- /dev/null +++ b/client/src/_components/common/singleselect.js @@ -0,0 +1,62 @@ +/*! + * MLE.Client.Components.Common.SingleSelect + * File: singleselect.js + * Copyright(c) 2023 Runtime Software Development Inc. + * Version 2.0 + * MIT Licensed + */ + +import React from 'react'; +import { sorter } from '../../_utils/data.utils.client'; + +/** + * Build multiselect widget. + * + * @public + * @param id + * @param name + * @param label + * @param value + * @param disabled + * @param required + * @param disabled + * @param options + * @param onChange + * @param onSelect + */ + +const SingleSelect = ({ id, name, label, value, disabled, required, options, onChange, onSelect }) => { + // prepare options data for select input + const opts = options + .sort(sorter) + .map((opt, index) => { + const {value = '', label = ''} = opt || {}; + return ; + }); + + return ; +}; + +export default SingleSelect; \ No newline at end of file diff --git a/client/src/_components/common/slider.js b/client/src/_components/common/slider.js index d771a9ed..5fedef27 100644 --- a/client/src/_components/common/slider.js +++ b/client/src/_components/common/slider.js @@ -19,9 +19,9 @@ import React, {useLayoutEffect, useRef, useState} from 'react'; import { schema } from '../../schema'; import Loading from './loading'; import { UserMessage } from './message'; -import {scaleToFit} from '../toolkit/tools/scaler.toolkit'; +import {scaleToFit} from '../alignment/tools/scaler.alignment'; import InputSelector from "../selectors/input.selector"; -import Canvas from "../toolkit/canvas/default.canvas.toolkit"; +import Canvas from "../alignment/canvas/default.canvas.alignment"; import styles from '../styles/slider.module.css'; import {useWindowSize} from "../../_utils/events.utils.client"; diff --git a/client/src/_components/common/table.js b/client/src/_components/common/table.js index e704de09..49fd509e 100644 --- a/client/src/_components/common/table.js +++ b/client/src/_components/common/table.js @@ -8,31 +8,7 @@ import React from 'react'; import Loading from './loading'; - -/** - * Render table header. - * - * @public - * @param tableID - * @param { rows } - * @return {JSX.Element} - */ - -const TableHeader = ({ tableID, cols }) => { - return - - { - cols.map((col, index) => - - {col.label} - ) - } - - -} +import Icon from "./icon"; /** * Render table body. Filters item values not defined in @@ -48,23 +24,23 @@ const TableHeader = ({ tableID, cols }) => { const TableBody = ({tableID, rows, cols}) => { const noop = ()=>{}; return { - rows.map((row, index) => { - return ( - - { - cols - .filter(col => row.hasOwnProperty(col.name)) - .map(col => - - {row[col.name]} - - ) - } - - ); - }) + rows.map((row, index) => { + return ( + + { + cols + .filter(col => row.hasOwnProperty(col.name)) + .map(col => + + {row[col.name]} + + ) + } + + ); + }) } } @@ -87,15 +63,62 @@ const Table = ({ rows, cols, className=''}) => { // generate unique ID value for table const tableID = Math.random().toString(16).substring(2); + // determine default sort field + const defaultSort = cols.filter(({defaultSort}) => !!defaultSort).map(({name}) => name).join(); + const [sortBy, setSortBy] = React.useState(defaultSort); + const [order, setOrder] = React.useState(1); + + function _selectSort(col) { + console.log(col) + setSortBy(col); + setOrder(-order); + } + + function _compareFn(a, b) { + // ensure field value can be sorted by selected column name + if (!a.hasOwnProperty(sortBy) || !a.hasOwnProperty(sortBy)) return 0; + const nameA = String(a[sortBy]).toLowerCase(); // ignore upper and lowercase + const nameB = String(b[sortBy]).toLowerCase(); // ignore upper and lowercase + if (nameA < nameB) { + return -order; + } + if (nameA > nameB) { + return order; + } + + // names must be equal + return 0; + } + // ensure data has been retrieved return Array.isArray(rows) && Array.isArray(cols) ? - - - -
+ + + + { + cols.map((col, index) => + ) + } + + + +
{_selectSort(col.name)}} + > +
+
    +
  • {col.label}
  • +
  • + +
  • +
+
+
: - + } export default Table diff --git a/client/src/_components/common/tree.js b/client/src/_components/common/tree.js new file mode 100644 index 00000000..1f26d188 --- /dev/null +++ b/client/src/_components/common/tree.js @@ -0,0 +1,316 @@ +/*! + * MLE.Client.Components.Common.Tree + * File: tree.js + * Copyright(c) 2023 Runtime Software Development Inc. + * Version 2.0 + * MIT Licensed + * + * ---------- + * Description + * + * Node tree (list) component. Expandable node tree menu. + * + * --------- + * Revisions + */ + +import React from 'react' +import {useRouter} from '../../_providers/router.provider.client'; +import {useData} from '../../_providers/data.provider.client'; +import {createNodeRoute} from '../../_utils/paths.utils.client'; +import {getModelLabel, getNodeOrder } from '../../_services/schema.services.client'; +import Button from '../common/button'; +import {sorter} from '../../_utils/data.utils.client'; +import Loading from '../common/loading'; +import Accordion from "../common/accordion"; +import {useNav} from "../../_providers/nav.provider.client"; +import {useWindowSize} from "../../_utils/events.utils.client"; +import styles from '../styles/tree.module.css'; + +/** + * Navigation tree node component. + * + * @public + * @param {Object} item + */ + +const TreeNode = ({data, depth, maxdepth, callback=()=>{}}) => { + + // destructure node data + const { + type='', + id='', + label='', + hasDependents=false + } = data || {}; + + // create dynamic data states + const [toggle, setToggle] = React.useState(false); + const [selected, setSelected] = React.useState(false); + const [loadedData, setLoadedData] = React.useState(null); + const [error, setError] = React.useState(null); + const treeNode = React.createRef(); + const _isMounted = React.useRef(true); + + // initialization + const router = useRouter(); + const api = useData(); + + // get full model label + const modelLabel = getModelLabel(type); + + // handle toggle events + const _handleToggle = () => { + // open collapsible + setToggle(!toggle); + } + + // handle select events + const _handleSelect = () => { + callback(type, id); + setSelected(!selected); + } + + // toggle button classnames + const classnames = [ + 'tree-node', + hasDependents ? 'toggle' : 'leaf' + ]; + + // API call to retrieve node data (if not yet loaded) + React.useEffect(() => { + _isMounted.current = true; + + // load tree node data + if (!error && hasDependents && toggle && !loadedData) { + const route = createNodeRoute('nodes', 'show', id); + router.get(route) + .then(res => { + // update state with response data + if (_isMounted.current) { + + if (res.error) return setError(res.error); + + // destructure any available dependent nodes + const {response = {}} = res || {}; + let {data = {}} = response || {}; + const {dependents = []} = data || {}; + + // separate sorted from unsorted captures or non-capture nodes + const unsorted = dependents.filter(item => { + const { node = {}, status = '' } = item || {}; + const {type = ''} = node || {}; + return ( type === 'historic_captures' || type === 'modern_captures' ) && (status === 'unsorted') + }); + const sorted = dependents.filter(item => { + const { node = {}, status = '' } = item || {}; + const {type = ''} = node || {}; + return ( type !== 'historic_captures' && type !== 'modern_captures' ) || status !== 'unsorted' + }); + + // store separate properties to accommodate sorted/unsorted captures + setLoadedData({ + sorted: sorted, + unsorted: unsorted + }); + } + }) + .catch(err => console.error(err) + ); + } + return () => { + _isMounted.current = false; + }; + }, [ + api, + router, + id, + hasDependents, + toggle, + treeNode, + loadedData, + setLoadedData, + error + ]); + + return ( + <> +
+
+
    +
  • +
  • +
  • +
  • +
  • +
  • +
+
+ { + // toggle dependent nodes list + toggle && hasDependents + ? error + ?
+ + ); +} + +/** + * Navigation tree node list component. + * - Discovers appropriate menu label text using schema + * - Sorts node items: (1) Node order; (2) Alphabetically by label + * + * @public + */ + +const TreeNodeList = ({items, maxdepth, depth, callback}) => { + depth += 1; + return maxdepth > depth &&
    + { + // return sorted nodes + items + .map(item => { + const { + node = {}, + file = {}, + hasDependents = false, + status = '', + label = '', + metadata = {}, + refImage = {}, + attached = {} + } = item || {}; + const {id = '', type = '', owner_id = '', owner_type = ''} = node || {}; + const {file_size = 0, mimetype = '', filename = ''} = file || {}; + const {url = ''} = refImage || {}; + let itemMetadata = metadata || {}; + // include file metadata in details + itemMetadata.filename = filename; + itemMetadata.file_size = file_size; + itemMetadata.mimetype = mimetype; + return { + type: type, + id: id, + label: label, + node: node, + order: getNodeOrder(type || '') || 0, + hasDependents: hasDependents, + status: status, + metadata: itemMetadata, + url: url, + attached: attached, + owner: {type: owner_type, id: owner_id} + } + }) + // sort alphabetically / numerically + .sort(sorter) + // sort by node order + .sort(function (a, b) { + return a.order - b.order; + }) + .map(item => { + return ( +
  • + +
  • + ) + }) + } +
; +} + +/** + * Node Tree component. + * + * @public + * + * @return + */ + +const Tree = ({hidden, depth=1, callback=()=>{}}) => { + + const nav = useNav(); + const treeRef = React.useRef(); + + // window dimensions + const [, winHeight] = useWindowSize(); + + console.log('Tree data:', nav.tree) + + return <> + { + nav.tree && Object.keys(nav.tree).length > 0 + ? + : + } + +} + +export default React.memo(Tree) \ No newline at end of file diff --git a/client/src/_components/content/toolkit.help.js b/client/src/_components/content/alignment.help.js similarity index 93% rename from client/src/_components/content/toolkit.help.js rename to client/src/_components/content/alignment.help.js index a95b5156..ce6ccf9c 100644 --- a/client/src/_components/content/toolkit.help.js +++ b/client/src/_components/content/alignment.help.js @@ -1,6 +1,6 @@ /*! - * MLE.Client.Content.Help.Toolkit - * File: toolkit.help.js + * MLE.Client.Content.Help.Alignment + * File: alignment.help.js * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed @@ -8,11 +8,11 @@ * ---------- * Description * - * Help pages for the Image Toolkit component. + * Help pages for the Image Alignment component. * * --------- * Revisions - * - 09-07-2023 Updated instructions for upgraded Toolkit workflows and features. + * - 09-07-2023 Updated instructions for upgraded alignment workflows and features. */ import React from 'react'; @@ -40,10 +40,10 @@ const tooltips = {

To load an image from the MLP Library to the Alignment Tool:

  1. Locate the capture image in the navigator tree
  2. -
  3. Click the icon to open the Toolkit loader dialog
  4. -
  5. Select which Toolkit panel you want to load the image
  6. +
  7. Click the icon to open the Alignment loader dialog
  8. +
  9. Select which Alignment panel you want to load the image
  10. Select the image version you want to load
  11. -
  12. Click the green 'Load Image in Toolkit' button
  13. +
  14. Click the green 'Load Image in Alignment' button
, loadLocalImage:
@@ -61,8 +61,8 @@ const tooltips = {

To upload an image to the MLP Library from the Alignment Tool:

  1. Locate the capture image in the navigator tree
  2. -
  3. Click the icon to open the Toolkit Loader tool
  4. -
  5. Select which Toolkit panel you want to load the image
  6. +
  7. Click the icon to open the Alignment Loader tool
  8. +
  9. Select which Alignment panel you want to load the image
  10. Select the image format for the uploaded image
  11. Select the image version you want to upload
  12. Click the green 'Upload Image to MLP Library' button
  13. @@ -145,7 +145,7 @@ const tooltips = { * @public */ -const toolkitHelp = (gotoPage) => { +const alignmentHelp = (gotoPage) => { const gettingStarted = <> @@ -454,9 +454,9 @@ const toolkitHelp = (gotoPage) => { * @public */ - const toolkitModes = <> + const alignmentModes = <>

    Alignment Tool Modes

    -

    Toolkit operations are available in four modes:

    +

    Alignment operations are available in four modes:

    @@ -532,20 +532,6 @@ const toolkitHelp = (gotoPage) => { ; - const masteredImages = <> -

    Image Mastering in MLE

    -

    For aligned and registered images classified as 'mastered' to be uploaded to the MLP library, they must meet the following preconditions:

    -
      -
    1. Capture images are aligned Both capture image must be aligned Follow the instructions - in
    2. -
    3. Capture images are sorted The historic and modern capture images must be attached to a - historic visit and location (modern visit) respectively, which are associated - with a common station node. -
    4. -
    - - return [ { label: 'Getting Started', @@ -564,19 +550,15 @@ const toolkitHelp = (gotoPage) => { data: panelControls, }, { - label: 'Toolkit Modes', - data: toolkitModes, + label: 'Alignment Modes', + data: alignmentModes, }, { label: 'Image Registration', data: alignmentIATHelp, - }, - { - label: 'Mastered Images in MLE', - data: masteredImages, - }, + } ]; } -export default toolkitHelp; +export default alignmentHelp; diff --git a/client/src/_components/content/editor.help.js b/client/src/_components/content/editor.help.js index 27e5b4e6..80a0243d 100644 --- a/client/src/_components/content/editor.help.js +++ b/client/src/_components/content/editor.help.js @@ -125,8 +125,7 @@ const explorerHelp = (gotoPage) => {

    * All users have access to high-resolution versions of the images and metadata files. However, only - authenticated users - have access to the original image uploads.

    + authenticated users have access to the original image uploads.

    ; /** @@ -582,6 +581,24 @@ const explorerHelp = (gotoPage) => { ; + const masteredImages = <> +

    Mastered Captures

    +

    Historic and modern capture images must be classified as Mastered (the selected image state) to be used + in image comparison pairs. Since captures contain multiple images versions - including multiple mastered images - + the particular image used in historic and modern comparisons is the last updated mastered image. + To select an image as the selected mastered image, open the editor dialog for that image and click update.

    +

    Mastered images must also meet the following preconditions:

    +
      +
    1. Capture images must be aligned Both capture image must be properly aligned and registered using + an image editing software application or other tool. Explorer has a built-in Alignment tool that allows users + to align two images using homographic transformations. Refer to instructions + in the
    2. +
    3. Capture images must be sorted The historic and modern capture images must be attached to a + historic visit and location (modern visit) respectively, which are associated + with a common station node. +
    4. +
    ; + // index of editor help content return [ { @@ -596,6 +613,10 @@ const explorerHelp = (gotoPage) => { label: 'Handling Images', data: editorImagesHelp, }, + { + label: 'Mastered Captures', + data: masteredImages, + }, { label: 'Metadata Files', data: editorMetadataHelp, diff --git a/client/src/_components/content/explorer.help.js b/client/src/_components/content/explorer.help.js index 024c1c0e..928a135b 100644 --- a/client/src/_components/content/explorer.help.js +++ b/client/src/_components/content/explorer.help.js @@ -81,8 +81,8 @@ const explorerHelp = (gotoPage) => { Search and filter results are also loaded in the viewer.

    The viewer is where

+ } + { + loadedData && +
+
+
+
    +
  • +
  • +
  • +
  • +
+
+ + +
+ +
    +
  • + { + Array.isArray(selectedFeatures) && selectedFeatures.length > 0 && + <> +
  • +
+
+ + + } + +} \ No newline at end of file diff --git a/client/src/_components/editors/options.editor.js b/client/src/_components/editors/options.editor.js index 5e19399e..3fc1080b 100644 --- a/client/src/_components/editors/options.editor.js +++ b/client/src/_components/editors/options.editor.js @@ -33,7 +33,7 @@ const OptionsEditor = ({type='options', onCancel=()=>{}}) => { const [options, setOptions] = React.useState({}); const [selectedIDs, setSelectedIDs] = React.useState({}); const [optionData, setOptionData] = React.useState({}); - const excludedOpts = ['image_states', 'surveyors', 'surveys', 'survey_seasons']; + const excludedOpts = ['image_states', 'surveyors', 'surveys', 'survey_seasons', 'statuses', 'map_objects']; const [loaded, setLoaded] = React.useState(false); // generate unique ID value for form inputs diff --git a/client/src/_components/kml/Stn_1_Sanseverino_2016.kmz b/client/src/_components/kml/Stn_1_Sanseverino_2016.kmz deleted file mode 100644 index 8a9ed4d39ffd93dd723c124fdd14196bfd740654..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 730 zcmWIWW@Zs#U|`??Vg`oW8$2duF)=XwWo2Ms2l7+$ll8K5bFNMa%%5!_aD4t{|Hd2H z$=Oqq=IFd0LHj|4g%7U6JE^->U7d`{})Ulm6Wj-Q(%*`c3Xr{fkmVr*PT*E0nI!2% zOwizSe$mxk-q0%Rme_Pi!}D;)LM7Vee88zJ5qa3x6duCt)2ZxJcug8Q7 zEsqaAobjl@ysh47Lu=T#-*wZ^r|BMDY_#m@597zD>Q~-;(sV6+-Jeq-x8^nHMQ!|l zF)w8{tKNasHytue&Z`cc%Cl*oaHK>~C&TCETJ7&jiG>VXQv!wV3iU0|ZhQVfL~xCF xa6wI_XyyHlH_z$^cryZ%AMOMRN~DY+0t}$ZGr*gb4a8>zLQ^2!4>W>-0RW|$KGgsK diff --git a/client/src/_components/kml/example-2.kml b/client/src/_components/kml/example-2.kml deleted file mode 100644 index 56afabe3..00000000 --- a/client/src/_components/kml/example-2.kml +++ /dev/null @@ -1,85 +0,0 @@ - - - - Untitled Project - - https://earth.google.com/balloon_components/base/1.0.23.0/card_template.kml#main - - - - https://earth.google.com/balloon_components/base/1.0.23.0/card_template.kml#main - - - - - normal - #__managed_style_1619ACC94B22D7EECF31 - - - highlight - #__managed_style_2E9041D96122D7EECF31 - - - - Example Area - Example Area]]> - - -123.260724910576 - 49.99873614610491 - 1719.58595224931 - -4.512370726392674 - 0.5203993399117726 - 35 - 240479.2719009519 - absolute - - #__managed_style_0618FF8D4622D7EECF31 - - - - - -123.0500165453177,50.0903690722585,1030.048414414258 -123.1594324964716,49.89771658426939,436.9553872345922 -122.9041292507114,49.80075169552649,1480.937952077607 -122.5461382289756,49.87532573804571,1659.053332724201 -122.4457621615127,50.04974996754733,1005.115929721128 -122.6927977143789,50.15674705672059,1790.237375595104 -123.0500165453177,50.0903690722585,1030.048414414258 - - - - - - - diff --git a/client/src/_components/menus/editor.menu.js b/client/src/_components/menus/editor.menu.js index 0abde11f..ef9a4502 100644 --- a/client/src/_components/menus/editor.menu.js +++ b/client/src/_components/menus/editor.menu.js @@ -21,7 +21,7 @@ import {getDependentTypes, getModelLabel, isImageType, isCaptureType} from '../. import Button from '../common/button'; import Dropdown from "../common/dropdown"; import {useUser} from "../../_providers/user.provider.client"; -import {genID} from "../../_utils/data.utils.client"; +import {genID, sanitize} from "../../_utils/data.utils.client"; import {createNodeRoute, redirect} from "../../_utils/paths.utils.client"; import Download from "../common/download"; import {useDialog} from "../../_providers/dialog.provider.client"; @@ -62,10 +62,21 @@ const EditorMenu = ({ attached={}, files={}, size= 'lg', - visible=['show', 'edit', 'remove', 'new', 'attach', 'download'], + visible=[ + 'show', + 'edit', + 'remove', + 'new', + 'attach', + 'download', + 'extract_map_features', + 'view_map_features' + ], callback=()=>{}, className='' }) => { + + // dialog provider const dialog = useDialog(); @@ -131,8 +142,6 @@ const EditorMenu = ({ ]) .filter(item => !!item); - if (String(id) === '81234') console.log('>>>', id, metadata, visible) - return
    { @@ -259,6 +268,36 @@ const EditorMenu = ({ /> } + { + // Extract map features from uploaded KMZ file + isAdmin && model === 'map_objects' && id && visible.includes('extract_map_features') && +
  • +
  • + } + { + // View map features for node + model === 'survey_seasons' && id && visible.includes('view_map_features') + && (attached || {}).maps?.some(map => map.data.map_features_id) && +
  • +
  • + } { // Remove node isAdmin && id && metadata && visible.includes('remove') && diff --git a/client/src/_components/menus/header.menu.js b/client/src/_components/menus/header.menu.js index a2db157b..70e01e4e 100644 --- a/client/src/_components/menus/header.menu.js +++ b/client/src/_components/menus/header.menu.js @@ -60,6 +60,7 @@ const HeaderMenu = () => { // generate heading text const headingText = genHeading(); + // expand node metadata to pass to menu const { file_size=0, mimetype='', filename='' } = api.file || {}; let itemMetadata = api.metadata || {}; diff --git a/client/src/_components/menus/viewer.menu.js b/client/src/_components/menus/viewer.menu.js index 38a9e855..bc6c1035 100644 --- a/client/src/_components/menus/viewer.menu.js +++ b/client/src/_components/menus/viewer.menu.js @@ -11,7 +11,8 @@ * * --------- * Revisions - * - 22-07-2023 Added new download selection button. + * - 22-07-2023 Added new download selection button. + * - 23-12-2023 Added new Map Object dialog for KMZ data files */ import React from 'react'; @@ -85,6 +86,12 @@ const ViewerPanelMenu = () => { type: 'projects', label: `Add new ${getModelLabel('projects')}`, callback: () => {dialog.setCurrent({dialogID: 'new_project'})} + }, + { + icon: 'maps', + type: 'map_objects', + label: `Add new ${getModelLabel('map_objects')}`, + callback: () => {dialog.setCurrent({dialogID: 'new_map_object'})} }]} /> } diff --git a/client/src/_components/navigator/filter.navigator.js b/client/src/_components/navigator/filter.navigator.js index b40ff739..b2acd8af 100644 --- a/client/src/_components/navigator/filter.navigator.js +++ b/client/src/_components/navigator/filter.navigator.js @@ -1,9 +1,18 @@ /*! * MLE.Client.Components.Navigator.Filter * File: filter.navigator.js - * Copyright(c) 2022 Runtime Software Development Inc. + * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed + * + * ---------- + * Description + * + * Filter navigator component. Sets filtered stations to appear on map tool. + * + * --------- + * Revisions + */ import React from 'react'; @@ -88,7 +97,7 @@ function FilterNavigator() { loader={_loader} schema={genSchema({ view:'filterNavigation', model:'stations'})} onReset={()=>{ - setFilterData({}) + setFilterData({}); }} onCancel={() => {dialog.cancel()}} onChange={onChange} diff --git a/client/src/_components/navigator/map.navigator.js b/client/src/_components/navigator/map.navigator.js index d4fcd3d2..49fcf289 100644 --- a/client/src/_components/navigator/map.navigator.js +++ b/client/src/_components/navigator/map.navigator.js @@ -13,7 +13,7 @@ * * --------- * Revisions - * - 16-09-2023 Converted log/lat display to DMS. + */ import React from 'react'; @@ -26,10 +26,23 @@ import {debounce, useWindowSize} from '../../_utils/events.utils.client'; import Loading from "../common/loading"; import {getPref, setPref} from "../../_services/session.services.client"; import {useNav} from "../../_providers/nav.provider.client"; -import { getMarker, baseLayers } from "../tools/map.tools"; +import {getMarker, getBaseLayers, setFeaturePopup} from "../tools/map.tools"; import Button from "../common/button"; import 'leaflet-kml/L.KML.js'; import {convertCoordDMS} from "../../_utils/data.utils.client"; +import {useDialog} from "../../_providers/dialog.provider.client"; + + +// change default marker icon +delete L.Icon.Default.prototype._getIconUrl; +const iconSVG = getMarker(1); + +L.Icon.Default.mergeOptions({ + iconRetinaUrl: 'data:image/svg+xml;base64,' + btoa(iconSVG), + iconUrl: 'data:image/svg+xml;base64,' + btoa(iconSVG), + shadowUrl: null, + shadowSize: [0, 0] +}); /** * Page height offset @@ -62,6 +75,7 @@ function MapNavigator({ filter, hidden }) { const router = useRouter(); const api = useData(); const nav = useNav(); + const dialog = useDialog(); // mounted component flag const _isMounted = React.useRef(false); @@ -79,19 +93,22 @@ function MapNavigator({ filter, hidden }) { const [center, setCenter] = React.useState([lat, lng]); const [zoom, setZoom] = React.useState(4); const [clustered, setClustered] = React.useState(true); + const [showMarkers, setShowMarkers] = React.useState(true); const [stale, setStale] = React.useState(true); // window dimensions const [winWidth, winHeight] = useWindowSize(); - // leaflet map object + // leaflet map objects (references) const mapPane = React.useRef(null); const mapObj = React.useRef(null); - const layerGrp = React.useRef(null); + const stationMarkers = React.useRef(null); + const mapFeatures = React.useRef(null); - // refresh navigator data + // refresh map tiles and data const _handleRefresh = () => { - nav.refresh(); + const baseLayers = getBaseLayers(L); + baseLayers[selectedBaseLayer].addTo(mapObj.current); setStale(true); }; @@ -100,19 +117,40 @@ function MapNavigator({ filter, hidden }) { setClustered(!clustered) }; + // toggle markers display + const _handleMarkers = () => { + setShowMarkers(!showMarkers) + }; + + // select map features overlay + const _handleMapFeatures = () => { + dialog.setCurrent({ + dialogID: 'map_features', + callback: (data) => { + nav.setOverlay(data) + dialog.cancel(); + } + }); + }; + // request station(s) view in selected cluster // - if single station, go to that station info page // - for multiple station, go to filter page for ids - const loadView = React.useCallback((ids = []) => { + const loadStations = React.useCallback((ids = []) => { ids.length === 1 ? router.update(createNodeRoute('stations', 'show', ids[0])) : router.update(createRoute('/filter', { ids: ids })); }, [router]); + // show metadata for item in view panel + const loadViewPane = React.useCallback((id, model) => { + router.update(createNodeRoute(model, 'show', id)); + }, [router]); + // cluster station locations for n > 1 const getClusterMarkers = React.useCallback((currentIDs) => { - if (!currentIDs) return; + if (!currentIDs || !showMarkers) return; // apply user-defined filter const _applyFilter = (station) => { @@ -254,7 +292,7 @@ function MapNavigator({ filter, hidden }) { .on('click', () => { // clicking on marker loads filter results in data pane debounce(() => { - loadView( + loadStations( cluster.stations.map(station => {return station.nodes_id}) ); // recenter map @@ -270,11 +308,11 @@ function MapNavigator({ filter, hidden }) { .on('mouseover', function () { // show station name and location on clusters where n < 15 this.bindTooltip(`${ - n <= 15 + n <= 15 ? cluster.stations.map(station => { // convert DMS to degrees / minutes / seconds return `${station.name} [${convertCoordDMS(station.lat)}, ${convertCoordDMS(station.lng)}]` - }).join('
    ') + }).join('
    ') : `Cluster (n = ${n})
    Lat: ${convertCoordDMS(centroid[0])}
    Lng: ${convertCoordDMS(centroid[1])}` @@ -289,7 +327,7 @@ function MapNavigator({ filter, hidden }) { }, o); return o; }, []); - }, [nav, mapObj, loadView, zoom, clustered]); + }, [nav, mapObj, loadStations, zoom, clustered, showMarkers]); /** * Reset map view to new center coordinate and zoom level. @@ -301,7 +339,7 @@ function MapNavigator({ filter, hidden }) { */ const reset = React.useCallback((coord, zoomLevel) => { - if (coord && zoomLevel && layerGrp.current) { + if (coord && zoomLevel && stationMarkers.current) { setCenter(coord); setZoom(zoomLevel); } @@ -310,12 +348,60 @@ function MapNavigator({ filter, hidden }) { // assign selected nodes on map React.useEffect(() => { _isMounted.current = true; - if (_isMounted.current && mapObj.current && layerGrp.current) { - layerGrp.current.clearLayers(); - layerGrp.current = L.layerGroup(getClusterMarkers(currentFilter)).addTo(mapObj.current); + if (_isMounted.current && mapObj.current && stationMarkers.current) { + stationMarkers.current.clearLayers(); + stationMarkers.current = L.layerGroup(getClusterMarkers(currentFilter)).addTo(mapObj.current); + } + return () => {_isMounted.current = false;} + }, [getClusterMarkers, currentFilter, filter, showMarkers, zoom, center]) + + // assign selected nodes on map + React.useEffect(() => { + + const geojsonMarkerOptions = { + radius: 8, + fillColor: "skyblue", + color: "#FFF", + weight: 2, + opacity: 1, + fillOpacity: 0.5 + }; + + _isMounted.current = true; + + if (_isMounted.current && mapObj.current && mapFeatures.current) { + // clear current map features + mapFeatures.current.clearLayers(); + // include selected map features as layers added to group (geoJSON) + if (Array.isArray(nav.overlay) && nav.overlay.length > 0) { + nav.overlay.forEach(({id, geoJSON, selected}) => { + let selectedLayer; + const featureLayer = L.geoJSON(geoJSON, { + onEachFeature: (feature, layer)=>{ + selectedLayer = layer; + setFeaturePopup(id, feature, layer, loadViewPane); + }, + pointToLayer: function (feature, latlng) { + return L.circleMarker(latlng, geojsonMarkerOptions); + } + }); + mapFeatures.current.addLayer(featureLayer); + // show pop-up of selected feature + if (!!selected) { + selectedLayer.openPopup(); + const bounds = featureLayer.getBounds(); + mapObj.current.fitBounds(bounds); + } + }); + // For multiple selected map features: adjust map bounds to show group + if (nav.overlay.length > 1) { + const bounds = mapFeatures.current.getBounds(); + mapObj.current.fitBounds(bounds); + } + } } return () => {_isMounted.current = false;} - }, [getClusterMarkers, currentFilter, filter, zoom, center]) + }, [nav.overlay, loadViewPane]) // API data change detected: recenter map to selected coordinate (if available) // - if on station info page, center and zoom to location on the map @@ -333,7 +419,7 @@ function MapNavigator({ filter, hidden }) { } } return () => {_isMounted.current = false;} - }, [api, setClustered]) + }, [api.location, setClustered]) // Redraw map if container was resized. React.useEffect(() => { @@ -372,6 +458,9 @@ function MapNavigator({ filter, hidden }) { ? center : [center.lat || '', center.lng || '']; + // retrieve base tile layers + const baseLayers = getBaseLayers(L); + // initialize map with DOM container and initial coordinates mapObj.current = L.map(domNode, { center: [lat, lng], @@ -385,14 +474,11 @@ function MapNavigator({ filter, hidden }) { // reset saved map centre coordinate / zoom level reset(center, zoom); - // add marker layer to map - layerGrp.current = L.layerGroup(getClusterMarkers(currentFilter)).addTo(mapObj.current); + // add station marker layer group to map + stationMarkers.current = L.layerGroup(getClusterMarkers(currentFilter)).addTo(mapObj.current); - // Include any kml overlay - // if (nav.overlay) { - // const track = new L.KML(nav.overlay); - // mapObj.current.addLayer(track); - // } + // add map features layer group to map + mapFeatures.current = new L.FeatureGroup().addTo(mapObj.current); // add layers to leaflet tools L.control.layers(baseLayers).addTo(mapObj.current); @@ -422,7 +508,7 @@ function MapNavigator({ filter, hidden }) { } }, [ - api, + api.loaded, nav, currentFilter, center, @@ -467,17 +553,33 @@ function MapNavigator({ filter, hidden }) { }} /> {nav.toggle &&
    + {/**/}
    }
diff --git a/client/src/_components/navigator/map/base.map.js b/client/src/_components/navigator/map/base.map.js new file mode 100644 index 00000000..f07c6f95 --- /dev/null +++ b/client/src/_components/navigator/map/base.map.js @@ -0,0 +1,161 @@ +/*! + * MLE.Client.Components.Navigator.Map.Base + * File: default.canvas.alignment.js + * Copyright(c) 2023 Runtime Software Development Inc. + * Version 2.0 + * MIT Licensed + * + * ---------- + * Description + * + * Base Leaflet map component forMap Navigator. + * + * --------- + * Revisions + * - + */ + +import React, {forwardRef, useRef, useImperativeHandle, useEffect} from 'react'; + +/** + * Leaflet Map Component + */ + +const LeafletMap = forwardRef(function Map(props, ref) { + + const mapRef = useRef(null); + const {onKeyDown, onKeyUp} = props || {}; + + // add event listener for key events + useEffect(()=>{ + if (onKeyDown && onKeyDown) { + document.addEventListener('keydown', onKeyDown); + document.addEventListener('keyup', onKeyUp); + return () => { + document.removeEventListener("keydown", onKeyDown); + document.removeEventListener("keyup", onKeyUp); + }; + } + }, [onKeyDown, onKeyUp]) + + useImperativeHandle(ref, () => { + const context = mapRef.current.getContext('2d', { willReadFrequently: true }); + return { + load: (image) => { + + if (!image) return; + + // load image data to image canvas + mapRef.current.width = image.width; + mapRef.current.height = image.height; + + // draw image to canvas + if (image instanceof HTMLImageElement) + context.drawImage(image, 0, 0, image.width, image.height); + else context.putImageData(image, 0, 0); + }, + putImageData: (imageData, dims) => { + + /** + * Loads image data to canvas + * Note: Image size sets new data canvas dimensions + * + * @public + */ + + // destructure dimensions + const {x, y, w, h} = dims || {}; + + // put image to canvas + context.putImageData(imageData, x || 0, y || 0, 0, 0, w || imageData.width, h || imageData.height); + }, + draw: (image, dims) => { + + /** + * Redraws image data to canvas + * Note: Scale sets new data canvas dimensions + * - dx + * The x-axis coordinate in the destination canvas at which to place the top-left + * corner of the source image. + * - dy + * The y-axis coordinate in the destination canvas at which to place the top-left + * corner of the source image. + * - dWidth + * The width to draw the image in the destination canvas. This allows scaling of the + * drawn image. If not specified, the image is not scaled in width when drawn. + * - dHeight + * The height to draw the image in the destination canvas. This allows scaling of + * the drawn image. If not specified, the image is not scaled in height when drawn. + * + * @public + */ + + if (!image) return; + + // clear, resize and render image data to canvas + const {source, view} = dims || {}; + context.clearRect(0, 0, mapRef.current.width, mapRef.current.height); + // set canvas dimensions + // canvasRef.current.width = view && view.w || canvasRef.current.width; + // canvasRef.current.height = view && view.h || canvasRef.current.height; + // draw source image to canvas + context.drawImage( + image, + source && source.x || 0, + source && source.y || 0, + source && source.w || image.width, + source && source.h || image.height, + view && view.x || 0, + view && view.y || 0, + view && view.w, + view && view.h + ); + }, + canvas: () => { + return mapRef.current; + }, + context: () => { + return context; + }, + clear: () => { + context.clearRect(0, 0, mapRef.current.width, mapRef.current.height); + }, + dims: () => { + return {w: mapRef.current.width, h: mapRef.current.height}; + }, + bounds: () => { + const rect = mapRef.current.getBoundingClientRect(); + return { + top: rect.top, + left: rect.left, + width: rect.width, + height: rect.height + } + }, + data: () => { + return mapRef.current.toDataURL('image/jpeg', 1.0); + }, + getImageData: () => { + return context.getImageData(0, 0, mapRef.current.width, mapRef.current.height); + }, + blob: (image, type, quality, callback) => { + // if image data is provided, load to canvas and convert to blob + if (image) { + if (image instanceof HTMLImageElement) + context.drawImage(image, 0, 0, image.width, image.height); + else context.putImageData(image, 0, 0); + } + + }, + alpha: (alpha) => { + // set canvas opacity + mapRef.current.style.opacity = alpha; + } + }; + }, []); + + return
; + +}); + +export default LeafletMap; diff --git a/client/src/_components/navigator/tree.navigator.js b/client/src/_components/navigator/tree.navigator.js index 1974e787..616da6df 100644 --- a/client/src/_components/navigator/tree.navigator.js +++ b/client/src/_components/navigator/tree.navigator.js @@ -1,9 +1,17 @@ /*! * MLE.Client.Components.Navigator.Tree * File: tree.navigator.js - * Copyright(c) 2022 Runtime Software Development Inc. + * Copyright(c) 2023 Runtime Software Development Inc. * Version 2.0 * MIT Licensed + * + * ---------- + * Description + * + * Tree (list) navigator component. Expandable node tree menu. + * + * --------- + * Revisions */ import React from 'react' diff --git a/client/src/_components/selectors/dialog.selector.js b/client/src/_components/selectors/dialog.selector.js index e97778c0..2e0ea097 100644 --- a/client/src/_components/selectors/dialog.selector.js +++ b/client/src/_components/selectors/dialog.selector.js @@ -12,7 +12,8 @@ * * --------- * Revisions - * - 22-07-2023 Include basic node data to include create and last modified dates. + * - 22-07-2023 Include basic node data to include create and last modified dates. + * - 23-12-2023 Added new Map Object dialog for KMZ data files */ import React from 'react'; @@ -33,9 +34,11 @@ import Button from "../common/button"; import {useDialog} from "../../_providers/dialog.provider.client"; import {useData} from "../../_providers/data.provider.client"; import {useNav} from "../../_providers/nav.provider.client"; -import {LoaderTool} from "../toolkit/tools/loader.toolkit"; +import {LoaderTool} from "../alignment/tools/loader.alignment"; import Accordion from "../common/accordion"; import Image from "../common/image"; +import MapSelector from "./map.selector"; +import {MapEditor} from "../editors/map.editor"; /** * Dialog view for selecting forms/content to display in dialog popup components. @@ -80,8 +83,8 @@ const DialogSelector = () => { const {group_type = '' } = metadata || {}; // handle callback and data refresh - const _handleCallback = () => { - if (callback) callback(); + const _handleCallback = (data) => { + if (callback) callback(data); dialog.clear(); } @@ -207,6 +210,9 @@ const DialogSelector = () => { filter: , + map_features: + + , move: , @@ -308,6 +314,7 @@ const DialogSelector = () => { route={createNodeRoute('surveyors', 'new')} schema={genSchema({view: 'new', model: 'surveyors', user: user})} onRefresh={_handleRefresh} + onCancel={_handleCancel} callback={(error, model, id) => { error ? _handleCallback() : redirect(createNodeRoute(model, 'show', id)); }} @@ -325,11 +332,46 @@ const DialogSelector = () => { route={createNodeRoute('projects', 'new')} schema={genSchema({view: 'new', model: 'projects', user: user})} onRefresh={_handleRefresh} + onCancel={_handleCancel} + callback={(error, model, id) => { + error ? _handleCallback() : redirect(createNodeRoute(model, 'show', id)); + }} + /> + , + new_map_object: 0 ? 'hidden' : ''} + > + { error ? _handleCallback() : redirect(createNodeRoute(model, 'show', id)); }} /> , + extract_map_features: 0 ? 'hidden' : ''} + > +

+ Use this form to extract map features from a KMZ file. +

+ +
, image:
@@ -340,7 +382,7 @@ const DialogSelector = () => { onClick={_handleCancel} />
-
, + }; // create add new dependents dialog popups for requested model diff --git a/client/src/_components/selectors/file.selector.js b/client/src/_components/selectors/file.selector.js index 2f0e9adf..80baece4 100644 --- a/client/src/_components/selectors/file.selector.js +++ b/client/src/_components/selectors/file.selector.js @@ -28,7 +28,7 @@ const FileSelector = ({ data, scale='thumb' }) => { // destructure file data const {label='', file={}, url={}, metadata={} } = data || {}; - const {id='', owner_id='', file_type='', filename='', file_size='', mimetype='' } = file || {}; + const {id='', file_type='', filename='', file_size='', mimetype='' } = file || {}; let itemMetadata = metadata // include file metadata in details itemMetadata.filename = filename; @@ -61,7 +61,6 @@ const FileSelector = ({ data, scale='thumb' }) => { * handle download response * - sets image metadata in provider to load in dialog view * - * @param {Event} e */ const _handleDownload = () => {} diff --git a/client/src/_components/selectors/input.selector.js b/client/src/_components/selectors/input.selector.js index 15136335..b4023554 100644 --- a/client/src/_components/selectors/input.selector.js +++ b/client/src/_components/selectors/input.selector.js @@ -18,7 +18,6 @@ import React from 'react'; import 'flatpickr/dist/themes/material_green.css'; -import {sorter} from '../../_utils/data.utils.client'; import Icon from '../common/icon'; import Message, {UserMessage} from '../common/message'; import MultiSelect from '../common/multiselect'; @@ -27,6 +26,8 @@ import {AttachedMetadataEditor} from "../editors/attached.editor"; import {DependentsEditor} from "../editors/dependents.editor"; import {ComparisonEditor} from "../editors/comparison.editor"; import Coord from "../common/coord"; +import SingleSelect from "../common/singleselect"; +import MapSelector from "./map.selector"; /** * No operation. @@ -85,7 +86,14 @@ export const InputSelector = ({ const [highlight, setHighlight] = React.useState(false); // define label-less inputs - const noLabel = [ 'hidden', 'file', 'dependentEditor', 'compareSelector', 'attachedMetadataEditor']; + const noLabel = [ + 'hidden', + 'file', + 'dependentEditor', + 'compareSelector', + 'attachedMetadataEditor', + 'generateMapFeatures' + ]; // append unique ID value for input id = `${name}_${id}`; @@ -149,6 +157,20 @@ export const InputSelector = ({ />; }, + json: () => { + return