From 9b10a987f3f044657dad09ba932056d73cb60509 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Fri, 21 Oct 2022 17:23:32 -0700 Subject: [PATCH] Add status change support in mindmap editor --- .../src/classes/action/capability/index.ts | 6 +- .../editor/src/classes/model/editor/index.ts | 6 +- .../src/classes/model/map-info/index.ts | 32 ++ .../editor/src/components/app-bar/index.tsx | 295 +++++++++--------- packages/editor/src/components/index.tsx | 43 ++- packages/editor/src/index.tsx | 5 + .../playground/map-render/js/MapInfoImpl.ts | 66 ++++ .../test/playground/map-render/js/editor.tsx | 6 +- .../playground/map-render/js/editorlocked.tsx | 9 +- .../playground/map-render/js/showcase.tsx | 6 +- .../playground/map-render/js/viewmode.tsx | 6 +- .../editor/test/unit/toolbar/toolbar.test.tsx | 10 +- packages/webapp/images/logo-medium.svg | 2 +- .../webapp/src/classes/app-config/index.ts | 18 ++ .../client/cache-decorator-client/index.ts | 4 + packages/webapp/src/classes/client/index.ts | 2 + .../src/classes/client/mock-client/index.ts | 23 +- .../src/classes/client/rest-client/index.ts | 19 ++ .../src/classes/editor-map-info/index.ts | 77 +++++ .../src/components/editor-page/index.tsx | 35 ++- packages/webapp/src/redux/clientSlice.ts | 18 ++ packages/webapp/webpack.dev.js | 1 - 22 files changed, 492 insertions(+), 197 deletions(-) create mode 100644 packages/editor/src/classes/model/map-info/index.ts create mode 100644 packages/editor/test/playground/map-render/js/MapInfoImpl.ts create mode 100644 packages/webapp/src/classes/editor-map-info/index.ts diff --git a/packages/editor/src/classes/action/capability/index.ts b/packages/editor/src/classes/action/capability/index.ts index 607b3cb8..d34c4609 100644 --- a/packages/editor/src/classes/action/capability/index.ts +++ b/packages/editor/src/classes/action/capability/index.ts @@ -181,6 +181,10 @@ const ActionConfigByRenderMode: Record = { hidden: ['viewonly', 'edition-viewer', 'edition-editor', 'edition-owner'], }, }, - starred: undefined, + starred: { + desktop: { + hidden: ['showcase', 'viewonly'], + }, + }, }; export default Capability; diff --git a/packages/editor/src/classes/model/editor/index.ts b/packages/editor/src/classes/model/editor/index.ts index 5eacc371..d0f82ce2 100644 --- a/packages/editor/src/classes/model/editor/index.ts +++ b/packages/editor/src/classes/model/editor/index.ts @@ -48,16 +48,16 @@ class Editor { this.component.loadMap(mapId); } - registerEvents(setToolbarsRerenderSwitch: (timestamp: number) => void, capability: Capability) { + registerEvents(canvasUpdate: (timestamp: number) => void, capability: Capability) { const desiger = this.component.getDesigner(); const onNodeBlurHandler = () => { if (!desiger.getModel().selectedTopic()) { - setToolbarsRerenderSwitch(Date.now()); + canvasUpdate(Date.now()); } }; const onNodeFocusHandler = () => { - setToolbarsRerenderSwitch(Date.now()); + canvasUpdate(Date.now()); }; // Register events ... diff --git a/packages/editor/src/classes/model/map-info/index.ts b/packages/editor/src/classes/model/map-info/index.ts new file mode 100644 index 00000000..36063c27 --- /dev/null +++ b/packages/editor/src/classes/model/map-info/index.ts @@ -0,0 +1,32 @@ +/* + * Copyright [2021] [wisemapping] + * + * Licensed under WiseMapping Public License, Version 1.0 (the "License"). + * It is basically the Apache License, Version 2.0 (the "License") plus the + * "powered by wisemapping" text requirement on every single page; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the license at + * + * http://www.wisemapping.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +interface MapInfo { + isStarred(): Promise; + updateStarred(value: boolean): Promise; + + getTitle(): string; + setTitle(value: string): void; + + isLocked(): boolean; + getLockedMessage(): string; + + getZoom(): number; + + getId(): string; +} +export default MapInfo; diff --git a/packages/editor/src/components/app-bar/index.tsx b/packages/editor/src/components/app-bar/index.tsx index e0d5c11f..0d121875 100644 --- a/packages/editor/src/components/app-bar/index.tsx +++ b/packages/editor/src/components/app-bar/index.tsx @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import MaterialToolbar from '@mui/material/Toolbar'; import MaterialAppBar from '@mui/material/AppBar'; import { ToolbarMenuItem } from '../toolbar'; @@ -40,159 +40,168 @@ import Button from '@mui/material/Button'; import LogoTextBlackSvg from '../../../images/logo-text-black.svg'; import IconButton from '@mui/material/IconButton'; import { ToolbarActionType } from '../toolbar/ToolbarActionType'; +import MapInfo from '../../classes/model/map-info'; interface AppBarProps { model: Editor; - mapTitle: string; + mapInfo: MapInfo; capability: Capability; onAction?: (type: ToolbarActionType) => void; accountConfig?; } +const appBarDivisor = { + render: () => , +}; -const AppBar = ({ model, mapTitle, capability, onAction, accountConfig }: AppBarProps) => { - const appBarDivisor = { - render: () => , +const AppBar = ({ model, mapInfo, capability, onAction, accountConfig }: AppBarProps) => { + const [isStarred, setStarred] = useState(undefined); + + const handleStarredOnClick = () => { + const newStatus = !isStarred; + mapInfo.updateStarred(newStatus).then(() => setStarred(newStatus)); }; - const buildConfig = ( - model: Editor, - mapTitle: string, - capability: Capability, - onAction: (type: ToolbarActionType) => void, - accountConfig, - ): ActionConfig[] => { - return [ - { - icon: , - tooltip: $msg('BACK_TO_MAP_LIST'), - onClick: () => history.back(), - }, - { - render: () => , - }, - { - render: () => ( - - - {mapTitle} - - - ), - }, - null, - { - render: () => ( - , - tooltip: $msg('UNDO') + ' (' + $msg('CTRL') + ' + Z)', - onClick: () => designer.undo(), - }} - disabledCondition={(event) => event.undoSteps > 0} - > - ), - visible: !capability.isHidden('undo-changes'), - disabled: () => !model?.isMapLoadded(), - }, - { - render: () => ( - , - tooltip: $msg('REDO') + ' (' + $msg('CTRL') + ' + Shift + Z)', - onClick: () => designer.redo(), - }} - disabledCondition={(event) => event.redoSteps > 0} - > - ), - visible: !capability.isHidden('redo-changes'), - disabled: () => !model?.isMapLoadded(), - }, - null, - { - icon: , - tooltip: $msg('SAVE') + ' (' + $msg('CTRL') + ' + S)', - onClick: () => { - model.save(true); - }, - visible: !capability.isHidden('save'), - disabled: () => !model?.isMapLoadded(), - }, - { - icon: , - tooltip: $msg('HISTORY'), - onClick: () => onAction('history'), - visible: !capability.isHidden('history'), - }, - appBarDivisor, - { - tooltip: $msg('SAVE') + ' (' + $msg('CTRL') + ' + S)', - render: () => ( - {}}> - - - ), - visible: !capability.isHidden('starred'), - disabled: () => !model?.isMapLoadded(), - }, - { - icon: , - tooltip: $msg('EXPORT'), - onClick: () => onAction('export'), - visible: !capability.isHidden('export'), - }, - { - icon: , - tooltip: $msg('PRINT'), - onClick: () => onAction('print'), - visible: !capability.isHidden('print'), - }, - { - icon: , - onClick: () => onAction('info'), - tooltip: $msg('MAP_INFO'), - visible: !capability.isHidden('info'), - }, - { - icon: , - onClick: () => onAction('publish'), - tooltip: $msg('PUBLISH'), - visible: !capability.isHidden('publish'), - }, - { - render: () => ( - - ), - visible: !capability.isHidden('share'), - }, - { - render: () => accountConfig, - visible: !capability.isHidden('account'), - }, - { - render: () => ( - - ), - visible: !capability.isHidden('sign-up'), - }, - ]; - }; + useEffect(() => { + mapInfo + .isStarred() + .then((value) => setStarred(value)) + .catch((e) => { + console.error(`Unexpected error loading starred status-> ${e}`); + }); + }, []); + + console.log(``); + const config: ActionConfig[] = [ + { + icon: , + tooltip: $msg('BACK_TO_MAP_LIST'), + onClick: () => history.back(), + }, + { + render: () => , + }, + { + render: () => ( + + + {mapInfo.getTitle()} + + + ), + }, + null, + { + render: () => ( + , + tooltip: $msg('UNDO') + ' (' + $msg('CTRL') + ' + Z)', + onClick: () => designer.undo(), + }} + disabledCondition={(event) => event.undoSteps > 0} + /> + ), + visible: !capability.isHidden('undo-changes'), + disabled: () => !model?.isMapLoadded(), + }, + { + render: () => ( + , + tooltip: $msg('REDO') + ' (' + $msg('CTRL') + ' + Shift + Z)', + onClick: () => designer.redo(), + }} + disabledCondition={(event) => event.redoSteps > 0} + /> + ), + visible: !capability.isHidden('redo-changes'), + disabled: () => !model?.isMapLoadded(), + }, + null, + { + icon: , + tooltip: $msg('SAVE') + ' (' + $msg('CTRL') + ' + S)', + onClick: () => { + model.save(true); + }, + visible: !capability.isHidden('save'), + disabled: () => !model?.isMapLoadded(), + }, + { + icon: , + tooltip: $msg('HISTORY'), + onClick: () => onAction('history'), + visible: !capability.isHidden('history'), + }, + appBarDivisor, + { + tooltip: $msg('STARRED'), + render: () => ( + + + + ), + + visible: !capability.isHidden('starred'), + disabled: () => isStarred !== undefined, + }, + { + icon: , + tooltip: $msg('EXPORT'), + onClick: () => onAction('export'), + visible: !capability.isHidden('export'), + }, + { + icon: , + tooltip: $msg('PRINT'), + onClick: () => onAction('print'), + visible: !capability.isHidden('print'), + }, + { + icon: , + onClick: () => onAction('info'), + tooltip: $msg('MAP_INFO'), + visible: !capability.isHidden('info'), + }, + { + icon: , + onClick: () => onAction('publish'), + tooltip: $msg('PUBLISH'), + visible: !capability.isHidden('publish'), + }, + { + render: () => ( + + ), + visible: !capability.isHidden('share'), + }, + { + render: () => accountConfig, + visible: !capability.isHidden('account'), + }, + { + render: () => ( + + ), + visible: !capability.isHidden('sign-up'), + }, + ]; - const config = buildConfig(model, mapTitle, capability, onAction, accountConfig); return ( void; @@ -62,25 +59,24 @@ type EditorProps = { }; const Editor = ({ - mapId, + mapInfo, options, persistenceManager, onAction, theme, accountConfiguration, }: EditorProps) => { - const [model, setModel]: [Model | undefined, Function] = useState(); + const [model, setModel] = useState(); + const [canvasUpdate, setCanvasUpdate] = useState(); const editorTheme: Theme = theme ? theme : defaultEditorTheme; - const [toolbarsRerenderSwitch, setToolbarsRerenderSwitch] = useState(0); - const [popoverOpen, popoverTarget, widgetManager] = DefaultWidgetManager.create(); - const capability = new Capability(options.mode, options.locked); + const capability = new Capability(options.mode, mapInfo.isLocked()); const mindplotRef = useCallback((component: MindplotWebComponent) => { // Initialized model ... const model = new Model(component); - model.loadMindmap(mapId, persistenceManager, widgetManager); - model.registerEvents(setToolbarsRerenderSwitch, capability); + model.loadMindmap(mapInfo.getId(), persistenceManager, widgetManager); + model.registerEvents(setCanvasUpdate, capability); setModel(model); }, []); @@ -101,7 +97,7 @@ const Editor = ({ {!capability.isHidden('edition-toolbar') && model?.isMapLoadded() && ( - + )} + + /> + /> - + + message={mapInfo.isLocked() ? mapInfo.getLockedMessage() : ''} + /> ); diff --git a/packages/editor/src/index.tsx b/packages/editor/src/index.tsx index ea6c11da..5bade7f6 100644 --- a/packages/editor/src/index.tsx +++ b/packages/editor/src/index.tsx @@ -34,7 +34,10 @@ import { Importer, TextImporterFactory, } from '@wisemapping/mindplot'; + import Editor from './components'; +import { EditorOptions } from './components'; +import MapInfo from './classes/model/map-info'; declare global { // used in mindplot @@ -65,6 +68,8 @@ export { Exporter, Importer, TextImporterFactory, + EditorOptions, + MapInfo, }; export default Editor; diff --git a/packages/editor/test/playground/map-render/js/MapInfoImpl.ts b/packages/editor/test/playground/map-render/js/MapInfoImpl.ts new file mode 100644 index 00000000..1181c22e --- /dev/null +++ b/packages/editor/test/playground/map-render/js/MapInfoImpl.ts @@ -0,0 +1,66 @@ +/* + * Copyright [2021] [wisemapping] + * + * Licensed under WiseMapping Public License, Version 1.0 (the "License"). + * It is basically the Apache License, Version 2.0 (the "License") plus the + * "powered by wisemapping" text requirement on every single page; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the license at + * + * http://www.wisemapping.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { MapInfo } from '../../../../src'; + +class MapInfoImpl implements MapInfo { + private id: string; + private title: string; + private locked: boolean; + private starred: boolean; + + constructor(id: string, title: string, locked: boolean) { + this.id = id; + this.title = title; + this.locked = locked; + this.starred = true; + } + + isStarred(): Promise { + return Promise.resolve(this.starred); + } + + updateStarred(value: boolean): Promise { + this.starred = value; + return Promise.resolve(); + } + + getTitle(): string { + return this.title; + } + + setTitle(value: string): void { + throw this.title; + } + + isLocked(): boolean { + return this.locked; + } + + getLockedMessage(): string { + return 'Map Is Locked !'; + } + + getZoom(): number { + return 0.8; + } + + getId(): string { + return this.id; + } +} +export default MapInfoImpl; diff --git a/packages/editor/test/playground/map-render/js/editor.tsx b/packages/editor/test/playground/map-render/js/editor.tsx index 4dc1037c..1cfdb8a2 100644 --- a/packages/editor/test/playground/map-render/js/editor.tsx +++ b/packages/editor/test/playground/map-render/js/editor.tsx @@ -19,6 +19,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import Editor, { EditorOptions } from '../../../../src/index'; import { LocalStorageManager, Designer } from '@wisemapping/mindplot'; +import MapInfoImpl from './MapInfoImpl'; const initialization = (designer: Designer) => { designer.addEvent('loadSuccess', () => { @@ -32,9 +33,6 @@ const initialization = (designer: Designer) => { const persistence = new LocalStorageManager('samples/{id}.wxml', false, false); const mapId = 'welcome'; const options: EditorOptions = { - zoom: 0.8, - locked: false, - mapTitle: 'Develop WiseMapping', mode: 'edition-owner', locale: 'en', enableKeyboardEvents: true, @@ -42,7 +40,7 @@ const options: EditorOptions = { ReactDOM.render( console.log('action called:', action)} diff --git a/packages/editor/test/playground/map-render/js/editorlocked.tsx b/packages/editor/test/playground/map-render/js/editorlocked.tsx index ab4299e9..b1890ba5 100644 --- a/packages/editor/test/playground/map-render/js/editorlocked.tsx +++ b/packages/editor/test/playground/map-render/js/editorlocked.tsx @@ -19,6 +19,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import Editor, { EditorOptions } from '../../../../src/index'; import { LocalStorageManager, Designer } from '@wisemapping/mindplot'; +import MapInfoImpl from './MapInfoImpl'; const initialization = (designer: Designer) => { designer.addEvent('loadSuccess', () => { @@ -30,20 +31,16 @@ const initialization = (designer: Designer) => { }; const persistence = new LocalStorageManager('samples/{id}.wxml', false, false); -const mapId = 'welcome'; const options: EditorOptions = { - zoom: 0.8, - locked: true, - lockedMsg: 'Blockeado', - mapTitle: 'Develop WiseMapping', mode: 'edition-editor', locale: 'en', enableKeyboardEvents: true, }; +const mapInfo = new MapInfoImpl('welcome', 'Develop WiseMapping', true); ReactDOM.render( console.log('action called:', action)} diff --git a/packages/editor/test/playground/map-render/js/showcase.tsx b/packages/editor/test/playground/map-render/js/showcase.tsx index acd5de82..b5b32f6d 100644 --- a/packages/editor/test/playground/map-render/js/showcase.tsx +++ b/packages/editor/test/playground/map-render/js/showcase.tsx @@ -19,6 +19,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import Editor, { EditorOptions } from '../../../../src/index'; import { LocalStorageManager, Designer } from '@wisemapping/mindplot'; +import MapInfoImpl from './MapInfoImpl'; const initialization = (designer: Designer) => { designer.addEvent('loadSuccess', () => { @@ -32,9 +33,6 @@ const initialization = (designer: Designer) => { const persistence = new LocalStorageManager('samples/{id}.wxml', false, false); const mapId = 'welcome'; const options: EditorOptions = { - zoom: 0.8, - locked: false, - mapTitle: 'Develop WiseMapping', mode: 'showcase', locale: 'en', enableKeyboardEvents: true, @@ -42,7 +40,7 @@ const options: EditorOptions = { ReactDOM.render( console.log('action called:', action)} diff --git a/packages/editor/test/playground/map-render/js/viewmode.tsx b/packages/editor/test/playground/map-render/js/viewmode.tsx index bd338610..c0ad3b0f 100644 --- a/packages/editor/test/playground/map-render/js/viewmode.tsx +++ b/packages/editor/test/playground/map-render/js/viewmode.tsx @@ -3,6 +3,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import Editor, { EditorOptions } from '../../../../src/index'; import { LocalStorageManager, Designer } from '@wisemapping/mindplot'; +import MapInfoImpl from './MapInfoImpl'; const initialization = (designer: Designer) => { designer.addEvent('loadSuccess', () => { @@ -32,9 +33,6 @@ const params = new URLSearchParams(window.location.search.substring(1)); const mapId = params.get('id') || 'welcome'; const persistence = new LocalStorageManager('samples/{id}.wxml', false); const options: EditorOptions = { - zoom: 0.8, - locked: false, - mapTitle: 'Develop WiseMapping', mode: 'viewonly', locale: 'en', enableKeyboardEvents: true, @@ -42,7 +40,7 @@ const options: EditorOptions = { ReactDOM.render( console.log('action called:', action)} diff --git a/packages/editor/test/unit/toolbar/toolbar.test.tsx b/packages/editor/test/unit/toolbar/toolbar.test.tsx index 7d06d539..df0691a3 100644 --- a/packages/editor/test/unit/toolbar/toolbar.test.tsx +++ b/packages/editor/test/unit/toolbar/toolbar.test.tsx @@ -13,6 +13,7 @@ import AppBar from '../../../src/components/app-bar'; import ActionConfig from '../../../src/classes/action/action-config'; import Capability from '../../../src/classes/action/capability'; import Editor from '../../../src/classes/model/editor'; +import MapInfoImpl from '../../playground/map-render/js/MapInfoImpl'; require('babel-polyfill'); jest.mock('../../../src/components/app-bar/styles.css', () => ''); @@ -275,7 +276,14 @@ describe('AppBar', () => { it('When render it displays a menu', () => { const capacity = new Capability('edition-owner', false); const model = new Editor(null); - render(); + + render( + , + ); screen.getByRole('menubar'); }); }); diff --git a/packages/webapp/images/logo-medium.svg b/packages/webapp/images/logo-medium.svg index fae99531..af1d1bd0 100644 --- a/packages/webapp/images/logo-medium.svg +++ b/packages/webapp/images/logo-medium.svg @@ -1,5 +1,5 @@ - + diff --git a/packages/webapp/src/classes/app-config/index.ts b/packages/webapp/src/classes/app-config/index.ts index 18265653..52c2f0d9 100644 --- a/packages/webapp/src/classes/app-config/index.ts +++ b/packages/webapp/src/classes/app-config/index.ts @@ -1,3 +1,21 @@ +/* + * Copyright [2021] [wisemapping] + * + * Licensed under WiseMapping Public License, Version 1.0 (the "License"). + * It is basically the Apache License, Version 2.0 (the "License") plus the + * "powered by wisemapping" text requirement on every single page; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the license at + * + * http://www.wisemapping.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import Client from '../client'; import CacheDecoratorClient from '../client/cache-decorator-client'; import MockClient from '../client/mock-client'; diff --git a/packages/webapp/src/classes/client/cache-decorator-client/index.ts b/packages/webapp/src/classes/client/cache-decorator-client/index.ts index 4a1b3bee..d46bbeba 100644 --- a/packages/webapp/src/classes/client/cache-decorator-client/index.ts +++ b/packages/webapp/src/classes/client/cache-decorator-client/index.ts @@ -17,6 +17,10 @@ class CacheDecoratorClient implements Client { this.client = client; } + fetchStarred(id: number): Promise { + return this.client.fetchStarred(id); + } + onSessionExpired(callback?: () => void): () => void { return this.client.onSessionExpired(callback); } diff --git a/packages/webapp/src/classes/client/index.ts b/packages/webapp/src/classes/client/index.ts index bec7e6ad..af188a1d 100644 --- a/packages/webapp/src/classes/client/index.ts +++ b/packages/webapp/src/classes/client/index.ts @@ -80,6 +80,8 @@ interface Client { renameMap(id: number, basicInfo: BasicMapInfo): Promise; fetchAllMaps(): Promise; + fetchStarred(id: number): Promise; + fetchMapPermissions(id: number): Promise; addMapPermissions(id: number, message: string, permissions: Permission[]): Promise; deleteMapPermission(id: number, email: string): Promise; diff --git a/packages/webapp/src/classes/client/mock-client/index.ts b/packages/webapp/src/classes/client/mock-client/index.ts index 9865c25f..2054315d 100644 --- a/packages/webapp/src/classes/client/mock-client/index.ts +++ b/packages/webapp/src/classes/client/mock-client/index.ts @@ -1,3 +1,20 @@ +/* + * Copyright [2021] [wisemapping] + * + * Licensed under WiseMapping Public License, Version 1.0 (the "License"). + * It is basically the Apache License, Version 2.0 (the "License") plus the + * "powered by wisemapping" text requirement on every single page; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the license at + * + * http://www.wisemapping.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ import Client, { AccountInfo, BasicMapInfo, @@ -108,6 +125,10 @@ class MockClient implements Client { this.labels = [label1, label2, label3]; } + fetchStarred(id: number): Promise { + return Promise.resolve(this.maps.find((m) => m.id == id).starred); + } + onSessionExpired(callback?: () => void): () => void { return callback; } @@ -123,8 +144,6 @@ class MockClient implements Client { let perm = this.permissionsByMap.get(id) || []; perm = perm.concat(permissions); this.permissionsByMap.set(id, perm); - - console.debug(`Message ${message}`); return Promise.resolve(); } diff --git a/packages/webapp/src/classes/client/rest-client/index.ts b/packages/webapp/src/classes/client/rest-client/index.ts index 4cad27b7..7a4658d2 100644 --- a/packages/webapp/src/classes/client/rest-client/index.ts +++ b/packages/webapp/src/classes/client/rest-client/index.ts @@ -72,6 +72,25 @@ export default class RestClient implements Client { }; return new Promise(handler); } + + fetchStarred(id: number): Promise { + const handler = (success: (starred: boolean) => void, reject: (error: ErrorInfo) => void) => { + this.axios + .get(`${this.baseUrl}/c/restful/maps/${id}/starred`, { + headers: { 'Content-Type': 'text/plain' }, + }) + .then((response) => { + const data = response.data; + success(data); + }) + .catch((error) => { + const errorInfo = this.parseResponseOnError(error.response); + reject(errorInfo); + }); + }; + return new Promise(handler); + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars addMapPermissions(id: number, message: string, permissions: Permission[]): Promise { const handler = (success: () => void, reject: (error: ErrorInfo) => void) => { diff --git a/packages/webapp/src/classes/editor-map-info/index.ts b/packages/webapp/src/classes/editor-map-info/index.ts new file mode 100644 index 00000000..dfd09d56 --- /dev/null +++ b/packages/webapp/src/classes/editor-map-info/index.ts @@ -0,0 +1,77 @@ +/* + * Copyright [2021] [wisemapping] + * + * Licensed under WiseMapping Public License, Version 1.0 (the "License"). + * It is basically the Apache License, Version 2.0 (the "License") plus the + * "powered by wisemapping" text requirement on every single page; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the license at + * + * http://www.wisemapping.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { MapInfo } from '@wisemapping/editor'; +import Client from '../client'; + +class MapInfoImpl implements MapInfo { + private client: Client; + private id: number; + private title: string; + private zoom: number; + private locked: boolean; + private lockedMsg: string; + + constructor( + id: number, + client: Client, + title: string, + locked: boolean, + lockedMsg: string, + zoom: number, + ) { + this.id = id; + this.client = client; + this.title = title; + this.zoom = zoom; + this.locked = locked; + this.lockedMsg = lockedMsg; + } + + isStarred(): Promise { + return this.client.fetchStarred(this.id); + } + + updateStarred(value: boolean): Promise { + return this.client.updateStarred(this.id, value); + } + + getTitle(): string { + return this.title; + } + + setTitle(value: string): void { + this.client.renameMap(Number.parseInt(this.getId(), 10), { title: value }); + } + + isLocked(): boolean { + return this.locked; + } + + getLockedMessage(): string { + return this.lockedMsg; + } + + getZoom(): number { + return this.zoom; + } + + getId(): string { + return String(this.id); + } +} +export default MapInfoImpl; diff --git a/packages/webapp/src/components/editor-page/index.tsx b/packages/webapp/src/components/editor-page/index.tsx index 79c7c2b0..81e1708a 100644 --- a/packages/webapp/src/components/editor-page/index.tsx +++ b/packages/webapp/src/components/editor-page/index.tsx @@ -1,3 +1,20 @@ +/* + * Copyright [2021] [wisemapping] + * + * Licensed under WiseMapping Public License, Version 1.0 (the "License"). + * It is basically the Apache License, Version 2.0 (the "License") plus the + * "powered by wisemapping" text requirement on every single page; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the license at + * + * http://www.wisemapping.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ import React, { useEffect } from 'react'; import ActionDispatcher from '../maps-page/action-dispatcher'; import { ActionType } from '../maps-page/action-chooser'; @@ -13,6 +30,10 @@ import EditorOptionsBuilder from './EditorOptionsBuilder'; import { buildPersistenceManagerForEditor } from './PersistenceManagerUtils'; import { useTheme } from '@mui/material/styles'; import AccountMenu from '../maps-page/account-menu'; +import MapInfoImpl from '../../classes/editor-map-info'; +import { MapInfo } from '@wisemapping/editor'; +import { activeInstance } from '../../redux/clientSlice'; +import Client from '../../classes/client'; export type EditorPropsType = { isTryMode: boolean; @@ -23,6 +44,7 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => { const hotkey = useSelector(hotkeysEnabled); const userLocale = AppI18n.getUserLocale(); const theme = useTheme(); + const client: Client = useSelector(activeInstance); useEffect(() => { ReactGA.send({ hitType: 'pageview', page: window.location.pathname, title: `Map Editor` }); @@ -62,16 +84,25 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => { const loadCompleted = mode && isAccountLoaded; let options, persistence: PersistenceManager; + let mapInfo: MapInfo; if (loadCompleted) { options = EditorOptionsBuilder.build(userLocale.code, mode, hotkey); persistence = buildPersistenceManagerForEditor(mode); + mapInfo = new MapInfoImpl( + mapId, + client, + options.title, + options.isLocked, + options.lockedMsg, + options.zoom, + ); } useEffect(() => { if (options?.mapTitle) { document.title = `${options.mapTitle} | WiseMapping `; } - }, options?.mapTitle); + }, [loadCompleted]); return loadCompleted ? ( { onAction={setActiveDialog} options={options} persistenceManager={persistence} - mapId={mapId} + mapInfo={mapInfo} theme={theme} accountConfiguration={ // Prevent load on non-authenticated. diff --git a/packages/webapp/src/redux/clientSlice.ts b/packages/webapp/src/redux/clientSlice.ts index 39d9c7d6..4d2022b8 100644 --- a/packages/webapp/src/redux/clientSlice.ts +++ b/packages/webapp/src/redux/clientSlice.ts @@ -1,3 +1,21 @@ +/* + * Copyright [2021] [wisemapping] + * + * Licensed under WiseMapping Public License, Version 1.0 (the "License"). + * It is basically the Apache License, Version 2.0 (the "License") plus the + * "powered by wisemapping" text requirement on every single page; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the license at + * + * http://www.wisemapping.org/license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { createSlice } from '@reduxjs/toolkit'; import { useQuery } from 'react-query'; diff --git a/packages/webapp/webpack.dev.js b/packages/webapp/webpack.dev.js index f5ea8149..0286fbe7 100644 --- a/packages/webapp/webpack.dev.js +++ b/packages/webapp/webpack.dev.js @@ -7,7 +7,6 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = merge(common, { mode: 'development', devtool: 'source-map', - watch: true, devServer: { contentBase: path.join(__dirname, 'dist'), port: 3000,