)
}
- renderLogout() {
- if (window.app.isValidSession()) {
- return (
-
- )
- }
+ renderGroup = (key, group) => {
+ const fromDecoratorIcon = groupsDecorator[key]?.icon
+ const fromDecoratorTitle = groupsDecorator[key]?.title
- return
+ )
+ }
+
+ generateSettings = (data) => {
+ let groups = {}
+
+ data.forEach((item) => {
+ if (!groups[item.group]) {
+ groups[item.group] = []
+ }
+
+ groups[item.group].push(item)
+ })
+
+ return Object.keys(groups).map((groupKey) => {
+ return this.renderGroup(groupKey, groups[groupKey])
+ })
}
render() {
+ const isDevMode = window.__evite.env.NODE_ENV !== "production"
+
return (
-
- {this.generateMenu(settingList)}
-
- {this.renderLogout()}
- {this.renderAboutApp()}
-
AboutApp.openModal()}>
- About
-
+
+ {this.generateSettings(settingList)}
+
+
+
{config.app?.siteName}
+
+
+ v{window.__evite.projectVersion}
+
+
+
+
+ {isDevMode ? : }
+ {isDevMode ? "development" : "stable"}
+
+
+
+
+
AboutApp.openModal()}>
+ About
+
+
)
}
-}
-
-const controller = {
- open: (key) => {
- // TODO: Scroll to content
- window.app.DrawerController.open("settings", SettingsMenu, {
- props: {
- width: "45%",
- },
- })
- },
-
- close: () => {
- window.app.DrawerController.close("settings")
- },
-}
-
-export default controller
+}
\ No newline at end of file
diff --git a/packages/app/src/components/Settings/index.less b/packages/app/src/components/Settings/index.less
index e0332d48..d9de886b 100644
--- a/packages/app/src/components/Settings/index.less
+++ b/packages/app/src/components/Settings/index.less
@@ -1,44 +1,81 @@
-.settings_groupItems{
- > div {
- padding: 12px 30px;
- }
+.settings {
+ display: flex;
+ flex-direction: column;
+
+ > div {
+ margin-bottom: 25px;
+ }
+
+ .group {
+ display: flex;
+ flex-direction: column;
+
+ .content {
+ > div {
+ margin-bottom: 25px;
+ }
+ }
+ }
+
+ .settingItem {
+ padding: 0 20px;
+
+ > div {
+ margin-bottom: 10px;
+ }
+
+ .header {
+ display: flex;
+ align-items: center;
+
+ h5{
+ margin: 0;
+ }
+
+ > div {
+ margin-right: 10px;
+ }
+ }
+
+ .component {
+ padding: 0 20px;
+ }
+ }
+
+ .footer {
+ position: relative;
+ width: 100%;
+
+ padding-top: 20px;
+ padding-bottom: 20px;
+
+ display: flex;
+ flex-direction: column;
+
+ justify-content: center;
+ align-items: center;
+
+ > div {
+ margin-bottom: 10px;
+
+ font-family: "Space Mono", monospace;
+ font-size: 10px;
+
+ display: flex;
+ flex-direction: row;
+
+ align-items: center;
+ justify-content: center;
+
+ .ant-tag {
+ height: 18px;
+ line-height: 18px;
+ font-size: 10px;
+ }
+
+ > div {
+ padding: 0 7px;
+ }
+ }
+ }
}
-
-.settings_about_app{
- font-family: 'Space Mono', monospace;
- font-size: 10px;
-
- display: flex;
- flex-direction: row;
-
- align-items: center;
- justify-content: center;
-
- .ant-tag{
- height: 18px;
- line-height: 18px;
- font-size: 10px;
- }
-
- > div {
- padding: 0 7px;
- }
-}
-
-.settings_bottom_items {
- position: relative;
- bottom: 0;
- right: 0;
- width: 100%;
- padding-bottom: 20px;
-
- display: flex;
- flex-direction: column;
-
- justify-content: center;
- align-items: center;
-
- > div {
- padding: 10px 0;
- }
-}
\ No newline at end of file
diff --git a/packages/app/src/components/buttonMenu/index.tsx b/packages/app/src/components/buttonMenu/index.tsx
deleted file mode 100644
index a41b57af..00000000
--- a/packages/app/src/components/buttonMenu/index.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from 'react'
-import * as antd from 'antd'
-import { Icons } from 'components/Icons'
-import { FormattedMessage } from 'react-intl'
-
-export default class ButtonMenu extends React.Component {
- handleClickMenu(id) {
- const element = document.getElementById(id)
- if (typeof (element) !== "undefined") {
- try {
- element.focus()
- } catch (error) {
- console.log(error)
- }
- }
- if (typeof (this.props.onClick) !== "undefined") {
- this.props.onClick(id)
- }
- }
-
- renderMenus() {
- return this.props?.menus?.map((e) => {
- return
this.handleClickMenu(e.id)} id={e.id ?? Math.random} key={e.id} className={window.classToStyle("indexMenuItem")}>
- {e.icon ? React.createElement(Icons[e.icon], { style: e.iconStyle ?? null }) : null}
-
-
- })
- }
-
- render() {
- return (
-
- {this.renderMenus()}
-
- )
- }
-}
\ No newline at end of file
diff --git a/packages/app/src/components/formGenerator/index.jsx b/packages/app/src/components/formGenerator/index.jsx
index 55c035dd..af22be99 100644
--- a/packages/app/src/components/formGenerator/index.jsx
+++ b/packages/app/src/components/formGenerator/index.jsx
@@ -392,4 +392,4 @@ export default class FormGenerator extends React.Component {
)
}
-}
+}
\ No newline at end of file
diff --git a/packages/app/src/components/googleMap/index.tsx b/packages/app/src/components/googleMap/index.tsx
deleted file mode 100644
index 06f95d0c..00000000
--- a/packages/app/src/components/googleMap/index.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react'
-
-const Marker = ({ text }) =>
-
-export default (props) => {
- if (typeof(props.size) == "undefined") {
- props.size = "420px"
- }
- return
-
-
-}
\ No newline at end of file
diff --git a/packages/app/src/components/index.js b/packages/app/src/components/index.js
index 8886a07a..478f1bcc 100644
--- a/packages/app/src/components/index.js
+++ b/packages/app/src/components/index.js
@@ -1,27 +1,17 @@
-import FormGenerator from './formGenerator'
-import ButtonMenu from './buttonMenu'
-import * as AboutApp from './AboutApp'
+export { default as FormGenerator } from "./FormGenerator"
+export { default as Settings } from "./Settings"
+export { default as NotFound } from "./NotFound"
+export { default as AppSearcher } from "./AppSearcher"
+export { default as RenderError } from "./RenderError"
-export { default as LoadingSpinner } from './LoadingSpinner'
-export { default as Settings } from './Settings'
-export { default as NotFound } from './notFound'
-export { default as AppLoading } from './AppLoading'
-export { default as AppSearcher } from './AppSearcher'
-export { default as RenderError } from './RenderError'
-
-export { default as ElementsList } from './ElementsList'
-export { default as Sessions } from './Sessions'
-export { default as Roles } from './Roles'
-export { default as ActionsBar } from './ActionsBar'
-export { default as SelectableList } from './SelectableList'
-export { default as ObjectInspector } from './ObjectInspector'
-export { default as FabricCreator } from './FabricCreator'
+export { default as Sessions } from "./Sessions"
+export { default as ActionsBar } from "./ActionsBar"
+export { default as SelectableList } from "./SelectableList"
+export { default as ObjectInspector } from "./ObjectInspector"
+export { default as FabricCreator } from "./FabricCreator"
+export { default as ServerStatus } from "./ServerStatus"
+export { default as ModifierTag } from "./ModifierTag"
+export * as AboutApp from "./AboutApp"
export * as QRReader from "./QRReader"
-export * as Window from './RenderWindow'
-
-export {
- AboutApp,
- ButtonMenu,
- FormGenerator,
-}
\ No newline at end of file
+export * as Window from "./RenderWindow"
\ No newline at end of file
diff --git a/packages/app/src/components/modifierTag/index.jsx b/packages/app/src/components/modifierTag/index.jsx
new file mode 100644
index 00000000..222a2019
--- /dev/null
+++ b/packages/app/src/components/modifierTag/index.jsx
@@ -0,0 +1,76 @@
+import React from "react"
+import * as antd from "antd"
+import { Icons, createIconRender } from "components/Icons"
+
+export default (props) => {
+ const [loading, setLoading] = React.useState(false)
+ const [options, setOptions] = React.useState([])
+ const [value, setValue] = React.useState(null)
+
+ const onChangeProperties = async (update) => {
+ if (props.eventDisable) {
+ return false
+ }
+
+ setLoading(true)
+
+ await props.onChangeProperties(update)
+ .then((data) => {
+ return setValue(update.join("-"))
+ })
+ .catch((error) => {
+ return
+ })
+
+ setLoading(false)
+ }
+
+ const getTagColor = () => {
+ if (props.colors) {
+ return props.colors[value]
+ }
+
+ return "default"
+ }
+
+ const handleOptionsLoad = async (fn) => {
+ setLoading(true)
+
+ const result = await fn()
+ setOptions(result)
+
+ setLoading(false)
+ }
+
+ const handleDefaultValueLoad = async (fn) => {
+ const result = await fn()
+ setValue(result)
+ }
+
+ React.useEffect(() => {
+ if (typeof props.options === "function") {
+ handleOptionsLoad(props.options)
+ } else {
+ setOptions(props.options)
+ }
+
+ if (typeof props.defaultValue === "function") {
+ handleDefaultValueLoad(props.defaultValue)
+ } else {
+ setValue(props.defaultValue)
+ }
+ }, [])
+
+ return
onChangeProperties(update)} >
+
+ {loading ? :
+ <>
+ {Icons[props.icon] && createIconRender(props.icon)}
+
+ {value}
+
+ >
+ }
+
+
+}
\ No newline at end of file
diff --git a/packages/app/src/controllers/settings/index.js b/packages/app/src/controllers/settings/index.js
index c0e5284c..63722949 100644
--- a/packages/app/src/controllers/settings/index.js
+++ b/packages/app/src/controllers/settings/index.js
@@ -1,16 +1,12 @@
import store from 'store'
-import EventEmitter from "@foxify/events"
import { objectToArrayMap } from '@corenode/utils'
-import handlers from 'core/handlers'
-
-const defaultKeys = import('schemas/defaultSettings.json')
+import defaultKeys from "schemas/defaultSettings.json"
class SettingsController {
constructor() {
- this.storeKey = "settings"
+ this.storeKey = "app_settings"
this.defaultSettings = defaultKeys
- this.events = new EventEmitter()
this.settings = store.get(this.storeKey) ?? {}
objectToArrayMap(this.defaultSettings).forEach((entry) => {
@@ -19,12 +15,6 @@ class SettingsController {
}
})
- this.events.on('changeSetting', (payload) => {
- if (typeof handlers[payload.id] === "function") {
- handlers[payload.id](payload)
- }
- })
-
return this
}
@@ -47,7 +37,7 @@ class SettingsController {
let value = to ?? !this.settings[key] ?? true
this.set(key, value)
- this.events.emit("changeSetting", { key, value, to })
+ window.app.eventBus.emit("changeSetting", { key, value, to })
return this.settings
}
diff --git a/packages/app/src/core/events.js b/packages/app/src/core/events.js
deleted file mode 100644
index dfd881b7..00000000
--- a/packages/app/src/core/events.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import handlers from './handlers'
-import { message, notification } from 'antd'
-
-const events = {
- invalidSidebarKey: (event) => {
- console.error(`[invalidSidebarKey] >>`, event)
- notification.error({
- message: `An error seems to have occurred trying to open this.`,
- description: "We will report this automatically"
- })
- }
-}
-
-export default events
\ No newline at end of file
diff --git a/packages/app/src/core/handlers.js b/packages/app/src/core/handlers.js
deleted file mode 100644
index 58ac3ffe..00000000
--- a/packages/app/src/core/handlers.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const handlers = {
- "edit_sidebar": () => {
- window.app.SidebarController.toogleEdit()
- }
-}
-
-export default handlers
\ No newline at end of file
diff --git a/packages/app/src/core/index.js b/packages/app/src/core/index.js
deleted file mode 100644
index 4d7c4613..00000000
--- a/packages/app/src/core/index.js
+++ /dev/null
@@ -1,186 +0,0 @@
-import { cloneDeep } from 'lodash'
-import store from 'store'
-import { pathToRegexp } from 'path-to-regexp'
-import config from 'config'
-
-const languages = config.i18n ? config.i18n.languages.map(item => item.key) : []
-const defaultLanguage = config.i18n ? config.i18n.defaultLanguage : 'en'
-
-/**
- * Query objects that specify keys and values in an array where all values are objects.
- * @param {array} array An array where all values are objects, like [{key:1},{key:2}].
- * @param {string} key The key of the object that needs to be queried.
- * @param {string} value The value of the object that needs to be queried.
- * @return {object|undefined} Return frist object when query success.
- */
-export function queryArray(array, key, value) {
- if (!Array.isArray(array)) {
- return
- }
- return array.find(_ => _[key] === value)
-}
-
-/**
- * Convert an array to a tree-structured array.
- * @param {array} array The Array need to Converted.
- * @param {string} id The alias of the unique ID of the object in the array.
- * @param {string} parentId The alias of the parent ID of the object in the array.
- * @param {string} children The alias of children of the object in the array.
- * @return {array} Return a tree-structured array.
- */
-export function arrayToTree(
- array,
- id = 'id',
- parentId = 'pid',
- children = 'children',
-) {
- const result = []
- const hash = {}
- const data = cloneDeep(array)
-
- data.forEach((item, index) => {
- hash[data[index][id]] = data[index];
- })
-
- data.forEach(item => {
- const hashParent = hash[item[parentId]]
- if (hashParent) {
- !hashParent[children] && (hashParent[children] = [])
- hashParent[children].push(item)
- } else {
- result.push(item)
- }
- })
- return result
-}
-
-/**
- * In an array object, traverse all parent IDs based on the value of an object.
- * @param {array} array The Array need to Converted.
- * @param {string} current Specify the value of the object that needs to be queried.
- * @param {string} parentId The alias of the parent ID of the object in the array.
- * @param {string} id The alias of the unique ID of the object in the array.
- * @return {array} Return a key array.
- */
-export function queryPathKeys(array, current, parentId, id = 'id') {
- const result = [current]
- const hashMap = new Map()
- array.forEach(item => hashMap.set(item[id], item))
-
- const getPath = current => {
- const currentParentId = hashMap.get(current)[parentId]
- if (currentParentId) {
- result.push(currentParentId)
- getPath(currentParentId)
- }
- }
-
- getPath(current)
- return result
-}
-
-/**
- * Query which layout should be used for the current path based on the configuration.
- * @param {layouts} layouts Layout configuration.
- * @param {pathname} pathname Path name to be queried.
- * @return {string} Return frist object when query success.
- */
-export function queryLayout(layouts, pathname) {
- let result = 'public'
-
- const isMatch = regepx => {
- return regepx instanceof RegExp
- ? regepx.test(pathname)
- : pathToRegexp(regepx).exec(pathname)
- }
-
- for (const item of layouts) {
- let include = false
- let exclude = false
- if (item.include) {
- for (const regepx of item.include) {
- if (isMatch(regepx)) {
- include = true
- break
- }
- }
- }
-
- if (include && item.exclude) {
- for (const regepx of item.exclude) {
- if (isMatch(regepx)) {
- exclude = true
- break
- }
- }
- }
-
- if (include && !exclude) {
- result = item.name
- break
- }
- }
-
- return result
-}
-
-export function getLocale() {
- return store.get('locale') || defaultLanguage
-}
-
-export function setLocale(language) {
- if (getLocale() !== language) {
- store.set('locale', language)
- window.location.reload()
- }
-}
-
-export function queryIndexer(array, callback, params) {
- if (!array) return false
- if (typeof (pathMatchRegexp) == "undefined") {
- return false
- }
-
- if (Array.isArray(array)) {
- let opt = {
- regex: /:id/gi
- }
-
- if (params) {
- opt = { ...opt, ...params }
- }
-
- array.forEach((e) => {
- if (e.match != null && e.to != null) {
- const pathMatch = pathMatchRegexp(e.match, window.location.pathname)
- if (pathMatch != null) {
- return callback(e.to.replace(opt.regex, pathMatch[1]))
- }
- }
- })
- }
-}
-
-export function generateGUID(lenght = 6) {
- let text = ""
- const possibleChars = "abcdefghijklmnopqrstuvwxyz0123456789"
-
- for (let i = 0; i < 6; i++)
- text += possibleChars.charAt(Math.floor(Math.random() * possibleChars.length))
-
- return text
-}
-
-export function generateRandomId(length = 15) {
- return Math.random().toString(36).substring(0, length)
-}
-
-//
-export function geteventBus() {
- if (typeof window.app.eventBus !== "undefined") {
- return window.app.eventBus
- }
- return null
-}
-
-export { config, languages, defaultLanguage }
\ No newline at end of file
diff --git a/packages/app/src/core/libs/controller/index.js b/packages/app/src/core/libs/controller/index.js
deleted file mode 100644
index 44f2c2d1..00000000
--- a/packages/app/src/core/libs/controller/index.js
+++ /dev/null
@@ -1,98 +0,0 @@
-import { verbosity } from '@corenode/utils'
-const inmutableKey = ["_params"]
-
-export class Controller {
- constructor(params) {
- this.params = params
-
- this.id = params.id
- // this.scope = ["window"]
- this.scopeWindow = params.scopeWindow ?? true
-
- this.freezedKeys = []
- this.lockController = params.locked ?? false
-
- this.register({ _params: params })
- }
-
- _canDestroy(key) {
- if (!inmutableKey.includes(key) && !this.freezedKeys.includes(key)) {
- return true
- }
- return false
- }
-
- _initWindowScope() {
- if (typeof (window.controllers) == "undefined") {
- window.controllers = Object
- }
- }
-
- register(controller) {
- // this.scope.forEach((key, index) => {
-
- // })
- if (this.scopeWindow) {
- if (typeof (window.controllers) == "undefined") {
- this._initWindowScope()
- }
-
- window.controllers[this.id] = controller
- }
- }
-
- freeze = {
- _keys: () => {
- return this.freezedKeys
- },
- isLock: (key) => {
- if (key === "_self") {
- return this.lockController
- }
-
- return this._canDestroy(key)
- },
- lock: (key) => {
- if (key === "_self") {
- return this.lockController = true
- }
- this.freezedKeys.push(key)
- },
- unlock: (key) => {
- if (key === "_self") {
- return this.lockController = false
- }
-
- const updated = this.freezedKeys.filter(function (value, index, arr) {
- return value !== key
- })
- this.freezedKeys = updated
- }
- }
-
- add(key, method, options, events) {
- this[key] = method
-
- window.controllers[this.id][key] = method
-
- if (options?.lock) {
- this.freeze.lock(key)
- }
- }
-
- remove(key) {
- if (this._canDestroy(key)) {
- return delete window.controllers[this.id][key]
- }
- verbosity.warn(`It is not possible to destroy this key because it is locked`)
- }
-
- destroy() {
- if (!this.lockController) {
- return delete window.controllers[this.id]
- }
- verbosity.warn(`It is not possible to destroy this controller because it is locked`)
- }
-}
-
-export default Controller
\ No newline at end of file
diff --git a/packages/app/src/core/libs/djail/index.js b/packages/app/src/core/libs/djail/index.js
deleted file mode 100644
index f43d077f..00000000
--- a/packages/app/src/core/libs/djail/index.js
+++ /dev/null
@@ -1,157 +0,0 @@
-// Prototype for nodecore module
-import { verbosity } from '@corenode/utils'
-import store from 'store'
-
-export class DJail {
- constructor(params) {
- this.storeKey = params.name
- this.voidMutation = params.voidMutation ?? false
- this.objectType = params.type ?? "object"
- this.data = null
-
- if (!this.storeKey) {
- throw new Error(`Invalid or missing store name`)
- }
-
- switch (this.objectType) {
- case "object": {
- this.data = new Object()
- break
- }
- case "array": {
- this.data = new Array()
- this.data[0] = {}
- break
- }
-
- default: {
- this.data = new Object()
- break
- }
- }
- }
-
- _pull() {
- const storaged = store.get(this.storeKey)
-
- if (storaged) {
- this.data = store.get(this.storeKey)
- }
-
- return this.data
- }
-
- _push(update) {
- if (typeof update !== "undefined") {
- switch (this.objectType) {
- case "object": {
- this.data = { ...this.data, ...update }
- }
- case "array": {
- this.data = [...this.data, ...update]
- }
- default: {
- break
- }
- }
- }
-
- store.set(this.storeKey, this.data)
- }
-
- getValue(key) {
- try {
- return this.get(key)[key]
- } catch (error) {
- verbosity.error(error)
- return false
- }
- }
-
- get(query) {
- this._pull()
- if (!query) {
- return this.data
- }
-
- let scope = []
- let matched = {}
-
- if (Array.isArray(query)) {
- scope = query
- } else {
- scope.push(query)
- }
-
- scope.forEach((key) => {
- switch (this.objectType) {
- case "object": {
- matched[key] = this.data[key]
- break
- }
- case "array": {
- const adresses = this.data[0]
- matched[key] = this.data[adresses[key]]
- break
- }
- default: {
- break
- }
- }
-
- })
-
- return matched
- }
-
- set(key, value) {
- this._pull()
-
- switch (this.objectType) {
- case "object": {
- if (typeof (value) == "undefined") {
- if (!this.voidMutation) {
- verbosity.warn(`voidMutation is enabled, no changes on key [${key}]`)
- return settings
- }
- verbosity.warn(`voidMutation is not enabled, undefined values causes key removal`)
- }
-
- this.data[key] = value
- break
- }
- case "array": {
- this.data.push(value)
- this.data[0][key] = (this.data.length - 1)
- break
- }
- default: {
- break
- }
- }
-
- this._push()
- return this.data
- }
-
- remove(key) {
- switch (this.objectType) {
- case "object": {
- delete this.data[key]
- this._push()
- break
- }
- case "array": {
- this.data.filter(item => item.key !== key)
- break
- }
- default: {
- break
- }
- }
-
- return this.data
- }
-}
-
-export default DJail
\ No newline at end of file
diff --git a/packages/app/src/core/libs/index.js b/packages/app/src/core/libs/index.js
deleted file mode 100644
index 8aa13484..00000000
--- a/packages/app/src/core/libs/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import { Controller } from './controller'
-import DJail from './djail'
-
-export { default as settings } from './settings'
-export { Controller, DJail }
\ No newline at end of file
diff --git a/packages/app/src/core/libs/settings/index.js b/packages/app/src/core/libs/settings/index.js
deleted file mode 100644
index 057092a2..00000000
--- a/packages/app/src/core/libs/settings/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import config from 'config'
-import DJail from '../djail'
-
-export const settings = new DJail({ name: config.app?.storage?.settings ?? "settings", voidMutation: true })
-export default settings
\ No newline at end of file
diff --git a/packages/app/src/core/models/settings/index.js b/packages/app/src/core/models/settings/index.js
deleted file mode 100644
index 91a4d88d..00000000
--- a/packages/app/src/core/models/settings/index.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import store from 'store'
-import EventEmitter from "@foxify/events"
-import { objectToArrayMap } from '@corenode/utils'
-import handlers from 'core/handlers'
-
-const defaultKeys = import('schemas/defaultSettings.json')
-
-class SettingsController {
- constructor() {
- this.storeKey = "app_settings"
- this.defaultSettings = defaultKeys
-
- this.events = new EventEmitter()
- this.settings = store.get(this.storeKey) ?? {}
-
- objectToArrayMap(this.defaultSettings).forEach((entry) => {
- if (typeof this.settings[entry.key] === "undefined") {
- this.settings[entry.key] = entry.value
- }
- })
-
- this.events.on('changeSetting', (payload) => {
- if (typeof handlers[payload.id] === "function") {
- handlers[payload.id](payload)
- }
- })
-
- return this
- }
-
- _pull() {
- this.settings = { ...this.settings, ...store.get(this.storeKey) }
- }
-
- _push(update) {
- if (typeof update !== "undefined") {
- this.settings = { ...this.settings, ...update }
- }
- store.set(this.storeKey, this.settings)
- }
-
- is = (key, value) => {
- return this.settings[key] === value ? true : false
- }
-
- change = (key, to) => {
- let value = to ?? !this.settings[key] ?? true
-
- this.set(key, value)
- this.events.emit("changeSetting", { key, value, to })
-
- return this.settings
- }
-
- set = (key, value) => {
- this.settings[key] = value
- store.set(this.storeKey, this.settings)
-
- return this.settings
- }
-
- get = (key) => {
- if (typeof key === "undefined") {
- return this.settings
- }
- return this.settings[key]
- }
-}
-
-export default SettingsController
\ No newline at end of file
diff --git a/packages/app/src/core/models/sidebar/index.js b/packages/app/src/core/models/sidebar/index.js
deleted file mode 100644
index af108fcc..00000000
--- a/packages/app/src/core/models/sidebar/index.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import store from 'store'
-import defaultKeys from 'schemas/defaultSidebar.json'
-
-class SidebarController {
- constructor() {
- this.storeKey = "app_sidebar"
- this.defaults = defaultKeys
-
- this.data = store.get(this.storeKey) ?? this.defaults
- return this
- }
-
- _pull = () => {
- this.data = [...this.data, ...store.get(this.storeKey)]
- }
-
- _push = (update) => {
- if (typeof update !== "undefined") {
- this.data = update
- }
- store.set(this.storeKey, this.data)
- }
-
- set = (value) => {
- this.data.push(value)
- this._push()
-
- return this.data
- }
-
- all = () => {
- let objs = []
-
- this.data.forEach((entry) => {
- objs.push(entry)
- })
-
- return objs
- }
-
- get = () => {
- return this.data
- }
-}
-
-export default SidebarController
\ No newline at end of file
diff --git a/packages/app/src/core/permissions/index.js b/packages/app/src/core/permissions/index.js
deleted file mode 100644
index 01235dca..00000000
--- a/packages/app/src/core/permissions/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { User } from "models"
-
-export function hasPermissions() {
-
-}
-
-export async function hasAdmin() {
- const roles = await User.roles
-
- if (!roles) {
- return false
- }
-
- return Array.isArray(roles) && roles.includes("admin")
-}
\ No newline at end of file
diff --git a/packages/app/src/debug/api/index.jsx b/packages/app/src/debug/api/index.jsx
deleted file mode 100644
index cef9c08f..00000000
--- a/packages/app/src/debug/api/index.jsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import React from 'react'
-
-export default () => {
- return
-
-
-}
\ No newline at end of file
diff --git a/packages/app/src/debug/evite/index.jsx b/packages/app/src/debug/evite/index.jsx
deleted file mode 100644
index 03d9d9ed..00000000
--- a/packages/app/src/debug/evite/index.jsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import React from "react"
-import ReactJson from "react-json-view"
-
-import "./index.less"
-
-export default class EviteDebugger extends React.Component {
- static bindMain = "all"
-
- getClassname(classname) {
- return `evite-debugger_${classname}`
- }
-
- getExtensions() {
- const extensions = {}
-
- Array.from(this.props.contexts.main.extensionsKeys).forEach((extension) => {
- extensions[extension.key] = extension
- })
-
- return extensions
- }
-
- render() {
- const { app, main } = this.props.contexts
-
- return (
-
- )
- }
-}
\ No newline at end of file
diff --git a/packages/app/src/debug/evite/index.less b/packages/app/src/debug/evite/index.less
deleted file mode 100644
index ba2e09e0..00000000
--- a/packages/app/src/debug/evite/index.less
+++ /dev/null
@@ -1,23 +0,0 @@
-.evite-debugger_warning_bindingDisabled {
- color: rgb(255, 166, 0);
- padding: 10px;
- text-align: center;
-}
-
-.evite-debugger_content{
- > div {
- margin-bottom: 15px;
- border: 0.3px solid #ccc;
- border-radius: 4px;
- padding: 5px;
- }
-}
-
-code {
- background-color: rgba(0, 0, 0, 0.7);
- border-radius: 6px;
- padding: 5px;
- font-size: 12px;
- color:aliceblue;
- margin: 5px;
-}
\ No newline at end of file
diff --git a/packages/app/src/debug/index.js b/packages/app/src/debug/index.js
deleted file mode 100644
index 739bd3d4..00000000
--- a/packages/app/src/debug/index.js
+++ /dev/null
@@ -1,4 +0,0 @@
-export { default as less } from './less'
-export { default as api } from './api'
-export { default as evite } from './evite'
-export { default as workload } from './workload'
\ No newline at end of file
diff --git a/packages/app/src/debug/less/index.jsx b/packages/app/src/debug/less/index.jsx
deleted file mode 100644
index 1ec43bf1..00000000
--- a/packages/app/src/debug/less/index.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react'
-import less from "less"
-
-export default () => {
- console.log(less)
-
- return
-
Current Variables
-
-
-}
\ No newline at end of file
diff --git a/packages/app/src/debug/workload/index.jsx b/packages/app/src/debug/workload/index.jsx
deleted file mode 100644
index 5c72b4cb..00000000
--- a/packages/app/src/debug/workload/index.jsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import React from "react"
-import RJson from "react-json-view"
-
-import "./index.less"
-
-export default class WorkloadDebugger extends React.Component {
- binding = window.app.debug.bindings["workload_list"]
-
- addTestWorkload = () => {
- this.binding.addWorkload({
- _id: "test",
- name: "Test Workload",
- status: "funny",
- })
- this.forceUpdate()
- }
-
- removeTestWorkload = () => {
- this.binding.deleteWorkload("test")
- this.forceUpdate()
- }
-
- render() {
- this.binding = window.app.debug.bindings["workload_list"]
-
- if (!this.binding) {
- return (
-
-
Workload binding not available
-
-
-
- )
- }
-
- return (
-
-
-
-
Test item
-
-
-
-
-
-
- )
- }
-}
diff --git a/packages/app/src/debug/workload/index.less b/packages/app/src/debug/workload/index.less
deleted file mode 100644
index c1c06cc6..00000000
--- a/packages/app/src/debug/workload/index.less
+++ /dev/null
@@ -1,14 +0,0 @@
-.wrapper {
- display: flex;
- flex-direction: column;
-
- > div {
- margin-bottom: 10px;
- }
-}
-
-.section {
- > div {
- padding-left: 10px;
- }
-}
\ No newline at end of file
diff --git a/packages/app/src/extensions/api/index.js b/packages/app/src/extensions/api/index.js
index 9d944142..cb8941d6 100644
--- a/packages/app/src/extensions/api/index.js
+++ b/packages/app/src/extensions/api/index.js
@@ -1,6 +1,7 @@
import config from 'config'
import { Bridge } from "linebridge/client"
import { Session } from "models"
+import io from "socket.io-client"
export default {
key: "apiBridge",
@@ -9,8 +10,23 @@ export default {
mutateContext: {
async initializeDefaultBridge() {
this.apiBridge = await this.createBridge()
+ this.ws = io(config.ws.address, { transports: ["websocket"] })
- window.app.apiBridge = this.apiBridge
+ this.ws.on("connect", (...context) => {
+ window.app.eventBus.emit("websocket_connected", ...context)
+ })
+
+ this.ws.on("disconnect", (...context) => {
+ window.app.eventBus.emit("websocket_disconnected", ...context)
+ })
+
+ this.ws.on("connect_error", (...context) => {
+ window.app.eventBus.emit("websocket_connection_error", ...context)
+ })
+
+ window.app.ws = this.ws
+ window.app.api = this.apiBridge
+ window.app.request = this.apiBridge.endpoints
},
createBridge: async () => {
const getSessionContext = () => {
@@ -27,7 +43,7 @@ export default {
}
const bridge = new Bridge({
- origin: config.api?.address,
+ origin: config.api.address,
onRequestContext: getSessionContext,
})
@@ -38,7 +54,7 @@ export default {
}
})
- return bridge.endpoints
+ return bridge
},
},
},
diff --git a/packages/app/src/extensions/debug/index.jsx b/packages/app/src/extensions/debug/index.jsx
deleted file mode 100644
index e314c094..00000000
--- a/packages/app/src/extensions/debug/index.jsx
+++ /dev/null
@@ -1,129 +0,0 @@
-import React from "react"
-import { Window } from "components"
-import { Skeleton, Tabs } from "antd"
-
-class DebuggerUI extends React.Component {
- state = {
- loading: true,
- error: null,
- debuggers: null,
- active: null,
- }
-
- toogleLoading = (to = !this.state.loading ?? false) => {
- this.setState({ loading: to })
- }
-
- loadDebuggers = async () => {
- this.toogleLoading(true)
-
- const debuggers = await import(`@/debug`)
- let renders = {}
-
- Object.keys(debuggers).forEach((key) => {
- renders[key] = debuggers[key]
- })
-
- this.setState({ debuggers: renders }, () => {
- this.toogleLoading(false)
- })
- }
-
- componentDidMount = async () => {
- await this.loadDebuggers()
- }
-
- componentDidCatch = (error, info) => {
- this.setState({ error })
- }
-
- onChangeTab = (key) => {
- this.setState({ active: key, error: null })
- }
-
- renderError = (key, error) => {
- return (
-
-
Debugger Error
-
-
- Catch on [{key}]
-
-
- `{error.message}
`
-
- {error.stack}
-
- )
- }
-
- renderTabs = () => {
- return Object.keys(this.state.debuggers).map((key) => {
- return
- })
- }
-
- renderDebugger = (_debugger) => {
- try {
- return React.createElement(window.app.bindContexts(_debugger))
- } catch (error) {
- return this.renderError(key, error)
- }
- }
-
- render() {
- const { loading, error } = this.state
-
- if (loading) {
- return
- }
-
- return (
-
-
{this.renderTabs()}
- {error && this.renderError(this.state.active, error)}
- {!this.state.active ? (
-
Select an debugger to start
- ) : (
- this.renderDebugger(this.state.debuggers[this.state.active])
- )}
-
- )
- }
-}
-
-class Debugger {
- constructor(mainContext, params = {}) {
- this.mainContext = mainContext
- this.params = { ...params }
-
- this.bindings = {}
- }
-
- openWindow = () => {
- new Window.DOMWindow({ id: "debugger", children: window.app.bindContexts(DebuggerUI) }).create()
- }
-
- bind = (id, binding) => {
- this.bindings[id] = binding
-
- return binding
- }
-
- unbind = (id) => {
- delete this.bindings[id]
- }
-}
-
-export default {
- key: "visualDebugger",
- expose: [
- {
- initialization: [
- async (app, main) => {
- main.setToWindowContext("debug", new Debugger(main))
- },
- ],
- },
- ],
-}
diff --git a/packages/app/src/extensions/index.js b/packages/app/src/extensions/index.js
index 9096f144..674d2ef9 100644
--- a/packages/app/src/extensions/index.js
+++ b/packages/app/src/extensions/index.js
@@ -1,6 +1,5 @@
export * as Render from './render'
export * as Splash from './splash'
export * as Sound from './sound'
-export { default as API } from './api'
-export { default as Debug } from './debug'
-export { default as Theme } from './theme'
\ No newline at end of file
+export * as Theme from './theme'
+export { default as API } from './api'
\ No newline at end of file
diff --git a/packages/app/src/extensions/render/index.jsx b/packages/app/src/extensions/render/index.jsx
index 1c6a6a67..f9ec0571 100644
--- a/packages/app/src/extensions/render/index.jsx
+++ b/packages/app/src/extensions/render/index.jsx
@@ -1,5 +1,6 @@
import React from "react"
import loadable from "@loadable/component"
+import resolve from "pages"
export const ConnectWithApp = (component) => {
return window.app.bindContexts(component)
@@ -15,9 +16,17 @@ export function GetRoutesMap() {
export const LazyRouteRender = (props) => {
const component = loadable(async () => {
const location = window.location
- const path = props.path ?? location.pathname
+ let path = props.path ?? location.pathname
- let module = await import(`/src/pages/${path}`).catch(() => {
+ if (path.startsWith("/")) {
+ path = path.substring(1)
+ }
+
+ const src = resolve(path)
+ console.log(src)
+
+ let module = await import(src).catch((err) => {
+ console.error(err)
return props.staticRenders?.NotFound ?? import("./statics/404")
})
module = module.default || module
@@ -53,7 +62,11 @@ export class RenderRouter extends React.Component {
lastHistoryState = null
shouldComponentUpdate() {
- return window.location.pathname !== this.lastPathname || this.lastHistoryState !== window.app.history.location.state
+ if (this.lastPathname !== window.location.pathname || this.lastHistoryState !== window.app.history.location.state) {
+ return true
+ }
+
+ return false
}
render() {
@@ -117,8 +130,9 @@ export const extension = {
})
main.history.setLocation = (to, state) => {
- if (typeof to !== "string") {
- console.warn(`Invalid location`)
+ const lastLocation = main.history.lastLocation
+
+ if (typeof lastLocation !== "undefined" && lastLocation?.pathname === to && lastLocation?.state === state) {
return false
}
@@ -128,6 +142,7 @@ export const extension = {
main.history.push({
pathname: to,
}, state)
+ main.history.lastLocation = main.history.location
}, defaultTransitionDelay)
}
diff --git a/packages/app/src/extensions/sound/index.js b/packages/app/src/extensions/sound/index.js
index 0fa76258..b87908de 100644
--- a/packages/app/src/extensions/sound/index.js
+++ b/packages/app/src/extensions/sound/index.js
@@ -10,18 +10,20 @@ export class SoundEngine {
}
getSounds = async () => {
- const soundPack = await import(`http://${window.location.host}/src/assets/sounds`)
- let sounds = soundPack.default
+ const origin = process.env.NODE_ENV === "development" ? `${window.location.origin}/src/assets/sounds/index.js` : `${window.location.origin}/assets/sounds/index.js`
- Object.keys(soundPack.default).forEach((key) => {
- const src = `http://${window.location.host}${sounds[key]}`
+ let soundPack = await import(origin)
+ soundPack = soundPack.default || soundPack
- sounds[key] = new Howl({
+ Object.keys(soundPack).forEach((key) => {
+ const src = soundPack[key]
+
+ soundPack[key] = new Howl({
src: [src]
})
})
- return sounds
+ return soundPack
}
play = (name) => {
diff --git a/packages/app/src/extensions/splash/index.jsx b/packages/app/src/extensions/splash/index.jsx
index 1fa7e7b1..e5200e48 100644
--- a/packages/app/src/extensions/splash/index.jsx
+++ b/packages/app/src/extensions/splash/index.jsx
@@ -32,18 +32,21 @@ export const extension = (params = {}) => {
height: 100vh;
`
- document.body.appendChild(splashElement)
- ReactDOM.render(
, splashElement)
+ const show = () => {
+ document.body.appendChild(splashElement)
+ ReactDOM.render(
, splashElement)
+ }
const removeSplash = () => {
- splashElement.style.animation = `${params.preset ?? "fadeOut"} ${fadeOutVelocity ?? 1000}ms`
+ splashElement.style.animation = `${params.preset ?? "fadeOut"} ${fadeOutVelocity}ms`
setTimeout(() => {
splashElement.remove()
- }, fadeOutVelocity ?? 1000)
+ }, fadeOutVelocity)
}
- main.eventBus.on("initialization_done", removeSplash)
+ main.eventBus.on("splash_show", show)
+ main.eventBus.on("splash_close", removeSplash)
},
],
},
diff --git a/packages/app/src/extensions/splash/index.less b/packages/app/src/extensions/splash/index.less
index 6485a219..39c6b7d2 100644
--- a/packages/app/src/extensions/splash/index.less
+++ b/packages/app/src/extensions/splash/index.less
@@ -1,10 +1,12 @@
.splash_wrapper {
overflow: hidden;
- background-color: #f0f2f5;
+
+ background-color: rgba(240, 242, 245, 0.8);
+ backdrop-filter: blur(10px);
width: 100%;
height: 100%;
- z-index: 100;
+ z-index: 1000;
display: flex;
flex-direction: column;
@@ -13,7 +15,6 @@
justify-content: center;
}
-
.splash_logo {
width: 100%;
height: 100%;
@@ -28,7 +29,7 @@
width: fit-content;
max-width: 50%;
max-height: 50%;
- filter: drop-shadow(14px 10px 10px rgba(70, 70, 70, 0.5));
+ filter: drop-shadow(14px 10px 10px rgba(128, 128, 128, 0.5));
}
}
diff --git a/packages/app/src/extensions/theme/index.jsx b/packages/app/src/extensions/theme/index.jsx
index 40b7ff9c..fa94494d 100644
--- a/packages/app/src/extensions/theme/index.jsx
+++ b/packages/app/src/extensions/theme/index.jsx
@@ -1,53 +1,168 @@
-import React from "react"
import config from "config"
+import store from "store"
+import { ConfigProvider } from "antd"
-const themeConfig = config.theme ?? {}
-
-//themeConfig["primary-color"]
-
-const BaseThemeVars = {
- "primary-color": "#32b7bb",
-}
-
-class ThemeController {
+export class ThemeController {
constructor(params) {
this.params = { ...params }
- this.vars = Object()
- this.root = document.documentElement
- // init
- this.init()
+ this.themeManifestStorageKey = "theme"
+ this.modificationStorageKey = "themeModifications"
+ this.variantStorageKey = "themeVariation"
+
+ this.theme = null
+
+ this.mutation = null
+ this.currentVariant = null
+
+ this.init()
+
+ return this
}
- init = () => {
- Object.keys(BaseThemeVars).forEach(key => {
- this.updateVar(key, BaseThemeVars[key])
- })
- }
-
- updateVar = (key, value) => {
- return this.root.style.setProperty(`--${key}`, value)
+ static get currentVariant() {
+ return document.documentElement.style.getPropertyValue("--themeVariant")
}
- generate = (payload = {}) => {
- const { variables } = payload
+ init = () => {
+ let theme = this.getStoragedTheme()
+ const modifications = this.getStoragedModifications()
+ const variantKey = this.getStoragedVariant()
+
+ if (!theme) {
+ // load default theme
+ theme = this.getDefaultTheme()
+ } else {
+ // load URL and initialize theme
+ }
+
+ // set global theme
+ this.theme = theme
+
+ // override with static vars
+ if (theme.staticVars) {
+ this.update(theme.staticVars)
+ }
+
+ // override theme with modifications
+ if (modifications) {
+ this.update(modifications)
+ }
+
+ // apply variation
+ this.applyVariant(variantKey)
}
- load = (payload) => {
+ getRootVariables = () => {
+ let attributes = document.documentElement.getAttribute("style").trim().split(";")
+ attributes = attributes.slice(0, (attributes.length - 1))
+ attributes = attributes.map((variable) => {
+ let [key, value] = variable.split(":")
+ key = key.split("--")[1]
- }
+ return [key, value]
+ })
+
+ return Object.fromEntries(attributes)
+ }
+
+ getDefaultTheme = () => {
+ // TODO: Use evite CONSTANTS_API
+ return config.defaultTheme
+ }
+
+ getStoragedTheme = () => {
+ return store.get(this.themeManifestStorageKey)
+ }
+
+ getStoragedModifications = () => {
+ return store.get(this.modificationStorageKey)
+ }
+
+ getStoragedVariant = () => {
+ return store.get(this.variantStorageKey)
+ }
+
+ setVariant = (variationKey) => {
+ return store.set(this.variantStorageKey, variationKey)
+ }
+
+ setModifications = (modifications) => {
+ return store.set(this.modificationStorageKey, modifications)
+ }
+
+ resetDefault = () => {
+ store.remove(this.themeManifestStorageKey)
+ store.remove(this.modificationStorageKey)
+
+ return this.init()
+ }
+
+ update = (update) => {
+ if (typeof update !== "object") {
+ return false
+ }
+
+ this.mutation = {
+ ...this.theme.staticVars,
+ ...this.mutation,
+ ...update
+ }
+
+ Object.keys(this.mutation).forEach(key => {
+ document.documentElement.style.setProperty(`--${key}`, this.mutation[key])
+ })
+
+ document.documentElement.className = `theme-${this.currentVariant}`
+ document.documentElement.style.setProperty(`--themeVariant`, this.currentVariant)
+
+ ConfigProvider.config({ theme: this.mutation })
+ }
+
+ applyVariant = (variant = (this.theme.defaultVariant ?? "light")) => {
+ const values = this.theme.variants[variant]
+
+ if (values) {
+ this.currentVariant = variant
+ this.update(values)
+ this.setVariant(variant)
+ }
+ }
}
-export default {
+export const extension = {
key: "theme",
expose: [
{
initialization: [
async (app, main) => {
- app.themeController = new ThemeController()
- main.setToWindowContext("themeController", app.themeController)
+ app.ThemeController = new ThemeController()
+
+ main.eventBus.on("darkMode", (payload) => {
+ if (payload.to) {
+ app.ThemeController.applyVariant("dark")
+ } else {
+ app.ThemeController.applyVariant("light")
+ }
+ })
+ main.eventBus.on("modifyTheme", (payload) => {
+ if (payload.to) {
+ app.ThemeController.update(payload.to)
+ app.ThemeController.setModifications(app.ThemeController.mutation)
+ } else {
+ app.ThemeController.update(payload)
+ app.ThemeController.setModifications(app.ThemeController.mutation)
+ }
+ })
+ main.eventBus.on("resetTheme", () => {
+ app.ThemeController.resetDefault()
+ })
+
+ main.setToWindowContext("ThemeController", app.ThemeController)
},
],
},
],
}
+
+export default extension
\ No newline at end of file
diff --git a/packages/app/src/layout/drawer/index.jsx b/packages/app/src/layout/drawer/index.jsx
index 2fa978ba..bc5685f1 100644
--- a/packages/app/src/layout/drawer/index.jsx
+++ b/packages/app/src/layout/drawer/index.jsx
@@ -2,6 +2,8 @@ import React from "react"
import * as antd from "antd"
import EventEmitter from "@foxify/events"
+import "./index.less"
+
export class Drawer extends React.Component {
options = this.props.options ?? {}
events = new EventEmitter()
@@ -82,14 +84,18 @@ export class Drawer extends React.Component {
}
return (
-
-
- {React.createElement(this.props.children, componentProps)}
+
+
+
+ {React.createElement(this.props.children, componentProps)}
+
)
}
diff --git a/packages/app/src/layout/drawer/index.less b/packages/app/src/layout/drawer/index.less
new file mode 100644
index 00000000..122831cf
--- /dev/null
+++ b/packages/app/src/layout/drawer/index.less
@@ -0,0 +1,20 @@
+.drawer {
+ height: 100vh;
+ max-height: 100vh;
+
+ .header {
+ position: relative;
+ top: 0;
+ z-index: 100;
+ }
+ .body {
+ padding: 10px 30px;
+ height: fit-content;
+ width: 100%;
+ }
+}
+
+.ant-drawer-content, .ant-drawer-wrapper-body, .ant-drawer-body{
+ height: 100vh;
+ max-height: 100vh;
+}
\ No newline at end of file
diff --git a/packages/app/src/layout/header/index.jsx b/packages/app/src/layout/header/index.jsx
index b39b0ab7..e0f4c628 100644
--- a/packages/app/src/layout/header/index.jsx
+++ b/packages/app/src/layout/header/index.jsx
@@ -1,5 +1,6 @@
import React from "react"
import * as antd from "antd"
+import { Icons } from "components/Icons"
import { AppSearcher } from "components"
import classnames from "classnames"
@@ -23,12 +24,19 @@ export default class Header extends React.Component {
window.app["HeaderController"] = this.HeaderController
}
+ onClickCreate = () => {
+ window.app.openFabric()
+ }
+
render() {
return (
+
+
} style={{ display: "flex", alignItems: "center", justifyContent: "center" }} />
+
)
}
diff --git a/packages/app/src/layout/header/index.less b/packages/app/src/layout/header/index.less
index e295caac..ab61f932 100644
--- a/packages/app/src/layout/header/index.less
+++ b/packages/app/src/layout/header/index.less
@@ -13,10 +13,10 @@
transition: all ease-in-out 150ms;
- background: @app_header_background!important;
- background-color: @app_header_background!important;
+ background: var(--background-color-primary)!important;
+ background-color: var(--background-color-primary)!important;
- border-bottom: 1px @app_background_accent solid;
+ border-bottom: 1px var(--background-color-accent) solid;
> div {
margin-right: 16px;
diff --git a/packages/app/src/layout/sidebar/components/editor/index.jsx b/packages/app/src/layout/sidebar/components/editor/index.jsx
index dd8b9479..70e5c49c 100644
--- a/packages/app/src/layout/sidebar/components/editor/index.jsx
+++ b/packages/app/src/layout/sidebar/components/editor/index.jsx
@@ -1,7 +1,7 @@
import React from "react"
import { Button } from "antd"
import { ActionsBar } from "components"
-import { Icons, createIconRender } from "components/Icons"
+import { Icons, createIconRender } from "components/icons"
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"
import Selector from "../selector"
diff --git a/packages/app/src/layout/sidebar/components/selector/index.jsx b/packages/app/src/layout/sidebar/components/selector/index.jsx
index efceafd7..4b608a40 100644
--- a/packages/app/src/layout/sidebar/components/selector/index.jsx
+++ b/packages/app/src/layout/sidebar/components/selector/index.jsx
@@ -1,7 +1,7 @@
import React from "react"
import { Icons, createIconRender } from "components/Icons"
-import { LoadingSpinner, SelectableList } from "components"
-import { Button, List, Checkbox, InputNumber } from "antd"
+import { SelectableList } from "components"
+import { List } from "antd"
import sidebarItems from "schemas/sidebar.json"
diff --git a/packages/app/src/layout/sidebar/index.jsx b/packages/app/src/layout/sidebar/index.jsx
index dec3e12a..740e3f20 100644
--- a/packages/app/src/layout/sidebar/index.jsx
+++ b/packages/app/src/layout/sidebar/index.jsx
@@ -1,8 +1,7 @@
import React from "react"
-import { Icons, createIconRender } from "components/Icons"
+import { Icons, createIconRender } from "components/icons"
import { Layout, Menu, Avatar } from "antd"
-import { Settings } from "components"
import { SidebarEditor } from "./components"
import config from "config"
@@ -16,7 +15,7 @@ const { Sider } = Layout
const onClickHandlers = {
settings: (event) => {
- Settings.open()
+ window.app.openSettings()
},
}
@@ -48,6 +47,7 @@ export default class Sidebar extends React.Component {
}
window.app["SidebarController"] = this.SidebarController
+ window.app.eventBus.on("edit_sidebar", () => this.toogleEditMode())
}
collapseDebounce = null
@@ -214,9 +214,9 @@ export default class Sidebar extends React.Component {
}
toogleCollapse = (to) => {
- if(window.app.configuration?.settings.is("collapseOnLooseFocus", true) && !this.state.editMode ){
+ if (window.app.configuration?.settings.is("collapseOnLooseFocus", true) && !this.state.editMode) {
this.setState({ collapsed: to ?? !this.state.collapsed })
- }else {
+ } else {
this.setState({ collapsed: false })
}
}
@@ -232,8 +232,8 @@ export default class Sidebar extends React.Component {
handleMouseLeave = () => {
if (!this.state.collapsed) {
- this.collapseDebounce = setTimeout(() => {this.toogleCollapse(true)}, 500)
- }
+ this.collapseDebounce = setTimeout(() => { this.toogleCollapse(true) }, 500)
+ }
}
renderExtraItems = (position) => {
@@ -261,7 +261,7 @@ export default class Sidebar extends React.Component {
onMouseLeave={this.handleMouseLeave}
theme={this.props.theme}
width={this.state.editMode ? 400 : 200}
- collapsed={this.state.editMode? false : this.state.collapsed}
+ collapsed={this.state.editMode ? false : this.state.collapsed}
onCollapse={() => this.props.onCollapse()}
className={classnames("sidebar", { ["edit_mode"]: this.state.editMode, ["hidden"]: !this.state.visible })}
>
@@ -306,4 +306,4 @@ export default class Sidebar extends React.Component {
)
}
-}
+}
\ No newline at end of file
diff --git a/packages/app/src/layout/sidebar/index.less b/packages/app/src/layout/sidebar/index.less
index bd110e6f..aea78a89 100644
--- a/packages/app/src/layout/sidebar/index.less
+++ b/packages/app/src/layout/sidebar/index.less
@@ -2,12 +2,14 @@
// SIDEBAR
.ant-layout-sider {
- background: @app_sidebar_backgroundColor!important;
- background-color: @app_sidebar_backgroundColor!important;
+ background: var(--sidebar-background-color)!important;
+ background-color: var(--sidebar-background-color)!important;
border-radius: 0 @app_sidebar_borderRadius @app_sidebar_borderRadius 0;
overflow: hidden;
- border: 1px solid @app_sidebar_backgroundColor!important;
+ border: 1px solid var(--sidebar-background-color)!important;
+
+ transition: all 150ms ease-in-out;
&.hidden{
flex: 0!important;
diff --git a/packages/app/src/layout/sidedrawer/index.less b/packages/app/src/layout/sidedrawer/index.less
index 1a782ed9..7d7aec2a 100644
--- a/packages/app/src/layout/sidedrawer/index.less
+++ b/packages/app/src/layout/sidedrawer/index.less
@@ -3,7 +3,7 @@
.sidedrawer {
width: 30vw; // by default
- background-color: @app_sidebar_backgroundColor;
+ background-color: var(--sidedrawer-background-color);
border-radius: @app_sidebar_borderRadius 0 0 @app_sidebar_borderRadius;
word-break: break-all;
diff --git a/packages/app/src/models/index.js b/packages/app/src/models/index.js
index 466f2157..ffa18c12 100644
--- a/packages/app/src/models/index.js
+++ b/packages/app/src/models/index.js
@@ -1,2 +1,4 @@
export { default as Session } from './session'
-export { default as User } from './user'
\ No newline at end of file
+export { default as User } from './user'
+export { default as SidebarController } from './sidebar'
+export { default as SettingsController } from './settings'
\ No newline at end of file
diff --git a/packages/app/src/models/session/index.js b/packages/app/src/models/session/index.js
deleted file mode 100644
index 506e91e0..00000000
--- a/packages/app/src/models/session/index.js
+++ /dev/null
@@ -1,123 +0,0 @@
-import cookies from 'js-cookie'
-import jwt_decode from "jwt-decode"
-import config from 'config'
-
-export default class Session {
- static get bridge() {
- return window.app?.apiBridge
- }
-
- static tokenKey = config.app?.storage?.token ?? "token"
-
- static get token() {
- return cookies.get(this.tokenKey)
- }
-
- static set token(token) {
- return cookies.set(this.tokenKey, token)
- }
-
- static get decodedToken() {
- return this.token && jwt_decode(this.token)
- }
-
- //* BASIC HANDLERS
- login = (payload, callback) => {
- const body = {
- username: window.btoa(payload.username),
- password: window.btoa(payload.password),
- allowRegenerate: payload.allowRegenerate
- }
-
- return this.generateNewToken(body, (err, res) => {
- if (typeof callback === 'function') {
- callback(err, res)
- }
-
- if (!err || res.status === 200) {
- let token = res.data
-
- if (typeof token === 'object') {
- token = token.token
- }
-
- Session.token = token
- window.app.eventBus.emit("new_session")
- }
- })
- }
-
- logout = async () => {
- await this.destroyCurrentSession()
- this.forgetLocalSession()
- }
-
- //* GENERATORS
- generateNewToken = async (payload, callback) => {
- const request = await Session.bridge.post.login(payload, undefined, {
- parseData: false
- })
-
- if (typeof callback === 'function') {
- callback(request.error, request.response)
- }
-
- return request
- }
-
- regenerateToken = async () => {
- return await Session.bridge.post.regenerate()
- }
-
- //* GETTERS
- getAllSessions = async () => {
- return await Session.bridge.get.sessions()
- }
-
- getTokenInfo = async () => {
- const session = Session.token
-
- return await Session.bridge.post.validateSession({ session })
- }
-
- isCurrentTokenValid = async () => {
- const health = await this.getTokenInfo()
-
- return health.valid
- }
-
- forgetLocalSession = () => {
- cookies.remove(this.tokenKey)
- }
-
- destroyAllSessions = async () => {
- const session = Session.decodedToken
-
- if (!session) {
- return false
- }
-
- const result = await Session.bridge.delete.sessions({ user_id: session.user_id })
- this.forgetLocalSession()
- window.app.eventBus.emit("destroyed_session")
-
- return result
- }
-
- destroyCurrentSession = async () => {
- const token = Session.token
- const session = Session.decodedToken
-
- if (!session || !token) {
- return false
- }
-
- const result = await Session.bridge.delete.session({ user_id: session.user_id, token: token })
- this.forgetLocalSession()
- window.app.eventBus.emit("destroyed_session")
-
- return result
- }
-
- logout = this.destroyCurrentSession
-}
\ No newline at end of file
diff --git a/packages/app/src/models/user/index.js b/packages/app/src/models/user/index.js
index b3981324..e923f8b8 100644
--- a/packages/app/src/models/user/index.js
+++ b/packages/app/src/models/user/index.js
@@ -2,7 +2,7 @@ import Session from '../session'
export default class User {
static get bridge() {
- return window.app?.apiBridge
+ return window.app?.request
}
static get data() {
@@ -36,4 +36,14 @@ export default class User {
return request.response.data
}
+
+ hasAdmin = async () => {
+ const roles = await User.roles
+
+ if (!roles) {
+ return false
+ }
+
+ return Array.isArray(roles) && roles.includes("admin")
+ }
}
\ No newline at end of file
diff --git a/packages/app/src/pages/account/index.jsx b/packages/app/src/pages/account/index.jsx
index e55fd687..01052b84 100644
--- a/packages/app/src/pages/account/index.jsx
+++ b/packages/app/src/pages/account/index.jsx
@@ -2,7 +2,6 @@ import React from "react"
import * as antd from "antd"
import { Icons } from "components/Icons"
-import { Roles } from "components"
import { AccountEditor, SessionsView, StatisticsView } from "./components"
import { Session } from "models"
@@ -160,7 +159,9 @@ export default class Account extends React.Component {
>
}