From 9a2e239ef04d8b0e8f3ae7a2ddf92dd11470701e Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Tue, 9 May 2023 22:59:22 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Added=20`WidgetsWrapper`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/WidgetsWrapper/index.jsx | 197 ++++++++++++++++++ .../src/components/WidgetsWrapper/index.less | 26 +++ packages/app/src/pages/index.jsx | 6 +- 3 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 packages/app/src/components/WidgetsWrapper/index.jsx create mode 100644 packages/app/src/components/WidgetsWrapper/index.less diff --git a/packages/app/src/components/WidgetsWrapper/index.jsx b/packages/app/src/components/WidgetsWrapper/index.jsx new file mode 100644 index 00000000..866b0159 --- /dev/null +++ b/packages/app/src/components/WidgetsWrapper/index.jsx @@ -0,0 +1,197 @@ +import React from "react" +import lodable from "@loadable/component" +import * as antd from "antd" + +import { SortableList, SortableItem, DragHandle } from "components/SortableList" + +import "./index.less" + +class WidgetComponent extends React.Component { + state = { + mountedCssFiles: [], + loading: true, + } + + componentDidMount = async () => { + if (Array.isArray(this.props.manifest.cssFiles)) { + for await (const cssFile of this.props.manifest.cssFiles) { + const cssFileElement = document.createElement("link") + + cssFileElement.rel = "stylesheet" + cssFileElement.href = cssFile + + document.head.appendChild(cssFileElement) + + await this.setState({ + mountedCssFiles: [ + ...this.state.mountedCssFiles, + cssFileElement, + ] + }) + + continue + } + } + + this.setState({ + loading: false, + }) + } + + componentWillUnmount() { + this.state.mountedCssFiles.forEach((cssFileElement) => { + cssFileElement.remove() + }) + } + + // catch if render error + componentDidCatch = (error, errorInfo) => { + console.error(error, errorInfo) + + this.setState({ + loading: false, + renderError: error, + }) + } + + render() { + const { RenderComponent, manifest } = this.props + + const RenderComponentCTX = { + + } + + if (this.state.renderError) { + return
+ +
+ } + + if (this.state.loading) { + return
+ +
+ } + + try { + if (!manifest) { + throw new Error("Widget has no manifest") + } + + if (!RenderComponent) { + throw new Error("Widget has not valid render") + } + + return
+ +
+ } catch (error) { + console.error(error) + + return
+ Invalid widget +
+ } + } +} + +const generateRemoteComponent = (props) => { + return lodable(async () => { + try { + let virtualModule = await import(props.url) + + virtualModule = virtualModule.default + + if (!virtualModule) { + throw new Error("Widget has not valid module") + } + + let RenderComponent = virtualModule.renderComponent + + if (!RenderComponent) { + throw new Error("Widget has not valid render") + } + + console.log(`Generate widget ${virtualModule.manifest.id}`) + + return () => + } catch (error) { + console.error(error) + + return () =>
+ Error loading widget +
+ } + }, { + fallback: + }) +} + +export default class WidgetsWrapper extends React.Component { + state = { + widgetsRender: app.cores.settings.get("widgets.urls").map((url, index) => { + return { + id: `${url}_${index}`, + url, + RenderItem: generateRemoteComponent({ + url, + index: index, + }) + } + }), + } + + handleOnSortEnd = (widgetsRender) => { + this.setState({ + widgetsRender + }) + + const urls = widgetsRender.map((widgetRender) => { + return widgetRender.url + }) + + app.cores.settings.set("widgets.urls", urls) + } + + render() { + return
+ { + const RenderItem = item.RenderItem + + return + + + }} + useDragOverlay + activeDragActions={[ + { + id: "add", + icon: "Plus", + disabled: true, + onClick: () => { + // TODO: Open widget browser + } + }, + ]} + /> +
+ } +} \ No newline at end of file diff --git a/packages/app/src/components/WidgetsWrapper/index.less b/packages/app/src/components/WidgetsWrapper/index.less new file mode 100644 index 00000000..0d7be4b6 --- /dev/null +++ b/packages/app/src/components/WidgetsWrapper/index.less @@ -0,0 +1,26 @@ +.widgets_wrapper { + gap: 20px; + + width: 20vw; + + .widgets_wrapper_list { + display: flex; + flex-direction: column; + gap: 20px; + } + + .widget_item { + display: flex; + flex-direction: column; + + border: 1px var(--border-color) solid; + + border-radius: 12px; + + padding: 10px; + + width: 100%; + + overflow: hidden; + } +} \ No newline at end of file diff --git a/packages/app/src/pages/index.jsx b/packages/app/src/pages/index.jsx index f9cf1dfc..34902439 100755 --- a/packages/app/src/pages/index.jsx +++ b/packages/app/src/pages/index.jsx @@ -2,6 +2,7 @@ import React from "react" import * as antd from "antd" import { Translation } from "react-i18next" +import WidgetsWrapper from "components/WidgetsWrapper" import { PagePanelWithNavMenu } from "components/PagePanels" import { Icons } from "components/Icons" @@ -50,13 +51,16 @@ export default class Home extends React.Component { - + } return + ]} extraPanel={extraPanel} primaryPanelClassName="full" useSetQueryType