Compare commits

..

No commits in common. "master" and "2806e8d88982979a71bcbd3f9c654910fd4c9af0" have entirely different histories.

106 changed files with 2 additions and 6781 deletions

View File

@ -1,3 +0,0 @@
dist
node_modules
public

View File

@ -1,13 +0,0 @@
{
"extends": [
"@antfu"
],
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "off",
"camelcase": "off"
},
"plugins": [
"snakecasejs"
]
}

21
LICENSE
View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020-2021 Jesús Pérez Lorenzo based in Anthony Fu developments
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,4 +1,4 @@
# Status interface for ZTerton services
# Status iterface for ZTerton services
<img style="margin-top: 1em;width: 500px;border: 0" alt="Fork me on GitHub" src="assets/images/status.svg?sanitize=true">

View File

@ -1 +0,0 @@
{"profile":{"image":"jesus.jpg"},"checkin":0,"sidebar":{"header":{"title":"Services Status"},"menu_items":[{"title":"app.title","icon_on":"carbon-campsite","name_to":"app.title","show_to":false,"click":"tophome","type":"app_link","pfx":""},{"title":"nav.Tasks","ctx":"home","icon_on":"carbon-services","name_to":"navm.Tasks","show_to":true,"click":"tsksrvcs","type":"app_link","pfx":""},{"title":"nav.Apps","ctx":"home","icon_on":"carbon-application","name_to":"navm.Apps","show_to":true,"click":"appsrvcs","type":"app_link","pfx":""},{"title":"nav.Informations","ctx":"home","icon_on":"carbon-operation","name_to":"navm.Infos","show_to":true,"click":"srvcstatus","type":"app_link","pfx":""}],"footer":{"itm":{"title":"menu.logout","name_to":"Logout","icon_on":"carbon-logout","type":"router_link"}}},"header":{"title":"Status","name_to":"Home","logo":"","navbar":{"menuright":{"notify":true,"search":true,"title":"menu.user","items":[{"title":"menu.your-profile","type":"app_link","click":"profile"},{"title":"menu.settings","type":"app_link","click":"user_settings"},{"title":"menu.sign-out","type":"router_link","name_to":"Logout"}]}}},"footer":{"left_items":[{"title":"LibreCloud © 2021","icon_on":"","href":"https://librecloud.online","type":"app_link"}],"right_items":[{"title":"LibreCloud","img":"app_w","href":"https://librecloud.online","type":"app_link"}],"central_items":[{"title":"button.home","mode":"icon","icon_on":"carbon-campsite","click":"tophome","type":"app_link","pfx":""},{"title":"button.toggle_dark","mode":"icon","icon_on":"carbon-moon","icon-off":"carbon-sun","vif":"isDark","click":"toggleDark","type":"app_link"},{"title":"button.toggle_langs","mode":"icon","icon_on":"carbon-language","click":"toggleLocales","type":"app_link"},{"title":"GitHub","mode":"icon","icon_on":"carbon-logo-github","href":"https://rlung.librecloud.online","type":"a_blank"},{"title":"button.about","mode":"icon","icon_on":"carbon-dicom-overlay","to":"/about","type":"router_link"},{"title":"button.login","mode":"icon","icon_on":"carbon-login","vif":"notValidUser","to":"/login","type":"router_link"}]}}

View File

@ -1,111 +0,0 @@
profile:
image: jesus.jpg
# checkin time in millisecond or 0 for not checkin
checkin: 0
# checkin: 60000
sidebar:
header:
title: Services Status
menu_items:
- title: app.title
icon_on: carbon-campsite
name_to: app.title
show_to: false
click: tophome
type: app_link
pfx: ''
- title: nav.Tasks
ctx: home
icon_on: carbon-services
name_to: navm.Tasks
show_to: true
click: tsksrvcs
type: app_link
pfx: ''
- title: nav.Apps
ctx: home
icon_on: carbon-application
name_to: navm.Apps
show_to: true
click: appsrvcs
type: app_link
pfx: ''
- title: nav.Informations
ctx: home
icon_on: carbon-operation
name_to: navm.Infos
show_to: true
click: srvcstatus
type: app_link
pfx: ''
footer:
itm:
title: menu.logout
name_to: Logout
icon_on: carbon-logout
type: router_link
header:
title: Status
name_to: Home
logo: ""
navbar:
menuright:
notify: true
search: true
title: menu.user
items:
- title: menu.your-profile
type: app_link
click: profile
- title: menu.settings
type: app_link
click: user_settings
- title: menu.sign-out
type: router_link
name_to: Logout
footer:
left_items:
- title: 'LibreCloud © 2021'
icon_on: ''
href: https://librecloud.online
type: app_link
right_items:
- title: 'LibreCloud'
img: 'app_w'
href: https://librecloud.online
type: app_link
central_items:
- title: button.home
mode: icon
icon_on: carbon-campsite
click: tophome
type: app_link
pfx: ''
- title: button.toggle_dark
mode: icon
icon_on: carbon-moon
icon-off: carbon-sun
vif: isDark
click: toggleDark
type: app_link
- title: button.toggle_langs
mode: icon
icon_on: carbon-language
click: toggleLocales
type: app_link
- title: GitHub
mode: icon
icon_on: carbon-logo-github
href: https://rlung.librecloud.online
type: a_blank
- title: button.about
mode: icon
icon_on: carbon-dicom-overlay
to: /about
type: router_link
- title: button.login
mode: icon
icon_on: carbon-login
vif: notValidUser
to: /login
type: router_link

View File

@ -1,12 +0,0 @@
<svg id="icon" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<defs>
<style>
.cls-1 {
fill: none;
}
</style>
</defs>
<path d="M25.8218,10.124a9.9991,9.9991,0,0,0-19.6435,0A7.4964,7.4964,0,0,0,7.5,25H8V23H7.5a5.4961,5.4961,0,0,1-.3769-10.9795l.8364-.0571.09-.8335a7.9979,7.9979,0,0,1,15.9013,0l.09.8335.8364.0571A5.4961,5.4961,0,0,1,24.5,23H24v2h.5a7.4964,7.4964,0,0,0,1.3218-14.876Z" transform="translate(0 0)"/>
<path d="M23,22V20H20.8989a4.9678,4.9678,0,0,0-.7319-1.7529l1.49-1.49-1.414-1.414-1.49,1.49A4.9678,4.9678,0,0,0,17,16.1011V14H15v2.1011a4.9678,4.9678,0,0,0-1.7529.7319l-1.49-1.49-1.414,1.414,1.49,1.49A4.9678,4.9678,0,0,0,11.1011,20H9v2h2.1011a4.9678,4.9678,0,0,0,.7319,1.7529l-1.49,1.49,1.414,1.414,1.49-1.49A4.9678,4.9678,0,0,0,15,25.8989V28h2V25.8989a4.9678,4.9678,0,0,0,1.7529-.7319l1.49,1.49,1.414-1.414-1.49-1.49A4.9678,4.9678,0,0,0,20.8989,22Zm-7,2a3,3,0,1,1,3-3A3.0033,3.0033,0,0,1,16,24Z" transform="translate(0 0)"/>
<rect id="_Transparent_Rectangle_" data-name="&lt;Transparent Rectangle&gt;" class="cls-1" width="32" height="32"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.0 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.7 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -1 +0,0 @@
cat defs.yaml | yq e -o=json | jq -cr > defs.json

172
auto-imports.d.ts vendored
View File

@ -1,172 +0,0 @@
// Generated by 'unplugin-auto-import'
// We suggest you to commit this file into source control
declare global {
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
const biSyncRef: typeof import('@vueuse/core')['biSyncRef']
const computed: typeof import('vue')['computed']
const computedInject: typeof import('@vueuse/core')['computedInject']
const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
const controlledRef: typeof import('@vueuse/core')['controlledRef']
const createApp: typeof import('vue')['createApp']
const createEventHook: typeof import('@vueuse/core')['createEventHook']
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable']
const customRef: typeof import('vue')['customRef']
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
const extendRef: typeof import('@vueuse/core')['extendRef']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const h: typeof import('vue')['h']
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
const inject: typeof import('vue')['inject']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onClickOutside: typeof import('@vueuse/core')['onClickOutside']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onStartTyping: typeof import('@vueuse/core')['onStartTyping']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
const provide: typeof import('vue')['provide']
const reactify: typeof import('@vueuse/core')['reactify']
const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
const reactive: typeof import('vue')['reactive']
const reactivePick: typeof import('@vueuse/core')['reactivePick']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const syncRef: typeof import('@vueuse/core')['syncRef']
const templateRef: typeof import('@vueuse/core')['templateRef']
const throttledWatch: typeof import('@vueuse/core')['throttledWatch']
const toRaw: typeof import('vue')['toRaw']
const toReactive: typeof import('@vueuse/core')['toReactive']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const triggerRef: typeof import('vue')['triggerRef']
const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount']
const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted']
const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose']
const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted']
const unref: typeof import('vue')['unref']
const unrefElement: typeof import('@vueuse/core')['unrefElement']
const until: typeof import('@vueuse/core')['until']
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
const useAttrs: typeof import('vue')['useAttrs']
const useBattery: typeof import('@vueuse/core')['useBattery']
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
const useClipboard: typeof import('@vueuse/core')['useClipboard']
const useCounter: typeof import('@vueuse/core')['useCounter']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVar: typeof import('@vueuse/core')['useCssVar']
const useDark: typeof import('@vueuse/core')['useDark']
const useDebounce: typeof import('@vueuse/core')['useDebounce']
const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory']
const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn']
const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion']
const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation']
const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio']
const useDevicesList: typeof import('@vueuse/core')['useDevicesList']
const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility']
const useDraggable: typeof import('@vueuse/core')['useDraggable']
const useElementBounding: typeof import('@vueuse/core')['useElementBounding']
const useElementSize: typeof import('@vueuse/core')['useElementSize']
const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility']
const useEventBus: typeof import('@vueuse/core')['useEventBus']
const useEventListener: typeof import('@vueuse/core')['useEventListener']
const useEventSource: typeof import('@vueuse/core')['useEventSource']
const useFavicon: typeof import('@vueuse/core')['useFavicon']
const useFetch: typeof import('@vueuse/core')['useFetch']
const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
const useHead: typeof import('@vueuse/head')['useHead']
const useI18n: typeof import('vue-i18n')['useI18n']
const useIdle: typeof import('@vueuse/core')['useIdle']
const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver']
const useInterval: typeof import('@vueuse/core')['useInterval']
const useIntervalFn: typeof import('@vueuse/core')['useIntervalFn']
const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier']
const useLastChanged: typeof import('@vueuse/core')['useLastChanged']
const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage']
const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys']
const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory']
const useMediaControls: typeof import('@vueuse/core')['useMediaControls']
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
const useMouse: typeof import('@vueuse/core')['useMouse']
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
const useMousePressed: typeof import('@vueuse/core')['useMousePressed']
const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver']
const useNetwork: typeof import('@vueuse/core')['useNetwork']
const useNow: typeof import('@vueuse/core')['useNow']
const useOnline: typeof import('@vueuse/core')['useOnline']
const usePageLeave: typeof import('@vueuse/core')['usePageLeave']
const useParallax: typeof import('@vueuse/core')['useParallax']
const usePermission: typeof import('@vueuse/core')['usePermission']
const usePointer: typeof import('@vueuse/core')['usePointer']
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
const useRafFn: typeof import('@vueuse/core')['useRafFn']
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
const useScroll: typeof import('@vueuse/core')['useScroll']
const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage']
const useShare: typeof import('@vueuse/core')['useShare']
const useSlots: typeof import('vue')['useSlots']
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
const useStorage: typeof import('@vueuse/core')['useStorage']
const useSwipe: typeof import('@vueuse/core')['useSwipe']
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
const useThrottle: typeof import('@vueuse/core')['useThrottle']
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo']
const useTimeout: typeof import('@vueuse/core')['useTimeout']
const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn']
const useTimestamp: typeof import('@vueuse/core')['useTimestamp']
const useTitle: typeof import('@vueuse/core')['useTitle']
const useToggle: typeof import('@vueuse/core')['useToggle']
const useTransition: typeof import('@vueuse/core')['useTransition']
const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams']
const useUserMedia: typeof import('@vueuse/core')['useUserMedia']
const useVirtualList: typeof import('@vueuse/core')['useVirtualList']
const useVModel: typeof import('@vueuse/core')['useVModel']
const useVModels: typeof import('@vueuse/core')['useVModels']
const useWakeLock: typeof import('@vueuse/core')['useWakeLock']
const useWebSocket: typeof import('@vueuse/core')['useWebSocket']
const useWebWorker: typeof import('@vueuse/core')['useWebWorker']
const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn']
const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus']
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
const watch: typeof import('vue')['watch']
const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
const watchEffect: typeof import('vue')['watchEffect']
const watchOnce: typeof import('@vueuse/core')['watchOnce']
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
const whenever: typeof import('@vueuse/core')['whenever']
}
export {}

34
components.d.ts vendored
View File

@ -1,34 +0,0 @@
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/vue-next/pull/3399
declare module 'vue' {
export interface GlobalComponents {
AccordionView: typeof import('./src/components/AccordionView.vue')['default']
AppImg: typeof import('./src/components/icons/AppImg.vue')['default']
AppLogoText: typeof import('./src/components/icons/AppLogoText.vue')['default']
AppLogoV: typeof import('./src/components/icons/AppLogoV.vue')['default']
CarbonCampsite: typeof import('~icons/carbon/campsite')['default']
CarbonCheck: typeof import('~icons/carbon/check')['default']
CarbonCheckmark: typeof import('~icons/carbon/checkmark')['default']
CarbonLanguage: typeof import('~icons/carbon/language')['default']
CarbonLogin: typeof import('~icons/carbon/login')['default']
CarbonLogoGithub: typeof import('~icons/carbon/logo-github')['default']
CarbonLogout: typeof import('~icons/carbon/logout')['default']
CarbonMoon: typeof import('~icons/carbon/moon')['default']
CarbonPedestrian: typeof import('~icons/carbon/pedestrian')['default']
CarbonScript: typeof import('~icons/carbon/script')['default']
CarbonSearch: typeof import('~icons/carbon/search')['default']
CarbonSun: typeof import('~icons/carbon/sun')['default']
CarbonWarning: typeof import('~icons/carbon/warning')['default']
CloudGroups: typeof import('./src/components/CloudGroups.vue')['default']
CloudServices: typeof import('./src/components/CloudServices.vue')['default']
CloudSrvc: typeof import('./src/components/CloudSrvc.vue')['default']
Footer: typeof import('./src/components/Footer.vue')['default']
MenuLocales: typeof import('./src/components/menus/MenuLocales.vue')['default']
NavMenu: typeof import('./src/components/NavMenu.vue')['default']
ProfileView: typeof import('./src/components/ProfileView.vue')['default']
}
}
export { }

View File

@ -1,26 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<title>Vitesse Lite</title>
<meta name="description" content="Opinionated Vite Starter Template">
</head>
<body>
<div id="app"></div>
<script>
(function() {
// window.ROOT_LOCATION='https://10.11.5.1'
// window.ROOT_LOCATION='https://status.librecloud.online'
// window.ROOT_LOCATION='https://localhost:8302'
window.ROOT_LOCATION='https://localhost:8302'
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
const setting = localStorage.getItem('color-schema') || 'auto'
if (setting === 'dark' || (prefersDark && setting !== 'light'))
document.documentElement.classList.toggle('dark', true)
})()
</script>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@ -1,7 +0,0 @@
## i18n
This directory is to serve your locale translation files. YAML under this folder would be loaded automatically and register with their filenames as locale code.
Check out [`vue-i18n`](https://github.com/intlify/vue-i18n-next) for more details.
If you are using VS Code, [`i18n Ally`](https://github.com/lokalise/i18n-ally) is recommended to make the i18n experience better.

View File

@ -1,151 +0,0 @@
All: All
auth:
invalidcredentials: Invalid credentials
loginForm: ''
newaccount: new account
password: password
register: Register
signin: Sign in
subHeading: Login info
subTitle: ''
wellcome: Wellcome !
bc:
home: librecloud
topographic_anatomy: klouds
bm:
topographic-anatomy: Topographic Anatomy
button:
about: About
back: Back
cancel: Cancel
close-panel: Close panel
delete: Delete
go: Go
home: Home
new: Nuevo
reset: Reset
save: Save
toggle_dark: Toggle dark mode
toggle_langs: Change language
login: Login
logout: Logout
connection:
error: Error conexión
dashboard: Dashboard
en: English
entry:
Apps: Apps
Code: Code
DB: DB
Data: Data
DataCode: Data / Code
Document: Document
Documents: Documents
Macro: Macro
Profiles: Profiles/roles
Schema: Schema
Services: Services
Shortcut: Shortcut
Template: Template
Trans: Translations
es: Español
form:
delete_done: Delete done
delete_error: Delete Error
save_done: Data saved
save_error: Data save Error
intro:
desc: Opinionated Vite Starter Template
dynamic-route: Demo of dynamic route
hi: Hi, {name}!
whats-your-name: What's your name?
login:
end_session: End session
form: Credentials
invalidcredentials: Incorrect data
newuser: New user
nodata: No data
password: Password
register: Register
reset: Reset
see_you_soon: See You soon !
signin: Signin
subHeading: Access
subtitle: LibreCloud online
user_email: User / email
wellcome: Wellcome
menu:
copy: Copy
data-grid: Data Grid
edit: Edit
edit-items: Edit items
home: Home
login: Init session
logout: Close session
new: New
open-recent: Open recent
paste: Paste
save: Save
settings: Configuration
sign-in: Signin
sign-out: Signout
your-profile: Your profile
message:
loadding: Loading
not-found: Not found
notes: Notes
notifications:
content: content
notifications: Notifications
search:
search: Search
settings:
above-noedit: ALL above options in "off" configure mode for
aside: Aside
col: Col
columns-settings: Columns
filter: Filter
grid: Grid
grid-options: Grid options
hidden: Hide
id: Id
list: List
main: Main
no-edition: no edition
pagination: Pagination
panels: Panels
pos: Pos
position: position
select: Select
select-config: Select configuration
select-grid-type: Select grid type
setting-id: Identificator
settings: Configuration
slide: Modal
sort: Sort
table: Table
undefined: Undefined
srvc:
mailserver::smtp::imap: mail imap
mailserver::smtp::pop: mail pop
mailserver::smtp::tls: mail tls
mailserver::smtp: mail smtp
pending: Pendiente
nav:
Services Status: Services Status Servicios
Tasks: Services
Search: Search
Apps: Applications
Informations: Informations
navm:
Infos: Infos
Status: Status
Tasks: Serv.
Apps: Aplic.
app:
title: Status
profile:
Close: Close
Settings: Settings
backgroud_color: Background color
Logout: Logout

View File

@ -1,155 +0,0 @@
All: All
auth:
invalidcredentials: Invalid credentials
loginForm: ''
newaccount: new account
password: password
register: Register
signin: Sign in
subHeading: Login info
subTitle: ''
wellcome: Wellcome !
bc:
home: librecloud
topographic_anatomy: klouds
bm:
topographic-anatomy: Anatomía topográfica
button:
about: Acerca de
back: Atrás
cancel: Cancelar
close-panel: Cerarr panel
delete: Borrar
go: Ir
home: Inicio
new: Nuevo
reset: Reset
save: Guardar
toggle_dark: Alternar modo oscuro
toggle_langs: Cambiar idiomas
login: Login
logout: Desconectar
connection:
error: Error conexión
dashboard: Panel de control
en: English
entry:
Apps: Apps
Code: Code
DB: DB
Data: Data
DataCode: Data / Code
Document: Document
Documents: Documents
Macro: Macro
Profiles: Profiles/roles
Schema: Schema
Services: Services
Shortcut: Shortcut
Template: Template
Trans: Translations
es: Español
form:
delete_done: Borrado realizado
delete_error: Error al borrar datos
save_done: Datos guardados
save_error: Error al guardar datos
intro:
desc: Plantilla de Inicio de Vite Dogmática
dynamic-route: Demo de ruta dinámica
hi: ¡Hola, {name}!
whats-your-name: ¿Cómo te llamas?
login:
end_session: Sesión finalizada
form: Credenciales
invalidcredentials: Datos incorrectos
newuser: Nuevo usuario
nodata: No hay datos
password: Password
register: Registrarse
reset: Reset
see_you_soon: ¡ Nos vemos pronto !
signin: Iniciar sesión
subHeading: Acceso
subtitle: LibreCloud online
user_email: Usuario / email
wellcome: Bienvenido/a
menu:
copy: Copiar
data-grid: Cuadrícula de datos
edit: Editar
edit-items: Editar items
home: Inicio
login: Inicio sesión
logout: Cerrar sesión
new: Nuevo
open-recent: Abrir reciente
paste: Pegar
save: Guardar
settings: Configuración
sign-in: Registrarse
sign-out: Desconectar
your-profile: Tu perfil
message:
loadding: Cargando
not-found: No se ha encontrado
notes: Notas
notifications:
content: contenido
notifications: Notificiaciones
search:
search: Buscar
settings:
above-noedit: TODAS las opciones de arriba en "off" configuran el modo
aside: Al lado
col: Col
columns-settings: Columnas
filter: Filtrar
grid: Cuadrícula
grid-options: Opciones cuadrícula
hidden: Ocultar
id: Id
list: Lista
main: Principal
no-edition: no edición
pagination: Paginación
panels: Paneles
pos: Pos
position: posición
select: Seleccionar
select-config: Seleccionar configuración
select-grid-type: Seleccionar tipo cuadrícula
setting-id: Identificador
settings: Configuración
slide: Modal
sort: Ordenar
table: Tabla
undefined: No definido
graphsettings:
clouds: Clouds
groups: Grupos
srvc:
mailserver::smtp::imap: correo imap
mailserver::smtp::pop: correo pop
mailserver::smtp::tls: correo tls
mailserver::smtp: correo smtp
pending: Pending
nav:
Informations: Informaciones
Services Status: Status Servicios
Tasks: Servicios
Applications: Aplicaciones
Apps: Aplicaciones
Search: Buscar
navm:
Infos: Infos
Status: Status
Tasks: Serv.
Apps: Aplic.
app:
title: Status
profile:
Close: Cerrar
Settings: Configuración
backgroud_color: Color de fondo
Logout: Desconectar

View File

@ -1,17 +0,0 @@
[build.environment]
NPM_FLAGS = "--prefix=/dev/null"
NODE_VERSION = "14"
[build]
publish = "dist"
command = "npx pnpm i --store=node_modules/.pnpm-store && npx pnpm run build"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[[headers]]
for = "/manifest.webmanifest"
[headers.values]
Content-Type = "application/manifest+json"

View File

@ -1,50 +0,0 @@
{
"private": true,
"scripts": {
"dev": "vite --port 3333 --open",
"build": "cross-env NODE_ENV=production vite build --debug",
"preview": "vite preview"
},
"dependencies": {
"@animxyz/vue": "^0.6.4",
"@headlessui/vue": "^1.4.1",
"@intlify/vite-plugin-vue-i18n": "^2.4.0",
"@vueuse/core": "^6.6.2",
"@vueuse/head": "^0.6.0",
"a17t": "^0.5.1",
"nprogress": "^0.2.0",
"toastify-js": "^1.11.2",
"vite-imagetools": "^3.8.0",
"vite-plugin-inspect": "^0.3.9",
"vue": "^3.2.20",
"vue-demi": "^0.11.4",
"vue-i18n": "^9.1.9",
"vue-router": "^4.0.12",
"vuex": "^4.0.2"
},
"devDependencies": {
"@antfu/eslint-config": "^0.9.0",
"@iconify-json/carbon": "^1.0.7",
"@types/node": "^16.11.1",
"@vitejs/plugin-vue": "^1.9.3",
"cross-env": "^7.0.3",
"eslint": "^7.32.0",
"pnpm": "^6.18.0",
"typescript": "^4.4.4",
"unplugin-auto-import": "^0.4.12",
"unplugin-icons": "^0.12.16",
"unplugin-vue-components": "^0.15.6",
"vite": "^2.6.10",
"vite-plugin-md": "^0.11.2",
"vite-plugin-pages": "^0.18.1",
"vite-plugin-vue-layouts": "^0.5.0",
"vite-plugin-windicss": "^1.4.12"
},
"eslintConfig": {
"extends": "@antfu/eslint-config",
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "off"
}
}
}

View File

@ -1,9 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<style>
path { fill: #222; }
@media (prefers-color-scheme: dark) {
path { fill: #ffffff; }
}
</style>
<path d="M27.562 26L17.17 8.928l2.366-3.888L17.828 4L16 7.005L14.17 4l-1.708 1.04l2.366 3.888L4.438 26H2v2h28v-2zM16 10.85L25.22 26H17v-8h-2v8H6.78z" />
</svg>

Before

Width:  |  Height:  |  Size: 347 B

View File

@ -1,2 +0,0 @@
User-agent: *
Allow: /

View File

@ -1,37 +0,0 @@
<template>
<component :is="layout" class="text-gray-700 dark:text-gray-200">
<router-view />
</component>
</template>
<script setup lang="ts">
// <Footer />
import { computed } from 'vue'
import { useRouter } from 'vue-router'
import { useStore } from 'vuex'
import { AppDefsAction } from '~/store/types'
// import AppLayout from '~/layouts/AppLayout.vue'
import { useHead } from '@vueuse/head'
// https://github.com/vueuse/head
// you can use this to manipulate the document head in any components,
// they will be rendered correctly in the html results with vite-ssg
import defs from '../assets/defs.json'
const store = useStore()
useHead({
title: 'Status',
meta: [
{ name: 'description', content: 'Opinionated Vite Starter Template' },
],
})
const { currentRoute } = useRouter()
const appLayout = 'AppLayout'
const layout = computed(() => {
return `${currentRoute.value.meta.layout || appLayout}`
})
onBeforeMount(() => {
if (defs) {
store.dispatch(AppDefsAction.addDefs, { key: 'ui', defs })
}
})
</script>

View File

@ -1,46 +0,0 @@
<script setup lang="ts">
import { StatusItemType } from '~/typs/clouds'
const props = defineProps<{
items: Array<StatusItemType>
title: string
}>()
const items = ref(props.items as Array<StatusItemType>)
const on_item = (it: any) => {
items.value = items.value.map((i: StatusItemType) => ({ ...i, isOpen: i.title !== it.title ? false : !i.isOpen }))
}
</script>
<template>
<div class="container mx-auto px-2 py-2">
<div id="srvcstatus" class="text-3xl bg-light-500 p-3 rounded-xl">
{{ props.title }}
</div>
<div class="leading-loose text-lg mt-6">
<div v-for="item in items" :key="item.title">
<div>
<button
class="w-full font-bold border-b border-gray-400 py-3 flex justify-between items-center mt-4"
@click="on_item(item)"
>
<!-- Specs has it that only one component can be open at a time and also you should be able to toggle the open state of the active component too -->
<div>{{ item.title }}</div>
<svg v-show="!item.isOpen" class="fill-current" viewBox="0 0 24 24" width="24" height="24">
<path
class="heroicon-ui"
d="M12 22a10 10 0 110-20 10 10 0 010 20zm0-2a8 8 0 100-16 8 8 0 000 16zm1-9h2a1 1 0 010 2h-2v2a1 1 0 01-2 0v-2H9a1 1 0 010-2h2V9a1 1 0 012 0v2z"
/>
</svg>
<svg v-show="item.isOpen" class="fill-current" viewBox="0 0 24 24" width="24" height="24">
<path
class="heroicon-ui"
d="M12 22a10 10 0 110-20 10 10 0 010 20zm0-2a8 8 0 100-16 8 8 0 000 16zm4-8a1 1 0 01-1 1H9a1 1 0 010-2h6a1 1 0 011 1z"
/>
</svg>
</button>
<div v-show="item.isOpen" class="text-gray-700 text-sm mt-2">
{{ item.text }}
</div>
</div>
</div>
</div>
</div>
</template>

View File

@ -1,115 +0,0 @@
<template>
<div class="breadcrump-box transition duration-300 ease-in-out py-3 ">
<div class="card-body">
<nav aria-label="breadcrumb" class="flex flex-wrap">
<ul v-for="(itm,i) in arrBcPath" :key="`bread-${i}`" class="breadcrumb">
<li v-if="i == 0 && itm[0] == '#'" class="breadcrumb-item flex-1 cursor-pointer" @click="bookselec(itm[i])">
<span class="shield">
<span class="icon">
<svg
v-if="itm === '#fa-cloud'"
aria-hidden="true"
focusable="false"
data-prefix="fas"
data-icon="cloud"
class="svg-inline--fa fa-cloud fa-w-16 dark:text-white text-blue-400"
role="img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 640 512"
><path fill="currentColor" d="M537.6 226.6c4.1-10.7 6.4-22.4 6.4-34.6 0-53-43-96-96-96-19.7 0-38.1 6-53.3 16.2C367 64.2 315.3 32 256 32c-88.4 0-160 71.6-160 160 0 2.7.1 5.4.2 8.1C40.2 219.8 0 273.2 0 336c0 79.5 64.5 144 144 144h368c70.7 0 128-57.3 128-128 0-61.9-44-113.6-102.4-125.4z"></path></svg>
<svg
v-if="itm === '#fa-book'"
aria-hidden="true"
focusable="false"
data-prefix="fad"
data-icon="book-reader"
class="svg-inline--fa fa-book-reader fa-w-16 dark:text-white"
role="img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
><g class="fa-group"><path class="fa-secondary" fill="currentColor" d="M256 192a96 96 0 1 1 96-96 96 96 0 0 1-96 96z" opacity="0.4" /><path class="fa-primary" fill="currentColor" d="M233.59 241.1c-59.33-36.32-155.43-46.3-203.79-49C13.55 191.13 0 203.51 0 219.14v222.8c0 14.33 11.59 26.28 26.49 27.06 43.66 2.29 132 10.68 193 41.43 9.37 4.72 20.48-1.71 20.48-11.87v-246a13.31 13.31 0 0 0-6.38-11.46zm248.61-49c-48.35 2.74-144.46 12.73-203.78 49a13.56 13.56 0 0 0-6.42 11.63v245.79c0 10.19 11.14 16.63 20.54 11.9 61-30.72 149.32-39.11 193-41.4C500.42 468.24 512 456.29 512 442V219.14c0-15.63-13.55-28.01-29.8-27.09z" /></g></svg>
<span v-else class="iconify" :data-icon="itm.replace('#','').replace('fa-','fa:')" />
</span>
</span>
<span class="slash text-xs">/</span>
</li>
<li v-else-if="arrBcPath[i+1]" class="breadcrumb-item flex-1 cursor-pointer">
<a href="#{itm}" class="mx-1 leading-tight text-xs" @click="(e) => { e.preventDefault(); $router.push(`/${itm}`)}">
{{ translate(itm) }}</a>
<span class="slash text-xs">/</span>
</li>
<li v-else class="breadcrumb-item active flex-1 mx-1 ml-1 leading-tight text-xs cursor-pointer" aria-current="page">
<span style="line-height: 2.2em" @click="bookselec(itm)"> {{ translate(itm) }} </span>
</li>
</ul>
</nav>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
const props = defineProps({
bcPath: {
type: String,
default: '',
},
})
const emit = defineEmits(['onBookSelec'])
// const currAppTab = ref('')
const arrBcPath = computed(() => props.bcPath.split('/'))
const bookselec = (book: any) => {
emit('onBookSelec', book)
}
const { t, locale } = useI18n()
const translate = (txt: any) => {
const tr_txt = t(`bc.${txt}`)
return tr_txt === `bc.${txt}` ? txt : tr_txt
}
// $: arrBcPath=bcPath.split("/");
// const bookselec = (e) => {
// dispatch("bookselec","main");
// // console.log(`mode: ${mode} id: ${id} target: ${target}`);
// const parent=".tabs-menu";
// document.querySelectorAll(`${parent} span`).forEach(it => it.classList.remove('active') )
// // e.target.parentElement.childNodes.forEach(it => it.classList.remove('active') )
// // e.target.classList.add('active')
// document.querySelectorAll(`${parent} span`).forEach(it => it.classList.remove('active') )
// document.querySelectorAll(`${parent} span.itm-${id}`).forEach(it => it.classList.add('active') )
// dispatch("choosetab",id);
// //const tab=document.querySelector(`#${currTab}`);
// //if (tab) { }
// }
</script>
<style scoped>
.breadcrumb-item .shield {
padding: 0em 0.5em;
/* margin-top: -0.4em; */
}
.breadcrumb-item .icon {
padding: 0em;
margin: 0;
}
.breadcrumb-item .icon svg {
width: 100%;
}
.breadcrumb .breadcrumb-item {
position: relative;
}
.breadcrumb-item a:hover {
padding-bottom: 0.2em;
border-bottom: 1px solid rgb(154, 154, 154);
border-bottom-width: thin;
border-bottom-style: dashed;
}
/*
.breadcrumb .breadcrumb-item:first-child {
margin-left: 0 !important;
}
*/
.breadcrumb .breadcrumb-item:not(:last-child):after {
content: '/';
color: rgb(154, 154, 154);
}
</style>

View File

@ -1,61 +0,0 @@
<template>
<div :id="props.target" class="border-t-gray-800 border-opacity-90 bg-light-600 dark:bg-gray-600 w-full p-4 mt-4 md:mt-2 rounded-l">
<div class="flex flex justify-between text-2xl bg-light-800 dark:bg-gray-400 p-3 rounded-xl" @click="on_group_item(props.target,$event)">
<div class="dark:text-white"> {{ props.title }} </div>
<svg v-show="props.hide" class="fill-current" viewBox="0 0 24 24" width="24" height="24">
<path
class="heroicon-ui"
d="M12 22a10 10 0 110-20 10 10 0 010 20zm0-2a8 8 0 100-16 8 8 0 000 16zm1-9h2a1 1 0 010 2h-2v2a1 1 0 01-2 0v-2H9a1 1 0 010-2h2V9a1 1 0 012 0v2z"
/>
</svg>
<svg v-show="!props.hide" class="fill-current" viewBox="0 0 24 24" width="24" height="24">
<path
class="heroicon-ui"
d="M12 22a10 10 0 110-20 10 10 0 010 20zm0-2a8 8 0 100-16 8 8 0 000 16zm4-8a1 1 0 01-1 1H9a1 1 0 010-2h6a1 1 0 011 1z"
/>
</svg>
</div>
<div v-for="[grp_key, grp_value] in props.groups" :key="grp_key" class="mt-3" :class="{ 'hidden' : props.hide }">
<div
v-for="[subgrp_key,subgrp_value] in grp_value"
:key="subgrp_key"
>
<div
v-for="(srvr,srvrindex) in subgrp_value"
:key="srvrindex"
class="flex flex-wrap -mx-2 pb-8"
>
<CloudServices
:source="props.target === 'tsksrvcs' ? srvr.tsksrvcs : srvr.appsrvcs"
:target="props.target"
:filter="props.search"
:hostname="srvr.hostname"
@on-cloud-server-item="onCloudServiceItem"
/>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { CloudGroupServcType,SrvcInfoType } from '~/typs/clouds'
const props = defineProps<{
groups: Map<string, Map<string, CloudGroupServcType>>
search: string
target: string
title: string
hide: boolean
}>()
const emit = defineEmits(['onCloudGroup'])
const on_group_item = (target: string, event: Event) => {
event.preventDefault()
event.stopImmediatePropagation()
event.stopPropagation()
emit('onCloudGroup', target)
}
const onCloudServiceItem = (item: SrvcInfoType) => {
if (item) {
// console.log(item)
}
}
</script>

View File

@ -1,134 +0,0 @@
<template>
<div class="shape-wrapper flex flex-wrap xyz-in" xyz="fade flip-up flip-left" v-if="props.source && props.source.length > 0">
<div
v-for="(item ,srvcindex) in props.source"
:key="`grp_${srvcindex}`"
class="shape w-1/2 md:w-1/4 lg:w-1/6 xl:w-1/7 font-light dark:bg-gray-200 bg-gray-300"
:class="{hidden: !filter_item(item)}"
@click="on_item(item,$event)"
>
<div
class="flex bg-white dark:bg-gray-300 rounded-lg shadow-md m-2 border-l-4 border-gray-500 dark:border-gray-500 hover:shadow-2xl hover:border-pink-500 cursor-pointer relative"
>
<div class=" p-4 pr-6 leading-normal">
<div class="font-medium text-xl truncate">
{{ item.name }}
</div>
<div
class="truncate text-xs text-gray-500 font-semibold pt-1 pb-2 tracking-widest"
v-html="map_srvc_target(item.srvc.target)"
>
</div>
<div class="flex font-medium">
<div v-if="authData.auth !== ''" class="flex-grow text-gray-400">
{{ item.srvc.req || 'tcp' }}
</div>
<div
class="flex-grow-0"
:class="{ 'text-indigo-500' : item.info === 'ok' , 'text-red-600' : item.info !== 'ok' && item.srvc.critical === CriticalType.yes, 'text-green-500': item.info !== 'ok' && item.srvc.critical !== CriticalType.yes}"
>
<span v-if="item.info === 'ok'" class="text-2xl">
<carbon-checkmark class="align-bottom" />
</span>
<span v-else class="ml-3">
<span v-if="authData.auth === '' && (item.srvc.critical === CriticalType.ifresized || item.srvc.critical === CriticalType.cloud) ">
{{ item.info }} <span class="ml-3">{{ t('srvc.pending','pending')}}</span>
</span>
<span v-else>
{{ item.info }} <span v-if="item.srvc.critical !== CriticalType.yes" class="ml-3">{{ item.srvc.critical }}</span>
</span>
</span>
</div>
</div>
<div v-if="authData.auth !== ''" class="flex mt-2 font-medium">
<div v-if="item.srvc.path" class="flex-grow-0 text-1xl text-blue-600 hover:text-blue-700 mr-2 block" :data="item.srvc.path">
<carbon-script class="inline-block" />
</div>
<div v-if="item.srvc.liveness" class="flex-grow text-xs text-blue-600 hover:text-blue-700 block" :data="item.srvc.liveness">
{{ item.srvc.liveness }}
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {
SrvcInfoType,
CriticalType,
} from '~/typs/clouds'
import { auth_data } from '~/hooks/utils'
const { t } = useI18n()
let shapWrapper = document.querySelector(".shape-wrapper");
const props = defineProps<{
source: SrvcInfoType[]
hostname: string
target: string
filter: string
}>()
const emit = defineEmits(['onCloudServiceItem'])
const on_item = (item: SrvcInfoType, event: Event) => {
event.preventDefault()
event.stopImmediatePropagation()
event.stopPropagation()
emit('onCloudServiceItem', item)
}
const authData = auth_data()
// TODO review https://medium.com/@KevinBGreene/typescript-enums-and-polymorphism-with-type-matching-fc3dc74b031c
const critical_matches = (val: CriticalType, match: string): boolean => {
switch (match) {
case 'yes':
return val === CriticalType.yes
case 'no':
return val === CriticalType.no
case 'cloud':
return val === CriticalType.cloud
case 'group':
return val === CriticalType.group
case 'ifresized':
return val === CriticalType.ifresized
default:
return false
}
}
const map_srvc_target = (srvc_target: string): string => {
return srvc_target ? srvc_target.replace('::','<br>') : (authData.auth !== '' && props.hostname || '')
}
const filter_item = (item: SrvcInfoType): boolean => {
if (authData.auth !== '')
return props.filter === '' || item.name.includes(props.filter) || item.srvc.target.includes(props.filter)
|| item.srvc.liveness.includes(props.filter) || item.info.includes(props.filter)
|| props.hostname.includes(props.filter) || critical_matches(item.srvc.critical,props.filter)
else
return props.filter === '' || item.name.includes(props.filter) || item.srvc.target.includes(props.filter)
|| item.info.includes(props.filter)
}
onMounted(() => {
shapWrapper = document.querySelector(".shape-wrapper");
function animate(selector: Element|null) {
if (selector && selector.classList.contains("xyz-in")) {
selector.classList.remove("xyz-in");
selector.classList.add("xyz-out");
} else if (selector) {
selector.classList.remove("xyz-out");
selector.classList.add("xyz-in");
}
}
animate(shapWrapper);
})
</script>
<style>
.shape-wrapper {
justify-content: center;
}
.shape {
width: auto;
height: auto;
margin: 1rem;
border-radius: 20px;
}
</style>

View File

@ -1,146 +0,0 @@
<template>
<nav class="text-xl mt-6 dark:bg-cool-gray-800 dark:text-white">
<span
v-for="(itm,index) in footerMenuCentral"
:key="`${String(index)}-${itm.title}`"
class="icon-btn mx-2"
>
<router-link v-if="itm.type === NavItemType.router_link && itemIf(itm)" :to="itm.to">
<span v-if="itm.to === '/'"> <carbon-campsite /> </span>
<span v-if="itm.to === '/login'"> <carbon-login /> </span>
<span v-if="itm.to === '/about'"> <carbon-dicom-overlay /> </span>
</router-link>
<a v-if="itm.type == NavItemType.app_link" :title="t(itm.title)" @click="itemClick(itm || '')">
<span v-if="itm.vif && itm.vif === 'isDark'" class="icon">
<svg
v-if="isDark"
aria-hidden="true"
focusable="false"
data-prefix="fal"
data-icon="cloud-sun"
class="svg-inline--fa fa-cloud-sun fa-w-20 dark:text-white text-blue-400 w-7"
style="margin-top: -0.8em"
role="img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 640 512"
><path fill="currentColor" d="M543.7 304.3C539.8 259.4 502 224 456 224c-17.8 0-34.8 5.3-49.2 15.2-22.5-29.5-57.3-47.2-94.8-47.2-66.2 0-120 53.8-120 120v.4c-38.3 16-64 53.5-64 95.6 0 57.3 46.7 104 104 104h304c57.3 0 104-46.7 104-104 0-54.8-42.6-99.8-96.3-103.7zM536 480H232c-39.7 0-72-32.3-72-72 0-32.3 21.9-60.7 53.3-69.2l13.3-3.6-2-17.2c-.3-2-.6-4-.6-6 0-48.5 39.5-88 88-88 32.2 0 61.8 17.9 77.2 46.8l10.6 19.8 15.2-16.5c10.8-11.7 25.4-18.1 41-18.1 30.9 0 56 25.1 56 56 0 1.6-.3 3.1-.8 6.9l-2.5 20 23.5-2.4c1.2-.2 2.5-.4 3.8-.4 39.7 0 72 32.3 72 72S575.7 480 536 480zM92.6 323l12.5-63.2c1.2-6.3-1.4-12.8-6.8-16.4l-53.5-35.8 53.5-35.8c5.4-3.6 8-10.1 6.8-16.4L92.6 92.1l63.2 12.5c6.4 1.3 12.8-1.5 16.4-6.8L208 44.3l35.8 53.5c3.6 5.3 9.9 8.1 16.4 6.8l63.2-12.5-12.5 63.2c-.3 1.6-.1 3.2 0 4.8.4 0 .7-.1 1.1-.1 10.1 0 20 1.1 29.6 3 .2-.5.5-.9.6-1.5l17.2-86.7c1-5.2-.6-10.6-4.4-14.4s-9.2-5.5-14.4-4.4l-76.2 15.1-43.1-64.4c-6-8.9-20.6-8.9-26.6 0l-43.2 64.5-76.1-15.1c-5.3-1.1-10.7.6-14.4 4.4-3.8 3.8-5.4 9.2-4.4 14.4l15.1 76.2-64.6 43.1c-4.4 3-7.1 8-7.1 13.3s2.7 10.3 7.1 13.3L71.6 264l-15.1 76.2c-1 5.2.6 10.6 4.4 14.4 3 3 7.1 4.7 11.3 4.7 1 0 2.1-.1 3.1-.3l32.8-6.5c6.2-13.8 14.6-26.5 25.1-37.6L92.6 323zM208 149.7c18.5 0 34.8 8.9 45.4 22.4 10.2-4.3 20.8-7.6 31.9-9.6-15.6-26.6-44.2-44.8-77.3-44.8-49.5 0-89.8 40.3-89.8 89.8 0 33 18.1 61.7 44.8 77.3 2-11.1 5.3-21.7 9.6-31.9-13.6-10.6-22.4-26.9-22.4-45.4 0-31.8 25.9-57.8 57.8-57.8z"></path></svg>
<svg
v-else
aria-hidden="true"
focusable="false"
data-prefix="fal"
data-icon="cloud-moon"
class="svg-inline--fa fa-cloud-moon fa-w-20 dark:text-white text-blue-400 w-7"
style="margin-top: -0.8em"
role="img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 640 512"
><path fill="currentColor" d="M351.5 313.6c-4.5-41.3-39.6-73.6-82.1-73.6-13.9 0-27.3 3.5-39.5 10.3-18.3-16.8-41.9-26.3-66.8-26.3-53.7 0-97.5 42.8-99.2 96.2-38.3 14.3-64 50.7-64 92.7C0 467.5 44.5 512 99.2 512h249.6c54.7 0 99.2-44.5 99.2-99.2 0-53.8-43-97.7-96.5-99.2zM348.8 480H99.2C62.1 480 32 449.9 32 412.8c0-31.6 21.5-58.5 52.4-65.4l14-5.9-2-14.6c-.2-1.2-.4-2.5-.4-3.8 0-37.1 30.1-67.2 67.2-67.2 20.1 0 39 9.2 52 25.2l10.1 12.5 12.4-10.1C247 276 258 272 269.4 272c27.9 0 50.6 22.7 50.6 50.6 0 1.5-.2 2.8-.7 6.4l-2.6 21.3 21.2-3.6c3.6-.6 7.2-1.2 11-1.2 37.1 0 67.2 30.2 67.2 67.2S385.9 480 348.8 480zm288.8-192.8c-4.1-8.6-12.4-13.9-21.8-13.9-1.5 0-3 .1-4.6.4-7.7 1.5-15.5 2.2-23.2 2.2-67 0-121.5-54.7-121.5-121.9 0-43.7 23.6-84.3 61.6-106 8.9-5.1 13.6-15 11.9-25.1-1.7-10.2-9.4-17.9-19.5-19.8-11.5-2-23.2-3.1-35-3.1-105.7 0-191.8 86.1-191.8 192 0 6.5.4 12.8 1.1 19.2 12.7 2.9 24.6 7.8 35.4 14.6-2.6-10.9-4.5-22-4.5-33.7 0-88.2 71.7-160 159.8-160 3 0 5.9.1 8.9.2-37.4 28.9-59.9 73.9-59.9 121.9C434.5 239 503.4 308 588 308c2.6 0 5.2-.1 7.8-.2C566.2 336.1 527 352 485.5 352c-7.5 0-14.8-.7-21.9-1.9 5.7 10.3 9.7 21.5 12.5 33.1 3.1.2 6.2.7 9.4.7 58.1 0 112.4-25.9 149-71.1 6-7.2 7.2-17.1 3.1-25.6z"></path></svg>
</span>
<IconLink v-else :typ="itm.type" :icon="itm.icon_on" :mode="itm.mode || ''" :open="false" :pfx="itm.pfx" :title="itm.title" :show_to="itm.show_to" :name="itm.name_to" />
</a>
<a
v-if="itm.type == NavItemType.a_blank"
rel="noreferrer"
:href="itm.href || '#'"
target="_blank"
:title="t(itm.title)"
>
<span v-if="itm.icon_on === 'carbon-logo-github'">
<carbon-logo-github />
</span>
</a>
</span>
</nav>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useStore } from 'vuex'
import { useRouter } from 'vue-router'
import { isDark, toggleDark } from '~/logics'
import { NavItemType } from '~/typs'
import { SideMenuItemType } from '~/typs/cmpnts'
import useState from '~/hooks/useState'
import { auth_data } from '~/hooks/utils'
// https://vitejs.dev/guide/features.html#static-assets
const router = useRouter()
const store = useStore()
const { t, availableLocales, locale } = useI18n()
const map_key = router.currentRoute.value.meta.uiMapkey || 'ui'
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
const footerMenuCentral = computed(() => {
return defs.value && defs.value.footer && defs.value.footer.central_items ? defs.value.footer.central_items : []
})
const toggleLocales = () => {
// change to some real logic
const locales = availableLocales
locale.value = locales[(locales.indexOf(locale.value) + 1) % locales.length]
}
const itemIf = (itm: SideMenuItemType) => {
switch (itm.vif) {
case 'notValidUser':
return auth_data().auth === '' ? true : false
;;
case 'validUser':
return auth_data().auth !== '' ? true : false
;;
default:
return true
}
}
const itemClick = (itm: SideMenuItemType) => {
switch (itm.click) {
case 'toggleDark':
toggleDark()
break
case 'toggleLocales':
toggleLocales()
break
case 'tophome':
if (useState().app_home_click.value) {
useState().app_home_click.value()
} else {
router.push('/')
}
break
default:
if (useState().side_menu_click.value) {
try {
useState().side_menu_click.value(itm)
} catch(e) {
console.log(e)
}
}
}
}
/*
<router-link class="icon-btn mx-2" to="/" :title="t('button.home')">
<carbon-campsite />
</router-link>
<a class="icon-btn mx-2" :title="t('button.toggle_dark')" @click="toggleDark">
<carbon-moon v-if="isDark" />
<carbon-sun v-else />
</a>
<a class="icon-btn mx-2" :title="t('button.toggle_langs')" @click="toggleLocales">
<carbon-language />
</a>
<router-link class="icon-btn mx-2" to="/about" :title="t('button.about')">
<carbon-dicom-overlay />
</router-link>
<a class="icon-btn mx-2" rel="noreferrer" href="https://github.com/antfu/vitesse" target="_blank" title="GitHub">
<carbon-logo-github />
</a>
<router-link class="icon-btn mx-2" to="/login" :title="t('button.login')">
<carbon-login />
</router-link>
*/
</script>

View File

@ -1,44 +0,0 @@
<template>
<span class="flex" :class="{'justify-start': open}">
<span v-if="pfx" class="-ml-5 mr-2 text-xs" :class="{ 'lg:hidden': open }">
<small class="text-gray-400">{{ pfx }}</small>
</span>
<span v-if="icon === 'carbon-home'" class="mt-1"> <carbon-home /> </span>
<span v-if="icon === 'carbon-campsite'" class="mt-1"> <carbon-campsite /> </span>
<span v-if="icon === 'carbon-login'" class="mt-1"> <carbon-login /> </span>
<span v-if="icon === 'carbon-dicom-overlay'" class="mt-1"> <carbon-dicom-overlay /> </span>
<span v-if="icon === 'carbon-table'" class="mt-1"> <carbon-table class="dark:text-white" /> </span>
<span v-if="icon === 'carbon-image'" class="mt-1"> <carbon-image /> </span>
<span v-if="icon === 'carbon-storage-pool'" class="mt-1"> <carbon-storage-pool /> </span>
<span v-if="icon === 'carbon-application'"> <carbon-application /> </span>
<span v-if="icon === 'carbon-services'" class="mt-1"> <carbon-cloud-services /> </span>
<span v-if="icon === 'carbon-event'"> <carbon-event /> </span>
<span v-if="icon === 'carbon-operation'"> <carbon-operation /> </span>
<span v-if="icon === 'carbon-api'"> <carbon-api /> </span>
<span v-if="icon === 'carbon-cloud'" class="flex justify-center items-center"> <carbon-cloud /> </span>
<span v-if="icon === 'carbon-flow'"> <carbon-flow /> </span>
<span v-if="icon === 'carbon-nominal'"> <carbon-nominal /> </span>
<span v-if="icon === 'carbon-language'"> <carbon-language /> </span>
<span v-if="show_to && name && name !== 'items'" class="mt-1 ml-2 text-xs" :class="{ 'hidden': open }"> {{ t(`${name}`,name||'') || '' }}</span>
<span v-if="mode !== 'icon'" class="ml-2" :class="{ 'lg:hidden': !open }"> {{ t(`${title}`,title||'') }}</span>
<span v-if="show_to" :class="{ 'lg:hidden': !open }" class="ml-2 text-xs flex justify-center items-center "> {{ t(`${name}`,name || '') }}</span>
</span>
</template>
<script setup lang="ts">
import { NavItemType } from '~/typs'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const props = defineProps<{
typ: NavItemType
icon: string | undefined
pfx: string | undefined
name: string | undefined
show_to: boolean | false
title: string | undefined
mode: sring | undefined
open: boolean | false
}>()
</script>

View File

@ -1,110 +0,0 @@
<template>
<nav
class="flex items-center justify-between flex-wrap p-1 fixed w-full z-10 top-0 left-0"
:class="{ 'shadow-lg bg-indigo-900' : isOpen , 'bg-blue-900' : !isOpen}"
@keydown.escape="isOpen = false"
>
<!--Logo etc-->
<div class="flex items-center flex-shrink-0 text-white ml-2 mr-6">
<a
aria-current="page"
href="/"
class="router-link-active router-link-exact-active flex items-center text-white no-underline hover:text-white hover:no-underline"
title="LibreCloud"
>
<span class="w-11 h-11 rounded-full mr-2">
<img class="max-w-7xl w-32 h-rounded" src="/assets/images/logo.svg" alt="App">
</span>
<span class="hidden text-sm md:block mr-2">{{props.navtitle}}</span>
<span
v-if="usetitle"
class="text-xl pl-2"
><i class="em em-grinning"></i> {{ t(`nav.${props.title}`,props.title) }} </span>
</a>
</div>
<!--Toggle button (hidden on large screens)-->
<button
type="button"
class="block lg:hidden px-2 text-gray-300 hover:text-white focus:outline-none focus:text-white"
:class="{ 'transition transform-180': isOpen }"
@click.prevent="isOpen = !isOpen"
>
<svg
class="h-6 w-6 fill-current"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path
v-show="isOpen"
fill-rule="evenodd"
clip-rule="evenodd"
d="M18.278 16.864a1 1 0 0 1-1.414 1.414l-4.829-4.828-4.828 4.828a1 1 0 0 1-1.414-1.414l4.828-4.829-4.828-4.828a1 1 0 0 1 1.414-1.414l4.829 4.828 4.828-4.828a1 1 0 1 1 1.414 1.414l-4.828 4.829 4.828 4.828z"
/>
<path
v-show="!isOpen"
fill-rule="evenodd"
d="M4 5h16a1 1 0 0 1 0 2H4a1 1 0 1 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2z"
/>
</svg>
</button>
<!--Menu-->
<div
class="w-full flex-grow lg:flex lg:items-center lg:w-auto"
:class="{ 'block shadow-3xl': isOpen, 'hidden': !isOpen }"
>
<ul
class="pt-4 lg:pt-0 list-reset lg:flex justify-end flex-1 items-center"
>
<li v-for="item in items" :key="item.name_to" class="mr-3">
<a
class="inline-block py-2 px-4 text-white no-underline"
:class="item.active ? '' : 'text-gray-400 no-underline hover:text-gray-200 hover:text-underline'"
:href="item.href"
@click.prevent="on_item(item)"
> {{ t(`nav.${item.title}`,item.title) }}
</a>
</li>
<slot name="opslist" />
<li class="p-1">
<div class="bg-white flex items-center rounded-full shadow-xl">
<slot name="search" />
</div>
</li>
<slot name="lastitems" />
<li class="p-1" v-if="authData.auth !== ''">
<router-link class="icon-btn text-2xl text-white no-underline" to="/logout" :title="t('button.logout')">
<carbon-logout />
</router-link>
</li>
<li class="p-1" v-else>
<router-link class="icon-btn text-2xl text-white no-underline" to="/login" :title="t('button.login')">
<carbon-login />
</router-link>
</li>
</ul>
</div>
</nav>
</template>
<script setup lang="ts">
import { SideMenuItemType } from '~/typs/cmpnts'
import { auth_data } from '~/hooks/utils'
const { t } = useI18n()
const props = defineProps<{
navtitle: string
usetitle: boolean
title: string
items: Array<SideMenuItemType>
}>()
const authData = auth_data()
const emit = defineEmits(['onNavMenu'])
const isOpen = ref(false)
const on_item = (item: SideMenuItemType) => {
emit('onNavMenu', item)
}
</script>

View File

@ -1,137 +0,0 @@
<script setup lang="ts">
import useState from '~/hooks/useState'
const { t } = useI18n()
const profile = ref({
username: 'jesusperez',
fullname: 'Jesús Pérez Lorenzo',
bgcolors: ['bg-emerald-500', 'bg-purple-500', 'bg-yellow-500', 'bg-gray-800', 'bg-pink-500'],
bgcolor: 'bg-dark-800',
photourl: 'https://avatars.githubusercontent.com/u/59666?v=4',
})
const profile_showsettings= ref(false)
const profile_editing= ref('')
const profile_saveedit = (name: string) => {
profile_editing.value = ''
}
const profile_edit = (name: string) => {
profile_editing.value = name
// this.$nextTick(() => {
// this.$refs[`${name}input`].focus()
// })
}
const profile_discard = (name: string) => {
// this.$refs[`${name}input`].value = this[name]
profile_editing.value = ''
}
const profile_selectcolor = (color: string) => {
profile.value.bgcolor = color
}
const onSettings = () => {
profile_showsettings.value= true
}
const onCloseSettings = () => {
profile_showsettings.value=false
}
const onLogout = () => {
useState().show_profile.value = false
}
</script>
<template>
<div class="block flex flex-col w-full h-screen justify-center items-center bg-white">
<div class="flex flex-col w-75 shadow-md max-w-full h-70 rounded-lg transition-colors ease-in" :class="profile.bgcolor">
<div v-show="profile_showsettings" class="fixed z-10 flex flex-col w-75 max-w-full h-70 text-center text-white p-5 origin-top-left transform scale-0 transition-all" :class="{'scale-100': profile_showsettings}">
<span class="text-2xl font-bold">{{ t('profile.Settings','Settings') }}</span>
<div class="flex flex-col space-y-2 mt-5 flex-grow">
<span class="text-md font-bold">{{ t('profile.backgroud_color','Background color') }}:</span>
<div class="w-full flex justify-center space-x-2">
<span v-for="c in profile.bgcolors" :key="c">
<button class="flex border-4 border-white inline cursor-pointer w-8 h-8 rounded-full" :class="c" :disabled="profile.bgcolor == c" @click="profile_selectcolor(c)"></button>
</span>
</div>
</div>
<div class="flex justify-center flex-shrink align-end">
<button class="rounded bg-transparent font-bold text-lg fill-current text-white" @click="onCloseSettings">
{{ t(`profile.Close`,'Close') }}
</button>
</div>
</div>
<div v-show="!profile_showsettings">
<div class="flex w-full justify-between p-2 mt-1">
<button @click="onSettings" class="flex space-x-1 group font-semibold items-center bg-transparent cursor-pointer text-white fill-current">
<svg class="w-7 h-7" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
<span class="origin-left transform scale-x-0 group-focus:scale-x-100 group-hover:scale-x-100 transition-transform ease-in select-none text-lg">{{ t('profile.Settings','Settings') }}</span>
</button>
<button @click="onLogout" class="flex space-x-1 group font-semibold items-center bg-transparent cursor-pointer text-white fill-current">
<span class="origin-right transform scale-x-0 group-focus:scale-x-100 group-hover:scale-x-100 transition-transform ease-in select-none text-lg">{{ t('profile.Logout','Logout') }}</span>
<svg class="w-7 h-7" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
</svg>
</button>
</div>
<div class="flex flex-col w-full h-full text-center">
<div class="flex flex-col space-y-2 items-center mb-3">
<img :src="profile.photourl" alt="Profile Picture" class="rounded-full select-none w-22">
<div class="text-center relative group">
<span v-show="profile_editing !== 'fullname'" class="text-xl break-words font-semibold text-white font-sans m-0 p-0 px-2 select-none" title="Double click to edit" @dblclick="profile_edit('fullname')">{{ profile.fullname }}</span>
<svg v-show="profile_editing != 'fullname'" xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-gray-50 inline absolute right-2 -top-3 transform scale-0 group-hover:scale-100 transition-transform" viewBox="0 0 20 20" fill="currentColor">
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z" />
<path fill-rule="evenodd" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" clip-rule="evenodd" />
</svg>
<input
v-show="profile_editing == 'fullname'"
id=""
type="text"
name=""
class="bg-transparent text-xl font-sans w-full p-0 px-2 m-0 text-center text-white font-semibold focus:outline-none focus:animate-pulse"
:value="profile.fullname"
spellcheck="false"
x-ref="fullnameinput"
title="Enter to save, click outside to discard."
maxlength="20"
@keydown.enter="profile_saveedit('fullname')"
@click="profile_discard('fullname')"
@keydown.escape="profile_discard('fullname')"
>
</div>
<div class="text-center relative group">
<span v-show="profile_editing != 'username'" class="text-sm text-wrap font-semibold font-sans m-0 p-0 text-green-100 select-none" title="Double click to edit" @dblclick="profile_edit('username')">{{ profile.username }}</span>
<svg v-show="profile_editing != 'username'" xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-gray-50 inline absolute ml-1 -top-1 transform scale-0 group-hover:scale-100 transition-transform" viewBox="0 0 20 20" fill="currentColor">
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z" />
<path fill-rule="evenodd" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" clip-rule="evenodd" />
</svg>
<input
v-show="profile_editing == 'username'"
id=""
type="text"
name=""
class="inline-block bg-transparent text-sm font-sans p-0 m-0 w-auto text-center font-semibold text-green-100 focus:outline-none focus:animate-pulse"
:value="profile.username"
spellcheck="false"
x-ref="usernameinput"
title="Enter to save, click outside to discard."
maxlength="15"
@keydown.enter="profile_saveedit('username')"
@click="profile_discard('username')"
@keydown.escape="profile_discard('username')"
>
</div>
</div>
<div class="hidden flex flex-row justify-evenly">
<div class="flex flex-col cursor-pointer hover:opacity-80">
<span class="text-lg font-bold text-white">11</span>
<span class="text-green-100 text-sm">Followers</span>
</div>
<div class="flex flex-col cursor-pointer hover:opacity-80">
<span class="text-lg font-bold text-white">52</span>
<span class="text-green-100 text-sm">Following</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>

View File

@ -1,9 +0,0 @@
## Components
Components in this dir will be auto-registered and on-demand, powered by [`unplugin-vue-components`](https://github.com/antfu/unplugin-vue-components).
### Icons
You can use icons from almost any icon sets by the power of [Iconify](https://iconify.design/).
It will only bundle the icons you use. Check out [`unplugin-icons`](https://github.com/antfu/unplugin-icons) for more details.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,99 +0,0 @@
<template>
<button class="icon-btn mx-2" @click="toggleShowLocales">
<carbon-language class="inline-block text-gray-900 dark:text-white" />
</button>
<div v-if="showLocalesSelector" :class="`select !normal max-w-xs ${selWidth} float-right`">
<select v-model="currentLocale" class="dark:text-white">
<option
v-for="itm in listLocales"
:key="itm"
:selected="itm === currentLocale"
:value="itm"
>
{{ localeLabel(itm) }}
</option>
</select>
</div>
</template>
<script lang="ts">
// import {
// PropType,
// } from 'vue'
</script>
<script setup lang="ts">
// <vue:window on:keydown={cleanOverlay} />
import {
ref,
onMounted,
computed,
PropType,
} from 'vue'
import { useI18n } from 'vue-i18n'
enum LocalesLabelModes {
value = 'val',
translation = 'trans',
}
const props = defineProps({
labelMode: {
type: Object as PropType<LocalesLabelModes>,
//default: LocalesLabelModes.translation,
required: false,
},
includeCurrent: {
type: Boolean,
default: false,
required: false,
},
})
const i18n = useI18n()
const showLocalesSelector = ref(false)
const currentLocale = computed({
get: (): string => i18n.locale.value,
set: (val: string) => {
if (i18n.availableLocales.includes(val)) {
// console.log(`change to ${val} from ${i18n.locale.value}`)
i18n.locale.value = val
showLocalesSelector.value = false
}
},
})
const locales = computed(() => i18n.availableLocales)
const listLocales = computed(() =>
props.includeCurrent ? locales.value : locales.value.filter(lcl => lcl !== currentLocale.value))
const toggleShowLocales = () => {
showLocalesSelector.value = !showLocalesSelector.value
// change to some real logic
// i18n.locale.value = i18n.availableLocales[(i18n.availableLocales.indexOf(i18n.locale.value) + 1) % i18n.availableLocales.length]
}
const localeLabel = (value: string): string => {
let label = ''
switch (props.labelMode) {
case LocalesLabelModes.translation:
label = i18n.t(value, value)
break
case LocalesLabelModes.value:
label = value
break
}
return label
}
const selWidth = computed(() => {
let width = ''
switch (props.labelMode) {
case LocalesLabelModes.translation:
width = 'w-28'
break
case LocalesLabelModes.value:
width = 'w-24'
break
}
return width
})
onMounted(() => {
})
</script>

View File

@ -1,251 +0,0 @@
<template>
<nav class="flex items-center justify-between pt-1 dark:bg-cool-gray-800 dark:text-white">
<!-- Navbar left -->
<div class="flex items-center space-x-3">
<span class="cursor-pointer p-2 text-xl font-semibold tracking-wider uppercase lg:hidden" @click="on_logo_app">
<img class="-mt-1 h-11 w-auto rounded" src="/assets/images/app_w.svg" alt="App">
</span>
<!-- Toggle sidebar button -->
<button class="p-2 rounded-md focus:outline-none focus:ring dark:bg-cool-gray-600" @click="toggleSidebar">
<span class="sr-only">Toggle sidebar</span>
<ChevronDoubleRight
aria-hidden="true"
class="w-4 h-4 text-gray-600 dark:text-white"
:class="{ 'transform transition-transform -rotate-180': isSidebarOpen }"
/>
</button>
<Breadcrump :bc-path="bcPath" @on-book-selec="bookSelec" />
<span class="lg:ml-3 flex">
<span
class="hidden lg:flex flex-grow"
:class="`${navTitle && navTitle.cmpnt === 'boxmenu' ? 'mt-2': ''} ${navTitle.textclick ? 'cursor-pointer': ''}`"
@click="onNavTitleClick"
>{{ navTitle && navTitle.text || '' }}
</span>
<BoxMenu
v-if="navTitle && navTitle.text !== '' && navTitle.cmpnt === 'boxmenu'"
class="-ml-4 lg:ml-0 flex-grow-0"
:menu-options="navTitle.ops"
:title="navTitle.title"
:btn-type="navTitle.btntype"
@on-menu-option="onNavTitleMenuOption"
/>
</span>
</div>
<!-- Navbar right -->
<nav aria-label="Secondary" class="flex items-center space-x-3">
<span class="cursor-pointer p-2 text-xl font-semibold tracking-wider uppercase" @click="on_logo_app">
<img class="-mt-1 h-11 w-auto rounded" src="/assets/images/logo.svg" alt="App">
</span>
<NavbarIconButton
v-show="authData.auth === ''"
label="Login"
@click="router.push('/login')"
>
<carbon-login /> {{ t('button.login','Login') }}
</NavbarIconButton>
<NavbarIconButton
v-show="useSettings"
label="Open setting panel"
@click="isSettingsPanelOpen = !isSettingsPanelOpen"
>
<carbon-settings />
</NavbarIconButton>
<!-- Search button -->
<NavbarIconButton v-if="navbar_right.search" label="Open search panel" @click="isSearchPanelOpen = true">
<!-- SearchIcon aria-hidden="true" class="w-6 h-6" -->
<carbon-search />
</NavbarIconButton>
<!-- Notification Button -->
<NavbarIconButton v-if="navbar_right.notify" label="Open notifications panel" @click="isNotificationsPanelOpen = true">
<!--BellIcon aria-hidden="true" class="w-6 h-6" /-->
<carbon-notification />
</NavbarIconButton>
<!-- User menu -->
<Menu v-slot="{ open }" as="div" class="relative pr-2">
<MenuButton
id="user-menu"
aria-haspopup="true"
:aria-expanded="open ? 'true' : 'false'"
class="relative flex items-center overflow-hidden rounded-full group focus:outline-none focus:ring"
v-if="authData.auth !== ''"
>
<span class="sr-only">{{ `${navbar_right.title || 'Open menu'}` }}</span>
<img
class="object-cover w-8 h-8 rounded-full group-hover:opacity-90"
src="/assets/images/jesus.jpg"
alt="User image"
>
<!-- <div class="absolute right-0 p-1 bg-green-400 rounded-full top-1 animate-ping"></div>
<div class="absolute right-0 p-1 bg-green-400 border border-white rounded-full top-1"></div> -->
</MenuButton>
<transition
enter-active-class="transition duration-100 ease-out"
enter-from-class="transform scale-95 opacity-0"
enter-to-class="transform scale-100 opacity-100"
leave-active-class="transition duration-75 ease-out"
leave-from-class="transform scale-100 opacity-100"
leave-to-class="transform scale-95 opacity-0"
>
<MenuItems
class="absolute right-0 z-999 w-48 py-1 mt-2 origin-top-righti dark:bg-gray-600 bg-white rounded-md shadow-lg focus:outline-none"
role="menu"
aria-orientation="vertical"
aria-labelledby="user-menu"
>
<MenuItem
v-for="(itm,index) in navbar_right.items"
v-slot="{ active }"
:key="`${String(index)}-${itm.title}`"
>
<span class="block text-sm dark:text-gray-300 text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-500">
<a
v-if="itm && itm.type === 'app_link'"
:class="{ 'bg-gray-100': active }"
class="px-4 py-2 flex items-center"
role="menuitem"
@click.prevent="onMenuItemClick(itm)"
>
{{ t(itm.title) }}
</a>
<router-link
v-if="itm && itm.type === 'router_link'"
:title="t(itm.title)"
:to="{ name: itm.name_to }"
class="px-4 py-2 flex items-center"
>
{{ t(itm.title) }}
</router-link>
</span>
</MenuItem>
</MenuItems>
</transition>
</Menu>
</nav>
</nav>
</template>
<script setup lang="ts">
/*
// https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
<MenuItem v-slot="{ active }">
<a
href="#"
class="block px-4 py-2 text-sm text-gray-700"
:class="{ 'bg-gray-100': active }"
role="menuitem"
>
{{ t('menu.your-profile') }}
</a>
</MenuItem>
<MenuItem v-slot="{ active }">
<a
href="#"
class="block px-4 py-2 text-sm text-gray-700"
:class="{ 'bg-gray-100': active }"
role="menuitem"
>
{{ t('menu.settings') }}
</a>
</MenuItem>
<MenuItem v-slot="{ active }">
<a
href="#"
class="block px-4 py-2 text-sm text-gray-700"
:class="{ 'bg-gray-100': active }"
role="menuitem"
>
{{ t('menu.sign-out') }}
</a>
</MenuItem>
*/
import {
computed,
} from 'vue'
import { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'
import ChevronDoubleRight from '@/icons/ChevronDoubleRight.vue'
// import SearchIcon from '@/icons/SearchIcon.vue'
// import BellIcon from '@/icons/BellIcon.vue'
import Breadcrump from '@/Breadcrump.vue'
import { useStore } from 'vuex'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import NavbarIconButton from './NavbarIconButton.vue'
import BoxMenu from '~/views/BoxMenu.vue'
import useState from '~/hooks/useState'
import useComponent from '~/hooks/useComponent'
// import { NavItemType } from '~/typs'
// import { SideMenuItemType } from '~/typs/cmpnts'
import { auth_data } from '~/hooks/utils'
import { SideMenuItemType } from '~/typs/cmpnts'
const router = useRouter()
const store = useStore()
const open_menu = ref(false)
const { isSidebarOpen, isSearchPanelOpen, isSettingsPanelOpen, toggleSidebar, isNotificationsPanelOpen, bcPath, navTitle } = useState()
const { t } = useI18n()
const authData = computed(() => auth_data())
const map_key = router.currentRoute.value.meta.uiMapkey || 'ui'
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
const user_image = computed(() => {
const image = defs.value.profile && defs.value.profile.image ? defs.value.profile.image : ''
if (image === '') {
return '/assets/images/user.jpg'
}
if (image.charAt(0) === '/' || image.includes('http')) {
return image
} else {
return `/assets/images/${image}`
}
})
const useSettings = computed(() => Object.entries(useComponent().settingsComponent.value).length !== 0)
const navbar_right = computed(() => {
return defs.value && defs.value.header && defs.value.header.navbar && defs.value.header.navbar.menuright
? defs.value.header.navbar.menuright
: { title: '', notify: false, search: false, items: [] }
})
const bookSelec = (target: string) => {
switch (target) {
case 'home':
useState().bcPath.value = ''
useState().dfltNavTitle()
router.push('/')
break
default:
useState().bookSelec(target)
}
}
const on_logo_app = () => {
useState().bcPath.value = ''
useState().dfltNavTitle()
useState().isSidebarOpen.value = false
if (useState().app_home_click.value) {
useState().app_home_click.value()
}
router.push('/')
}
const onMenuItemClick = (itm: SideMenuItemType ) => {
const ustate: any = useState()
const ky=`show_${itm.click}`
if (ustate[ky])
ustate[ky].value = !ustate[ky].value
}
const onNavTitleMenuOption = (data: any) => {
if (navTitle.value.cllbck)
navTitle.value.cllbck(data)
}
const onNavTitleClick = () => {
if (navTitle.value.textclick)
navTitle.value.textclick()
}
</script>

View File

@ -1,18 +0,0 @@
<template>
<button
type="button"
class="flex items-center justify-center p-2 text-gray-400 transition-colors bg-gray-100 rounded-full focus:outline-none focus:ring hover:bg-gray-200 hover:text-gray-500 dark:bg-cool-gray-600 dark:text-white"
>
<span class="sr-only">{{ label }}</span>
<slot />
</button>
</template>
<script setup>
defineProps({
label: {
type: String,
required: true,
},
})
</script>

View File

@ -1,236 +0,0 @@
<template>
<nav class="flex items-center justify-between pt-1 dark:bg-cool-gray-800 dark:text-white">
<!-- Navbar left -->
<div class="flex items-center space-x-3">
<span class="cursor-pointer p-2 text-xl font-semibold tracking-wider uppercase lg:hidden" @click="on_logo_app">
<img class="-mt-1 h-11 w-auto rounded" src="/assets/images/app_w.svg" alt="App">
</span>
<!-- Toggle sidebar button -->
<button class="p-2 rounded-md focus:outline-none focus:ring dark:bg-cool-gray-600" @click="toggleSidebar">
<span class="sr-only">Toggle sidebar</span>
<ChevronDoubleRight
aria-hidden="true"
class="w-4 h-4 text-gray-600 dark:text-white"
:class="{ 'transform transition-transform -rotate-180': isSidebarOpen }"
/>
</button>
<Breadcrump :bc-path="bcPath" @on-book-selec="bookSelec" />
<span class="lg:ml-3 flex">
<span
class="hidden lg:flex flex-grow"
:class="`${navTitle && navTitle.cmpnt === 'boxmenu' ? 'mt-2': ''} ${navTitle.textclick ? 'cursor-pointer': ''}`"
@click="onNavTitleClick"
>{{ navTitle && navTitle.text || '' }}
</span>
<BoxMenu
v-if="navTitle && navTitle.text !== '' && navTitle.cmpnt === 'boxmenu'"
class="-ml-4 lg:ml-0 flex-grow-0"
:menu-options="navTitle.ops"
:title="navTitle.title"
:btn-type="navTitle.btntype"
@on-menu-option="onNavTitleMenuOption"
/>
</span>
</div>
<!-- Navbar right -->
<nav aria-label="Secondary" class="flex items-center space-x-3">
<span class="cursor-pointer p-2 text-xl font-semibold tracking-wider uppercase" @click="on_logo_app">
<img class="-mt-1 h-11 w-auto rounded" src="/assets/images/logo.svg" alt="App">
</span>
<NavbarIconButton
v-show="useSettings"
label="Open setting panel"
@click="isSettingsPanelOpen = !isSettingsPanelOpen"
>
<carbon-settings />
</NavbarIconButton>
<!-- Search button -->
<NavbarIconButton v-if="navbar_right.search" label="Open search panel" @click="isSearchPanelOpen = true">
<!-- SearchIcon aria-hidden="true" class="w-6 h-6" -->
<carbon-search />
</NavbarIconButton>
<!-- Notification Button -->
<NavbarIconButton v-if="navbar_right.notify" label="Open notifications panel" @click="isNotificationsPanelOpen = true">
<!--BellIcon aria-hidden="true" class="w-6 h-6" /-->
<carbon-notification />
</NavbarIconButton>
<!-- User menu -->
<Menu v-slot="{ open }" as="div" class="relative pr-2">
<span> {{ navbar_right.items}} </span>
<MenuButton
id="user-menu"
aria-haspopup="true"
:aria-expanded="open ? 'true' : 'false'"
class="relative flex items-center overflow-hidden rounded-full group focus:outline-none focus:ring"
>
<span class="sr-only">{{ `${navbar_right.title || 'Open menu'}` }}</span>
<img
class="object-cover w-8 h-8 rounded-full group-hover:opacity-90"
src="/assets/images/jesus.jpg"
alt="User image"
>
<!-- <div class="absolute right-0 p-1 bg-green-400 rounded-full top-1 animate-ping"></div>
<div class="absolute right-0 p-1 bg-green-400 border border-white rounded-full top-1"></div> -->
</MenuButton>
<transition
enter-active-class="transition duration-100 ease-out"
enter-from-class="transform scale-95 opacity-0"
enter-to-class="transform scale-100 opacity-100"
leave-active-class="transition duration-75 ease-out"
leave-from-class="transform scale-100 opacity-100"
leave-to-class="transform scale-95 opacity-0"
>
<MenuItems
class="absolute right-0 z-999 w-48 py-1 mt-2 origin-top-righti dark:bg-gray-600 bg-white rounded-md shadow-lg focus:outline-none"
role="menu"
aria-orientation="vertical"
aria-labelledby="user-menu"
>
<MenuItem
v-for="(itm,index) in navbar_right.items"
v-slot="{ active }"
:key="`${String(index)}-${itm.title}`"
>
<span class="block text-sm dark:text-gray-300 text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-500">
<a
v-if="itm && itm.type === 'app_link'"
:href="itm.link"
:class="{ 'bg-gray-100': active }"
class="px-4 py-2"
role="menuitem"
>
{{ t(itm.title) }}
</a>
<router-link
v-if="itm && itm.type === 'router_link'"
:title="t(itm.title)"
:to="{ name: itm.name_to }"
class="px-4 py-2 flex items-center"
>
{{ t(itm.title) }}
</router-link>
</span>
</MenuItem>
</MenuItems>
</transition>
</Menu>
</nav>
</nav>
</template>
<script setup lang="ts">
/*
// https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
<MenuItem v-slot="{ active }">
<a
href="#"
class="block px-4 py-2 text-sm text-gray-700"
:class="{ 'bg-gray-100': active }"
role="menuitem"
>
{{ t('menu.your-profile') }}
</a>
</MenuItem>
<MenuItem v-slot="{ active }">
<a
href="#"
class="block px-4 py-2 text-sm text-gray-700"
:class="{ 'bg-gray-100': active }"
role="menuitem"
>
{{ t('menu.settings') }}
</a>
</MenuItem>
<MenuItem v-slot="{ active }">
<a
href="#"
class="block px-4 py-2 text-sm text-gray-700"
:class="{ 'bg-gray-100': active }"
role="menuitem"
>
{{ t('menu.sign-out') }}
</a>
</MenuItem>
*/
import {
computed,
} from 'vue'
import { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'
import ChevronDoubleRight from '@/icons/ChevronDoubleRight.vue'
// import SearchIcon from '@/icons/SearchIcon.vue'
// import BellIcon from '@/icons/BellIcon.vue'
import Breadcrump from '@/Breadcrump.vue'
import { useStore } from 'vuex'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import NavbarIconButton from './NavbarIconButton.vue'
import BoxMenu from '~/views/BoxMenu.vue'
import useState from '~/hooks/useState'
import useComponent from '~/hooks/useComponent'
// import { NavItemType } from '~/typs'
// import { SideMenuItemType } from '~/typs/cmpnts'
import { auth_data } from '~/hooks/utils'
const router = useRouter()
const store = useStore()
const { isSidebarOpen, isSearchPanelOpen, isSettingsPanelOpen, toggleSidebar, isNotificationsPanelOpen, bcPath, navTitle } = useState()
const { t } = useI18n()
const authData = computed(() => auth_data())
const map_key = router.currentRoute.value.meta.uiMapkey || 'ui'
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
const user_image = computed(() => {
const image = defs.value.profile && defs.value.profile.image ? defs.value.profile.image : ''
if (image === '') {
return '/assets/images/user.jpg'
}
if (image.charAt(0) === '/' || image.includes('http')) {
return image
} else {
return `/assets/images/${image}`
}
})
const useSettings = computed(() => Object.entries(useComponent().settingsComponent.value).length !== 0)
const navbar_right = computed(() => {
return defs.value && defs.value.header && defs.value.header.navbar && defs.value.header.navbar.menuright
? defs.value.header.navbar.menuright
: { title: '', notify: false, search: false, items: [] }
})
const bookSelec = (target: string) => {
switch (target) {
case 'home':
useState().bcPath.value = ''
useState().dfltNavTitle()
router.push('/')
break
default:
useState().bookSelec(target)
}
}
const on_logo_app = () => {
useState().bcPath.value = ''
useState().dfltNavTitle()
useState().isSidebarOpen.value = false
if (useState().app_home_click.value) {
useState().app_home_click.value()
}
router.push('/')
}
const onNavTitleMenuOption = (data: any) => {
if (navTitle.value.cllbck)
navTitle.value.cllbck(data)
}
const onNavTitleClick = () => {
if (navTitle.value.textclick)
navTitle.value.textclick()
}
</script>

View File

@ -1,45 +0,0 @@
<template>
<Panel :show="show" :title="title" id="aside" @close="close">
<div class="flex-1 max-h-full p-4 overflow-hidden hover:overflow-y-auto">
<keep-alive>
<component :is="asideComponent" />
</keep-alive>
<slot />
</div>
</Panel>
</template>
<script setup>
import { computed, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import Panel from './Panel.vue'
import useComponent, { DynComponent } from '~/hooks/useComponent'
defineProps({
show: {
type: Boolean,
required: true,
},
title: {
type: String,
required: false,
default: () => '',
},
})
const emit = defineEmits(['close'])
const cmpnt = useComponent()
const close = () => {
emit('close')
}
onMounted(() => {
document.addEventListener('keydown', (event) => {
switch (event.key) {
case 'Escape':
emit('close')
break
}
})
})
const { t, locale } = useI18n()
const asideComponent = computed(() => cmpnt.asideComponent.value)
</script>

View File

@ -1,40 +0,0 @@
<template>
<Panel :show="show" :title="t(title || 'notifications.notifications')" id="notifycation" @close="close">
<div class="flex-1 max-h-full p-4 overflow-hidden hover:overflow-y-auto">
<span>{{ t('notifications.content') }}</span>
<!-- Notifications Panel Content ... -->
</div>
</Panel>
</template>
<script setup>
import { onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import Panel from './Panel.vue'
defineProps({
show: {
type: Boolean,
required: true,
},
title: {
type: String,
required: false,
default: () => '',
},
})
const emit = defineEmits(['close'])
const close = () => {
emit('close')
}
const { t, locale } = useI18n()
onMounted(() => {
document.addEventListener('keydown', (event) => {
switch (event.key) {
case 'Escape':
emit('close')
break
}
})
})
</script>

View File

@ -1,73 +0,0 @@
<template>
<!-- Backdrop -->
<Backdrop :show="show" :blur="backdrop_blur" @close="close" />
<!-- Panel -->
<transition
enter-active-class="transition duration-300 ease-in-out transform"
:enter-from-class="left ? '-translate-x-full' : 'translate-x-full'"
:enter-to-class="left ? '-translate-x-0' : 'translate-x-0'"
leave-active-class="transition duration-300 ease-in-out transform"
:leave-from-class="left ? '-translate-x-0' : 'translate-x-0'"
:leave-to-class="left ? '-translate-x-full' : 'translate-x-full'"
>
<section
v-if="show"
:aria-labelledby="title"
class="fixed z-999 border-left-2 border-gray-400 max-w-xs bg-white sm:max-w-md ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-cool-gray-800 dark:text-white"
:class="`${left ? 'left-0' : 'right-0'} bg-opacity-${back_opacity} ${panel_style}`"
>
<div class="flex items-center justify-between flex-shrink-0 p-2">
<h6 class="p-2 text-lg">
{{ title }}
</h6>
<!-- Close button -->
<button class="p-2 rounded-md focus:outline-none focus:ring dark:bg-cool-gray-600" @click="close">
<CloseIcon class="w-6 h-6 text-gray-600 dark:text-white" />
</button>
</div>
<!-- Panel content -->
<slot />
</section>
</transition>
</template>
<script setup lang="ts">
import Backdrop from '../global/Backdrop.vue'
import CloseIcon from '../icons/CloseIcon.vue'
import useState from '~/hooks/useState'
const props = defineProps<{
show: {
type: boolean,
required: true,
},
left: {
type: boolean,
required: false,
default: false,
},
title: {
type: string,
required: true,
},
id: {
type: string,
required: true,
},
}>()
const backdrop_blur = useState().backdrop_blur
const back_opacity = useState().back_opacity
const emit = defineEmits(['close'])
const panel_style = computed(() => {
const key: any = props.id || ''
return useState().panels.value[key] && useState().panels.value[key].style ? useState().panels.value[key].style : 'inset-y-0 w-full'
})
const close = () => {
emit('close')
}
</script>

View File

@ -1,51 +0,0 @@
<template>
<Panel :show="show" :title="t(title || 'search.search')" id="search" @close="close">
<div class="flex-1 max-h-full p-4 space-y-4 overflow-hidden hover:overflow-y-auto dark:text-gray-600 dark:text-white">
<form @submit.prevent="close" >
<input
type="text"
v-model="search"
:placeholder="`${t('search.search')}...`"
class="w-full px-4 py-2 border rounded-md focus:outline-none focus:ring dark:text-gray-600 dark:text-white"
>
</form>
<div>
</div>
</div>
</Panel>
</template>
<script setup>
import { onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import Panel from './Panel.vue'
import useState from '~/hooks/useState'
const search = useState().search
defineProps({
show: {
type: Boolean,
required: true,
},
title: {
type: String,
required: false,
default: () => '',
},
})
const emit = defineEmits(['close'])
const close = () => {
emit('close')
}
const { t, locale } = useI18n()
onMounted(() => {
document.addEventListener('keydown', (event) => {
switch (event.key) {
case 'Escape':
emit('close')
break
}
})
})
</script>

View File

@ -1,47 +0,0 @@
<template>
<Panel :show="show" :title="title || t('settings.settings')" id="setting" @close="close">
<div class="flex-1 max-h-full p-4 overflow-hidden hover:overflow-y-auto">
<keep-alive>
<component :is="currentComponent" />
</keep-alive>
<slot />
<!-- Settings Panel Content ... -->
</div>
</Panel>
</template>
<script setup>
import { computed, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import Panel from './Panel.vue'
import useComponent, { DynComponent } from '~/hooks/useComponent'
defineProps({
show: {
type: Boolean,
required: true,
},
title: {
type: String,
required: false,
default: () => '',
},
})
const emit = defineEmits(['close'])
const cmpnt = useComponent()
const close = () => {
emit('close')
}
const { t, locale } = useI18n()
const currentComponent = computed(() => cmpnt.settingsComponent.value)
onMounted(() => {
document.addEventListener('keydown', (event) => {
switch (event.key) {
case 'Escape':
emit('close')
break
}
})
})
</script>

View File

@ -1,170 +0,0 @@
<template>
<Backdrop :show="isSidebarOpen" :blur="backdrop_blur" class="lg:hidden" @close="isSidebarOpen = false" />
<aside
class="fixed inset-y-0 z-999 flex flex-col flex-shrink-0 w-64 max-h-screen transition-all transform border-r dark:border-gray-700 border-gray-200 bg-white shadow-lg lg:z-auto lg:static lg:shadow-none"
:class="{ '-translate-x-full lg:translate-x-0 lg:w-20': !isSidebarOpen }"
>
<!-- sidebar header -->
<SidebarHeader />
<!-- Sidebar links -->
<nav aria-label="Main" class="dark:bg-cool-gray-800 dark:text-white bg-white flex-1 overflow-hidden hover:overflow-y-auto">
<!-- Sidebar Links... -->
<ul class="p-2">
<li
v-for="(itm,index) in sidebarMenuItems"
:key="`${String(index)}-${itm.title}`"
dark:border-gray-700
border-gray-200
>
<hr v-if="itm.type === NavItemType.separator" class=" dark:border-gray-600 border-gray-300">
<router-link
v-if="itm.type === NavItemType.router_link"
:title="t(itm.title)"
:to="{ name: itm.name_to }"
class="flex items-center p-2 overflow-hidden rounded-md hover:bg-gray-100 dark:hover:bg-gray-500"
:class="{ 'justify-center': !isSidebarOpen }"
>
<IconLink :typ="itm.type" :icon="itm.icon_on" :mode="itm.mode||''" :open="isSidebarOpen" :pfx="itm.pfx" :title="itm.title" :show_to="itm.show_to" :name="itm.name_to" />
</router-link>
<span
v-if="itm.type === NavItemType.module_label"
class="border-bottom-1 dark:border-gray-700 border-gray-200 flex text-xs color-gray-100"
:class="isSidebarOpen ? 'justify-end' : 'justify-start'"
>
<span class="float-right text-gray-400" :class="{ 'lg:hidden': !isSidebarOpen }"> {{ t(`menu.${itm.label}`,'') }}</span>
</span>
<a
v-if="itm.type == NavItemType.a_blank"
class="flex items-center p-2 overflow-hidden rounded-md hover:bg-gray-100 dark:hover:bg-gray-500"
:class="{ 'justify-center': !isSidebarOpen }"
@click="itemClick(itm.click || '')"
>
<IconLink :typ="itm.type" :icon="itm.icon_on" :mode="itm.mode || ''" :open="isSidebarOpen" :pfx="itm.pfx" :title="itm.title" :show_to="itm.show_to" :name="itm.name_to" />
</a>
<a
v-if="itm.type == NavItemType.a_link"
rel="noreferrer"
:href="itm.href || '#'"
target="_blank"
:title="t(itm.title)"
>
<span v-if="itm.icon_on === 'carbon-launch'"> <carbon-launch /> </span>
<span class="ml-2" :class="{ 'lg:hidden': !isSidebarOpen }"> {{ t(itm.title) }}</span>
</a>
<a
v-if="itm.type == NavItemType.app_link"
:title="t(itm.title)"
class="flex items-center p-2 overflow-hidden rounded-md hover:bg-gray-100 dark:hover:bg-gray-500"
:class="{ 'justify-center': !isSidebarOpen, 'ml-5': itm.name_to && itm.name_to === 'items' }"
@click.prevent="appItemClick(itm)"
>
<IconLink :typ="itm.type" :icon="itm.icon_on" :mode="itm.mode || ''" :open="isSidebarOpen" :pfx="itm.pfx" :title="itm.title" :show_to="itm.show_to" :name="itm.name_to" />
</a>
<a
v-if="itm.type == NavItemType.cloud_link && !isSidebarOpen && itm.name_to && itm.name_to !== 'items'"
:title="t(itm.title)"
class="flex items-center justify-center p-2 overflow-hidden rounded-md hover:bg-gray-300 dark:hover:text-gray-100 dark:hover:bg-gray-500"
@click.prevent="appItemClick(itm)"
>
<span v-if="itm.name_to && itm.name_to !== 'cloud'" class="flex -ml-2 text-gray-500 dark:text-gray-500 dark:hover:text-gray-100 dark:hover:bg-gray-500">
<span v-if="isSidebarOpen && itm.pfx" class="-ml-2 mr-2 font-light">
<small class="text-gray-400">{{ itm.pfx }}</small>
</span>
<span class="ml-2 text-xs font-light"> {{ itm.name || '' }}</span>
</span>
<span v-else class="pt-1 pb-1 border-b border-t border-gray-200 dark:border-gray-500">
<span v-if="itm.icon_on === 'carbon-cloud'" class="flex justify-center items-center"> <carbon-cloud /> </span>
<span class="text-xs flex justify-center items-center "> {{ itm.name || '' }}</span>
</span>
</a>
</li>
</ul>
</nav>
<span @click="on_logo_app" class="cursor-pointer text-xl font-semibold tracking-wider uppercase dark:bg-cool-gray-800 dark:text-white bg-white">
<div class="flex">
<img class="-mt-1 h-11 w-auto rounded" src="/assets/images/logo.svg" alt="App">
<span :class="{ 'lg:hidden': !isSidebarOpen }" class="ml-4 mt-2 text-gray-400">{{ t('app.title','') }}</span>
</div>
</span>
<SidebarFooter />
</aside>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useStore } from 'vuex'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import Backdrop from '@/global/Backdrop.vue'
import IconLink from '@/IconLink.vue'
import SidebarFooter from './SidebarFooter.vue'
import SidebarHeader from './SidebarHeader.vue'
import useState from '~/hooks/useState'
import { SideMenuItemType } from '~/typs/cmpnts'
import { NavItemType } from '~/typs'
const router = useRouter()
const store = useStore()
const { isSidebarOpen } = useState()
const { t } = useI18n()
const map_key = router.currentRoute.value.meta.uiMapkey || 'ui'
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
const backdrop_blur = useState().backdrop_blur
const sidebarMenuItems = computed((): SideMenuItemType[] => {
const ctx = router.currentRoute.value.meta.ctx || ''
const defsMenuItems = defs.value && defs.value.sidebar && defs.value.sidebar.menu_items ? defs.value.sidebar.menu_items : [] as SideMenuItemType[]
const all_items = [].concat(defsMenuItems || []) // .concat(useState().sidebarMenuItems.value as SideMenuItemType[] | any)
useState().sidebarMenuItems.value = all_items.filter((itm: SideMenuItemType) => {
if (itm.ctx && itm.ctx === ctx) {
return true
} else if (itm.ctx && itm.ctx !== ctx) {
return false
} else {
return true
}
})
return useState().sidebarMenuItems.value
})
const itemClick = (target: string) => {
switch (target) {
case 'home':
useState().bcPath.value = ''
// useState().navTitle.value = ''
router.push('/')
break
default:
}
}
const appItemClick = (itm: SideMenuItemType) => {
if (itm.cllbck) {
itm.cllbck(itm)
isSidebarOpen.value = false
} else {
if (useState().side_menu_click.value) {
try {
useState().side_menu_click.value(itm)
isSidebarOpen.value.value = false
} catch(e) {
console.log(e)
}
} else if (itm.click === 'tophome') {
router.push('/')
}
}
}
const on_logo_app = () => {
useState().bcPath.value = ''
useState().dfltNavTitle()
useState().isSidebarOpen.value = false
if (useState().app_home_click.value) {
useState().app_home_click.value()
}
router.push('/')
}
</script>

View File

@ -1,62 +0,0 @@
<template>
<div class="flex-shrink-0 p-4 border-t dark:border-gray-700 border-gray-200 max-h-14 dark:bg-cool-gray-800 dark:text-white">
<Button
v-if="sidebarFooter.itm.type === NavItemType.a_link"
class="flex w-full text-gray-700 bg-gray-100 hover:bg-gray-700 dark:bg-cool-gray-800 dark:text-gray-100 dark:hover:bg-gray-700"
:class="{'justify-start': isSidebarOpen}"
@click="itemClick(sidebarFooter.itm.click || '')"
>
<!-- LogoutIcon aria-hidden="true" class="w-6 h-6" -->
<span v-if="sidebarFooter.itm.icon_on === 'carbon-logout'"> <carbon-logout /> </span>
<span :class="{ 'lg:hidden': !isSidebarOpen }" class="ml-2"> {{ t(sidebarFooter.itm.title) }} </span>
</Button>
<router-link
v-if="sidebarFooter.itm.type === NavItemType.router_link"
:to="{ name: `${sidebarFooter.itm.name_to === 'Logout' && authData.auth === '' ? 'Login' : 'Logout'}` }"
class="flex w-full text-gray-700 bg-gray-100 dark:bg-cool-gray-800 dark:text-gray-100 dark:hover:bg-gray-700"
:class="{'justify-start': isSidebarOpen}"
>
<span v-if="sidebarFooter.itm.icon_on === 'carbon-logout' && authData.auth !== ''" class="mt-1"> <carbon-logout /> </span>
<span v-else class="mt-1"> <carbon-login /> </span>
<span :class="{ 'lg:hidden': !isSidebarOpen }" class="ml-2"> {{ t(sidebarFooter.itm.title) }} </span>
</router-link>
</div>
</template>
<script setup lang="ts">
import Button from '@/global/Button.vue'
// import LogoutIcon from '@/icons/LogoutIcon.vue'
import { computed } from 'vue'
import { useStore } from 'vuex'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import useState from '~/hooks/useState'
import { NavItemType } from '~/typs'
import { auth_data } from '~/hooks/utils'
const router = useRouter()
const store = useStore()
const { isSidebarOpen } = useState()
const { t } = useI18n()
const map_key = router.currentRoute.value.meta.uiMapkey || 'ui'
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
const authData = computed(() => auth_data())
const sidebarFooter = computed(() => {
return defs.value && defs.value.sidebar && defs.value.sidebar.footer ? defs.value.sidebar.footer : { itm: {} }
})
const itemClick = (target: string) => {
switch (target) {
case 'home':
useState().bcPath.value = ''
useState().navTitle.value = {} as any
router.push('/')
break
}
}
</script>

View File

@ -1,58 +0,0 @@
<template>
<div class="flex items-center justify-between flex-shrink-0 p-2 dark:bg-cool-gray-800 dark:text-white" :class="{ 'lg:justify-center': !isSidebarOpen }">
<span
class="cursor-pointer text-lg lg:text-xl font-semibold leading-8 tracking-wider uppercase whitespace-nowrap dark:bg-cool-gray-800 dark:text-white"
@click="on_logo_app"
>
<div class="flex">
<img class="h-11 w-auto rounded" :src="`${header.logo && header.logo !== '' ? header.logo : '/assets/images/app_w.svg'}`" alt="App">
<span :class="{ 'lg:hidden': !isSidebarOpen }" class="ml-4 mt-2 text-gray-400">{{ header.title || '' }}</span>
</div>
</span>
<button class="rounded-md lg:hidden" @click="isSidebarOpen = false">
<svg
class="w-6 h-6 text-gray-600"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import { useStore } from 'vuex'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import useState from '~/hooks/useState'
const router = useRouter()
const store = useStore()
const { isSidebarOpen } = useState()
const { t, locale } = useI18n()
const map_key = router.currentRoute.value.meta.uiMapkey || 'ui'
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
const header = computed(() => {
return defs.value && defs.value.header ? defs.value.header : {}
})
const on_logo_app = () => {
useState().bcPath.value = ''
useState().dfltNavTitle()
useState().isSidebarOpen.value = false
if (useState().app_home_click.value) {
useState().app_home_click.value()
}
router.push('/')
}
</script>

View File

@ -1,97 +0,0 @@
import { ref } from 'vue'
// import WysiwygEditor from '@/WysiwygEditor.vue'
// // import CodeEditor from '@/CodeEditor.vue'
// import GridSettings from '~/views/GridSettings.vue'
// import GridView from '~/views/GridView.vue'
// import TableView from '~/views/TableView.vue'
// import ListView from '~/views/ListView.vue'
// import FormView from '~/views/FormView.vue'
// import TaFormView from '/app_modules/bm/ta/views/ta_form.vue'
// import TaTableView from '/app_modules/bm/ta/views/ta_table.vue'
// import TaListView from '/app_modules/bm/ta/views/ta_list.vue'
export enum DynComponent {
// GridSettings,
// GridJs,
// TableView,
// ListView,
// FormView,
// WysiwygEditor,
// CodeEditor,
}
const asideComponent = ref({})
const settingsComponent = ref({})
const fullSliderComponent = ref({})
const formViewComponent = ref({})
const dataViewComponent = ref({})
const topPaneComponent = ref({})
const bottomPaneComponent = ref({})
const moduleComponent = ref({})
const getModuleComponent = (key: string, target: string): any => {
// switch (key) {
// case 'ta':
// switch (target) {
// case 'form':
// return TaFormView
// break
// case 'table':
// return TaTableView
// break
// case 'list':
// return TaListView
// break
// }
// break
// }
}
const getComponent = (cmpnt: DynComponent): any => {
// switch (cmpnt) {
// case DynComponent.WysiwygEditor:
// return WysiwygEditor
// break
// // case DynComponent.CodeEditor:
// // return CodeEditor
// // break
// case DynComponent.GridSettings:
// return GridSettings
// break
// case DynComponent.GridJs:
// return GridView
// break
// case DynComponent.TableView:
// return TableView
// break
// case DynComponent.ListView:
// return ListView
// break
// case DynComponent.FormView:
// return FormView
// break
// }
}
export default function useComponent() {
return {
getModuleComponent,
asideComponent,
settingsComponent,
fullSliderComponent,
dataViewComponent,
formViewComponent,
getComponent,
topPaneComponent,
bottomPaneComponent,
moduleComponent,
}
}

View File

@ -1,80 +0,0 @@
const roles = ['Admin', 'Editor', 'User']
const users = [
{
id: 'c27eb2bd-13d3-4231-aa60-e392b5f60d2e',
name: 'Agnes Bogisich',
email: 'Drake61@hotmail.com',
role: roles[Math.round(Math.random() * (roles.length - 1))],
active: true,
},
{
id: 'baca6dbf-4efe-4135-b584-5123dc6e1efa',
name: 'Damaris Huels',
email: 'Alayna.Rohan@yahoo.com',
role: roles[Math.round(Math.random() * (roles.length - 1))],
active: true,
},
{
id: 'ac991968-7f22-41e4-84ba-e62a335607c7',
name: 'Monique Kozey',
email: 'Louisa_Emard@gmail.com',
role: roles[Math.round(Math.random() * (roles.length - 1))],
active: false,
},
{
id: '2b353eda-d96a-47b0-aaed-1871b257abd1',
name: 'Kayden Collier',
email: 'Rosina71@yahoo.com',
role: roles[Math.round(Math.random() * (roles.length - 1))],
active: true,
},
{
id: '697fbe33-fe86-45fc-93e3-bd4335fe4063',
name: 'Kiera Baumbach',
email: 'Ashleigh10@hotmail.com',
role: roles[Math.round(Math.random() * (roles.length - 1))],
active: true,
},
{
id: '0dffdd8d-84f4-4b87-8832-c6f560ebe850',
name: 'Sage Dietrich',
email: 'Ramona70@gmail.com',
role: roles[Math.round(Math.random() * (roles.length - 1))],
active: false,
},
{
id: '46d0a8b6-b2c2-468e-b6d9-89c8520dccfe',
name: 'Jodie Jones',
email: 'Lempi89@gmail.com',
role: roles[Math.round(Math.random() * (roles.length - 1))],
active: true,
},
{
id: 'c8d54e36-f6e8-4c8f-b43a-4228ab11d7a9',
name: 'Blaze Reilly',
email: 'Dakota_Casper@yahoo.com',
role: roles[Math.round(Math.random() * (roles.length - 1))],
active: true,
},
{
id: '47e143af-9e03-4c7c-9fe1-99f3374841cb',
name: 'Margie Douglas',
email: 'Jadyn.Ernser@yahoo.com',
role: roles[Math.round(Math.random() * (roles.length - 1))],
active: true,
},
{
id: 'd40ff313-4a69-4a70-9fc3-398d51e53114',
name: 'Arianna Kilback',
email: 'Fritz.Tremblay@gmail.com',
role: roles[Math.round(Math.random() * (roles.length - 1))],
active: false,
},
]
export default function useData() {
return {
users,
}
}

View File

@ -1,127 +0,0 @@
import { ref, computed } from 'vue'
import type { SideMenuItemType, UiPanelsType } from '~/typs/cmpnts'
const reqError = ref({ defs: '', lang: '', data: '', gql: '', api: '' })
const currentMapKey = ref('')
const isSidebarOpen = ref(false)
const toggleSidebar = () => {
isSidebarOpen.value = !isSidebarOpen.value
}
const showModal = ref(false)
const isAsidePanelOpen = ref(false)
const sideSettingButton = ref(false)
const isSettingsPanelOpen = ref(false)
const isSearchPanelOpen = ref(false)
const usideSettingButton = ref(false)
const isNotificationsPanelOpen = ref(false)
const useSettings = ref(false)
const useSearch = ref(false)
const search = ref('')
const bcPath = ref('')
const navTitle = ref({
text: '',
textclick: null as null | Function,
title: '',
cmpnt: '',
ops: [] as any[],
btntype: '',
cllbck: null as null | Function,
})
const dfltNavTitle = () => {
navTitle.value = {
text: '',
textclick: null as null | Function,
title: '',
cmpnt: '',
ops: [] as any[],
btntype: '',
cllbck: null as null | Function,
}
}
// '#fa-book/biomagnetismo/microorganismos/virus'
const bookCllbck = ref()
const bookSelec = (data: string) => {
if (data === '#') {
bcPath.value = ''
dfltNavTitle()
}
else {
if (bookCllbck.value)
bookCllbck.value(data)
// else ...
}
}
const sidebarMenuItems = ref([] as SideMenuItemType[])
const checkin = ref(false)
const connection = ref({
state: '',
})
const tsksrvcs = 'tsksrvcs'
const appsrvcs = 'appsrvcs'
const srvcstatus = 'srvcstatus'
// const menu_items = ref([
// { id: tsksrvcs, title: 'Tasks', active: false, link: '#' },
// { id: appsrvcs, title: 'Applications', active: false, link: '#' },
// { id: srvcstatus, title: 'Informations', active: false, link: '#' },
// ])
const side_menu_click = ref()
const app_home_click = ref()
const backdrop_blur = ref(14)
const back_opacity = ref(60)
const panels = ref({} as UiPanelsType)
const show_profile = ref(false)
export default function useState() {
return {
reqError,
currentMapKey,
isSidebarOpen,
toggleSidebar,
isAsidePanelOpen,
isSettingsPanelOpen,
isSearchPanelOpen,
isNotificationsPanelOpen,
useSettings,
usideSettingButton,
sideSettingButton,
bcPath,
bookSelec,
bookCllbck,
navTitle,
dfltNavTitle,
checkin,
connection,
sidebarMenuItems,
showModal,
tsksrvcs,
appsrvcs,
srvcstatus,
// menu_items,
side_menu_click,
app_home_click,
useSearch,
search,
back_opacity,
backdrop_blur,
panels,
show_profile,
}
}

View File

@ -1,339 +0,0 @@
// import {
// FixedAdjust,
// DenseFixedAdjust,
// ProminentFixedAdjust,
// ShortFixedAdjust,
// } from "@smui/top-app-bar";
import Toastify from 'toastify-js'
import store from '~/store'
import useState from '~/hooks/useState'
import { AppDefsAction } from '~/store/types'
import { MessageType } from '~/typs'
import 'toastify-js/src/toastify.css'
const { connection } = useState()
// import { postData, sendData } from './api.js'
// https://www.carlrippon.com/fetch-with-async-await-and-typescript/
/*
const headers: HeadersInit = {
'Content-Type': 'application/json',
'X-Request-Id': uuidv4(),
'Authorization': `Bearer <API_TOKEN>`
}
*/
// https://github.com/Maronato/vue-toastification#installation
export const show_message = (typ: MessageType, msg: string, timeout?: number): void => {
// switch (typ) {
// case MessageType.Show:
// toast.show(msg)
// break
// case MessageType.Success:
// toast.success(msg)
// break
// case MessageType.Error:
// toast.error(msg)
// break
// case MessageType.Warning:
// toast.warning(msg)
// break
// case MessageType.Info:
// toast.info(msg)
// break
// }
// if (timeout && timeout > 0)
// setTimeout(toast.clear, timeout)
// https://github.com/apvarun/toastify-js
Toastify({
text: msg,
duration: timeout || 3000,
destination: 'https://github.com/apvarun/toastify-js',
newWindow: true,
className: '',
offset: {
x: 10, // horizontal axis - can be a number or a string indicating unity. eg: '2em'
y: 50, // vertical axis - can be a number or a string indicating unity. eg: '2em
},
close: true,
gravity: 'top', // `top` or `bottom`
position: 'left', // `left`, `center` or `right`
backgroundColor: 'linear-gradient(to right, #00b09b, #96c93d)',
stopOnFocus: true, // Prevents dismissing of toast on hover
onClick() {}, // Callback after click
}).showToast()
}
export const translate = (store: any, map: string, ky: string, ctx: string, dflt?: string): string => {
const val = dflt || ky
const lang = store.state.app_lang.lang.get(map)
// switch (ctx) {
// case 'main':
// val = lang.value.main && lang.value.main[ky] ? lang.value.main[ky] : val
// break
// case 'data':
// val = lang.value.main && lang.value.main[ky] ? lang.value.main[ky] : val
// val = lang.value.data[ky] || val
// break
// case 'forms':
// val = lang.value.forms && lang.value.forms[ky] ? lang.value.forms[ky] : val
// break
// }
if (lang && lang.value)
return lang.value[ctx] && lang.value[ctx][ky] ? lang.value[ctx][ky] : val
else if (lang && lang[ctx])
return lang[ctx][ky] ? lang[ctx][ky] : val
else
return val
}
export const senddata = async<T>(url: RequestInfo, data: BlobPart, file_name?: string, cllbck?: any): Promise<any> => {
const formData = new FormData()
// formData.append('blob', new Blob([JSON.stringify(rowData)]), 'test')
// let response: Ref < T | undefined > = ref()
formData.append('blob', new Blob([data]), file_name)
try {
const response = await fetch(url, {
mode: 'no-cors', // 'cors' by default
method: 'POST',
body: formData,
})
return response
}
catch (err) {
if (cllbck)
cllbck(err)
else
console.log(err)
}
}
export const postdata = (url: string, data: any, file_name: string, cllbck?: any): void => {
if (data && file_name) {
senddata(url, data, file_name, cllbck).then((result: any) => {
if (result.status !== 0) {
console.log(
// throw Error(
`Data sent to ${url} (${file_name}) - Network response NOT OK`,
)
}
else {
console.log(
`Save data to ${url} (${file_name}) status: ${result.status}`,
)
}
if (cllbck)
cllbck(result)
})
}
}
export const fetch_text = async(path: RequestInfo): Promise<any> => {
try {
const response = await fetch(path)
return !response.ok ? response.text() : new Error('No items found')
}
catch (err) {
return err
}
}
export const fetch_json = async(path: RequestInfo, timeout = 2000): Promise<any> => {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async(resolve, reject) => {
try {
const response = await self.fetch(path)
setTimeout(async() => {
resolve(await response.json())
}, timeout)
}
catch (err) {
reject(err)
}
})
}
export const load_data = async(data_path: RequestInfo, ato: number, timeout = 2000, cllbck?: any) => {
// eslint-disable-next-line no-async-promise-executor
// return await new Promise(async(resolve, reject) => {
useState().connection.value.state = ''
const token = localStorage.getItem('auth') || ''
// if (token === '')
// return `error no auth for ${data_path}`
try {
const headers = token !== "" ? { Authorization: `Bearer ${token}`} : {}
// 'content-type': 'application/json',
const res = await self.fetch(data_path, {
headers
})
// setTimeout(async() => {
let dataloaded = {}
try {
let strData = await res.text()
for (let i = 0; i < ato; i++)
strData = atob(strData)
dataloaded = JSON.parse(strData)
}
catch (e) {
return `error ${e} with ${data_path}`
}
if (Object.keys(dataloaded).length) {
if (cllbck)
cllbck(dataloaded)
return ''
}
else {
return new Error('No definitions found')
}
// }, timeout)
}
catch (err) {
show_message(MessageType.Error, `'Data Load' -> ${err}`)
useState().connection.value.state = 'connection.error'
return err
}
// })
}
export const post_data = async(url: string, formData: any, with_auth = true) => {
connection.value.state = ''
let headers = {}
if (with_auth) {
const token = localStorage.getItem('auth') || ''
if (token === '')
return `error no auth for ${url}`
headers = {
'content-type': 'application/json',
'Authorization': `Bearer ${token}`,
// 'Access-Control-Allow-Origin': '*',
// 'Accept': 'application/json',
}
}
else {
headers = { 'content-type': 'application/json' }
}
let formDataJsonString = ''
try {
formDataJsonString = JSON.stringify(formData)
}
catch (e) {
console.log(e)
return
}
try {
const response = await fetch(url, {
method: 'POST',
headers,
body: formDataJsonString,
})
if (!response.ok && response.status !== 200) {
const errorMessage = await response.text()
console.log(errorMessage)
// throw new Error(errorMessage)
}
if (response.ok && response.status === 200)
return response.json()
}
catch (e) {
connection.value.state = 'connection.error'
console.log(e)
}
}
export const check_credentials = async(url: string, data: any): Promise<any> => {
let dataJsonString = ''
try {
dataJsonString = JSON.stringify(data)
}
catch (e) {
console.log(e)
return
}
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
body: dataJsonString,
})
if (!response.ok) {
const errorMessage = await response.text()
// throw new Error(errorMessage)
console.log(errorMessage)
return
}
if (response.ok && response.status === 200)
return response.json()
}
catch (e) {
useState().connection.value.state = 'connection.error'
console.log(e)
}
}
export const run_task = (val: number, task: Function) => {
const now = new Date().getTime()
const timePassed = now % val
const run_at = val - timePassed
setTimeout(task, run_at)
}
export const verify_auth = async(mapkey: string, check_url: string, login_url: string) => {
const auth = localStorage.getItem('auth') || ''
const res = await check_credentials(check_url, { data: auth, mapkey })
if (res && res.token === auth) {
if (res.defs)
store.dispatch(AppDefsAction.addDefs, { key: mapkey, defs: res.defs })
if (res.defs.checkin && res.defs.checkin > 0) {
run_task(res.defs.checkin, async() => {
// console.log('run_task')
const res_task = await verify_auth(mapkey, check_url, login_url)
if (res_task)
return
if (useState().connection.value.state === '')
location.href = login_url
})
}
return res
}
return res
}
export const auth_data = () => {
const auth = localStorage.getItem('auth') || ''
let uidefs = {}
if (store && store.state && store.state.app_defs && store.state.app_defs.main) {
uidefs = store.state.app_defs.main.get('ui')
}
return {auth, uidefs}
}
export const parse_str_json_data = (src: string, dflt: object|any) => {
let data = dflt
try {
data = JSON.parse(src)
}
catch (e) {
data = dflt
}
return data
}
export default {
fetch_text,
fetch_json,
postdata,
senddata,
load_data,
post_data,
// store_data,
show_message,
translate,
check_credentials,
run_task,
verify_auth,
auth_data,
parse_str_json_data,
}

View File

@ -1,224 +0,0 @@
<template>
<div v-if="isCheckin">
<div class="spinner" style="margin: 100px auto; width: 80px; height: 80px;">
<div class="dot1" />
<div class="dot2" />
</div>
<div class="flex justify-center text-2xl">
{{ t('message.loadding') }} ...
</div>
</div>
<div v-else>
<div>
<div class="antialiased text-gray-900 bg-white dark:bg-gray-800 dark:text-white">
<div class="flex h-screen overflow-y-hidden bg-white">
<!-- Sidebar -->
<Sidebar />
<div class="flex flex-col flex-1 h-full overflow-hidden">
<!-- Navbar -->
<header class="flex-shrink-0 border-b dark:border-gray-700 border-gray-200">
<Navbar @on-nav-menu="onNavMenu" />
</header>
<!-- Main content -->
<main class="flex-1 max-h-full overflow-hidden overflow-y-scroll dark:bg-cool-gray-800 dark:text-white">
<slot />
</main>
<!-- Main footer -->
<footer class="flex items-center justify-between flex-shrink-0 p-4 border-t dark:border-gray-700 border-gray-200 max-h-14 dark:bg-cool-gray-800 dark:text-white">
<div class="flex">
<span
v-for="(itm,index) in left_items"
:key="`${String(index)}-${itm.title}`"
>
<a
v-if="itm && itm.type === NavItemType.app_link"
:href="itm.href"
class="text-xs"
>
{{ t(itm.title) }}
</a>
<router-link
v-if="itm && itm.type === 'router_link'"
:title="t(itm.title)"
:to="{ name: itm.name_to }"
class="small-text flex items-center text-shadow-xs"
>
{{ t(itm.title) }}
</router-link>
</span>
</div>
<div class="text-sm">
<Footer />
</div>
<div class="flex">
<span
v-for="(itm,index) in right_items"
:key="`${String(index)}-${itm.title}`"
>
<a
v-if="itm && itm.type === NavItemType.app_link"
:href="itm.href"
class="flex items-center"
>
<span class="hidden text-sm md:block mr-2"> {{ t(itm.title) }} </span>
<span v-if="itm.img" class="w-11 h-11 mr-2">
<app-img v-if="itm.img === 'librecloudd'" />
<img v-else class="h-11 w-auto rounded" :src="`/assets/images/${itm.img}.svg`" alt="App">
</span>
</a>
<router-link
v-if="itm && itm.type === 'router_link'"
:title="t(itm.title)"
:to="{ name: itm.name_to }"
class="flex items-center"
>
<span class="hidden text-sm md:block mr-2"> {{ t(itm.title) }} </span>
<span v-if="itm.img" class="w-11 h-11 mr-2">
<app-img v-if="itm.img === 'librecloudd'" />
<img v-else class="h-11 w-auto" :src="`/assets/images/${itm.img}.svg`" alt="App">
</span>
</router-link>
</span>
</div>
</footer>
</div>
<!-- Setting panel button -->
<div v-if="sideSettingButton" v-show="useSettings" class="fixed right-0 transform rotate-90 translate-x-8 top-1/2">
<Button class="text-sm font-medium z-999 text-white uppercase bg-gray-600" @click="isSettingsPanelOpen = true">
Settings
</Button>
</div>
<SettingsPanel :show="isSettingsPanelOpen" @close="isSettingsPanelOpen = false" />
<SearchPanel left :show="isSearchPanelOpen" @close="isSearchPanelOpen = false" />
<NotificationsPanel left :show="isNotificationsPanelOpen" @close="isNotificationsPanelOpen = false" />
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
/*
<suspense v-else>
<template #default>
</template>
<template #fallback>
<div class="space-up">
<div class="spinner" style="margin: 100px auto; width: 80px; height: 80px;">
<div class="dot1" />
<div class="dot2" />
</div>
<div class="flex justify-center text-2xl">
Check-in ...
</div>
</div>
</template>
</suspense>
<div>
<a
href="https://karyo.dev"
target="_blank"
class="flex items-center space-x-1"
>
<span class="w-11 h-11 dark:bg-gray-200 rounded-full mr-2">
<dsc-logo />
</span>
<span class="hidden text-sm md:block">Z-Terton</span>
</a>
</div>
*/
import { onMounted, onUnmounted, ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import Sidebar from '@/sidebar/Sidebar.vue'
import Navbar from '@/navbar/Navbar.vue'
import SettingsPanel from '@/panels/SettingsPanel.vue'
import SearchPanel from '@/panels/SearchPanel.vue'
import NotificationsPanel from '@/panels/NotificationsPanel.vue'
import Button from '@/global/Button.vue'
import Footer from '@/Footer.vue'
import AppImg from '@/icons/AppImg.vue'
import { useI18n } from 'vue-i18n'
import { useStore } from 'vuex'
import useState from '~/hooks/useState'
import { SideMenuItemType } from '~/typs/cmpnts'
import { NavItemType } from '~/typs'
// import { AppDefsAction } from '~/store/types'
// import useComponent, { DynComponent } from '~/hooks/useComponent'
// import { check_credentials } from '~/hooks/utils'
//const { reqError, isSidebarOpen, isAsidePanelOpen, isSettingsPanelOpen, isSearchPanelOpen, isNotificationsPanelOpen, sideSettingButton } = useState()
const { isSidebarOpen, isSettingsPanelOpen, isSearchPanelOpen, isNotificationsPanelOpen, sideSettingButton, useSettings } = useState()
const checkScreen = () => {
if (window.innerWidth <= 1024)
isSidebarOpen.value = false
}
// const props = defineProps<{
// appdefs: any
// }>()
// const { appdefs } = toRefs(props)
// const use_panels = true
// const show_top_pane = ref(false)
// const show_bottom_pane = ref(false)
const isCheckin = ref(true)
const { t } = useI18n()
const router = useRouter()
const map_key = router.currentRoute.value.meta.uiMapkey || 'ui'
const store = useStore()
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
const left_items = computed((): SideMenuItemType[] => {
return defs.value && defs.value.footer && defs.value.footer.left_items ? defs.value.footer.left_items : [] as SideMenuItemType[]
})
const right_items = computed((): SideMenuItemType[] => {
return defs.value && defs.value.footer && defs.value.footer.right_items ? defs.value.footer.right_items : [] as SideMenuItemType[]
})
const onNavMenu = (itm: SideMenuItemType) => {
useState().show_profile.value = true
}
onMounted(() => {
window.addEventListener('resize', checkScreen)
isCheckin.value = false
})
// const topPaneComponent = computed(() => useComponent().topPaneComponent.value)
// const bottomPaneComponent = computed(() => useComponent().bottomPaneComponent.value)
// const root_url = router.currentRoute.value.meta.rooturl || ''
onUnmounted(() => {
window.removeEventListener('resize', checkScreen)
})
</script>
<style scoped>
.small-text {
font-size: 75%;
}
.expandable {
background: #dadada;
overflow: hidden;
transition: all .5s ease-in-out;
line-height: 0;
padding: 0 1em;
color: transparent;
}
.expandable:target {
line-height: 1.5;
padding-top: 1em;
padding-bottom: 1em;
color: black;
}
</style>

View File

@ -1,7 +0,0 @@
<template>
<div class="flex flex-col items-center justify-center min-h-screen p-4 space-y-4 antialiased text-gray-900 bg-white">
<slot />
</div>
</template>
<script setup></script>

View File

@ -1,27 +0,0 @@
<script setup lang="ts">
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
const router = useRouter()
const { t } = useI18n()
</script>
<template>
<main class="px-4 py-10 text-center text-teal-700 dark:text-gray-200">
<div>
<p class="text-4xl">
<carbon-warning class="inline-block" />
</p>
</div>
<router-view />
<slot />
<div>
<button
class="btn m-3 text-sm mt-8"
@click="router.back()"
>
{{ t('button.back') }}
</button>
</div>
</main>
</template>

View File

@ -1,7 +0,0 @@
<template>
<div class="antialiased text-gray-900 bg-white">
<slot />
</div>
</template>
<script setup></script>

View File

@ -1,9 +0,0 @@
<template>
<main class="px-4 py-10 text-center text-gray-700 dark:text-gray-200">
<router-view />
<Footer />
<div class="mt-5 mx-auto text-center opacity-25 text-sm">
[Default Layout]
</div>
</main>
</template>

View File

@ -1,30 +0,0 @@
<template>
<main class="px-4 py-10 text-center text-gray-700 dark:text-gray-200">
<router-view />
<Footer />
<div class="mt-5 mx-auto text-center opacity-25 text-sm">
[Home Layout]
</div>
<router-link to="/datalist">
Data List
</router-link>
</main>
</template>
<script lang="ts">
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
export default {
setup() {
onBeforeRouteUpdate((to: any, from: any) => {
})
onBeforeRouteLeave((to, from) => {
// console.log(to);
// const answer = window.confirm(
// 'Do you really want to leave? you have unsaved changes!'
// )
// // cancel the navigation and stay on the same page
// if (!answer) return false
})
},
}
</script>

View File

@ -1,2 +0,0 @@
export const isDark = useDark()
export const toggleDark = useToggle(isDark)

View File

@ -1 +0,0 @@
export * from './dark'

View File

@ -1,59 +0,0 @@
// windicss layers
import 'virtual:windi-base.css'
import 'virtual:windi-components.css'
// your custom styles here
import './styles/main.css'
// windicss utilities should be the last style import
import 'virtual:windi-utilities.css'
// windicss devtools support (dev only)
import 'virtual:windi-devtools'
import VueAnimXYZ from '@animxyz/vue' // import AnimXZY vue package
import '@animxyz/core'
// register vue composition api globally
import { createApp } from 'vue'
// import { createRouter, createWebHistory } from 'vue-router'
import { createI18n } from 'vue-i18n'
import { createHead, useHead } from '@vueuse/head'
import App from './App.vue'
import routes from './router'
import store from './store'
import 'a17t'
import { messages } from './modules/i18n'
// import GuestLayout from '~/layouts/GuestLayout.vue'
import AppLayout from '~/layouts/AppLayout.vue'
import SimpleLayout from '~/layouts/SimpleLayout.vue'
const app = createApp(App)
const i18n = createI18n({
locale: 'es',
legacy: false,
fallbackLocale: ['es'],
fallbackWarn: false,
missing: (locale, key, instance) => {
console.warn(`detect '${key}' key missing in '${locale}'`)
},
messages,
})
const head = createHead()
// const router = createRouter({
// history: createWebHistory(),
// routes,
// })
app.use(VueAnimXYZ)
app.use(store)
app.use(i18n)
app.use(routes)
// app.use(router)
app.use(head)
app.component('AppLayout', AppLayout)
app.component('SimpleLayout', SimpleLayout)
// app.component('GuestLayout', GuestLayout)
app.mount('#app')

View File

@ -1,11 +0,0 @@
## Modules
A custom user module system. Place a `.ts` file with the following template, it will be installed automatically.
```ts
import { UserModule } from '~/types'
export const install: UserModule = ({ app, router, isClient }) => {
// do something
}
```

View File

@ -1,25 +0,0 @@
import { createI18n } from 'vue-i18n'
// import { UserModule } from '~/types'
// import i18n resources
// https://vitejs.dev/guide/features.html#glob-import
export const messages = Object.fromEntries(
Object.entries(
import.meta.globEager('../../locales/*.y(a)?ml'))
.map(([key, value]) => {
const yaml = key.endsWith('.yaml')
return [key.slice(14, yaml ? -5 : -4), value.default]
}),
)
/*
export const install: UserModule = ({ app }) => {
const i18n = createI18n({
legacy: false,
locale: 'en',
messages,
})
app.use(i18n)
}
*/

View File

@ -1,9 +0,0 @@
import NProgress from 'nprogress'
import { UserModule } from '~/types'
export const install: UserModule = ({ isClient, router }) => {
if (isClient) {
router.beforeEach(() => { NProgress.start() })
router.afterEach(() => { NProgress.done() })
}
}

View File

@ -1,12 +0,0 @@
import { UserModule } from '~/types'
export const install: UserModule = ({ isClient, router }) => {
if (isClient) {
router.isReady().then(async() => {
if (isClient) {
const { registerSW } = await import('virtual:pwa-register')
registerSW({ immediate: true })
}
})
}
}

View File

@ -1,20 +0,0 @@
## File-based Routing
Routes will be auto-generated for Vue files in this dir with the same file structure.
Check out [`vite-plugin-pages`](https://github.com/hannoeru/vite-plugin-pages) for more details.
### Path Aliasing
`~/` is aliased to `./src/` folder.
For example, instead of having
```ts
import { isDark } from '../../../../logic'
```
now, you can use
```ts
import { isDark } from '~/logic'
```

View File

@ -1,5 +0,0 @@
<template>
<div>
Not Found
</div>
</template>

View File

@ -1,52 +0,0 @@
<script setup lang="ts">
const name = ref('')
const router = useRouter()
const go = () => {
if (name.value)
router.push(`/hi/${encodeURIComponent(name.value)}`)
}
</script>
<template>
<div>
<p class="text-4xl">
<carbon-campsite class="inline-block" />
</p>
<p>
<a rel="noreferrer" href="https://github.com/antfu/vitesse-lite" target="_blank">
Vitesse Lite
</a>
</p>
<p>
<em class="text-sm opacity-75">Opinionated Vite Starter Template</em>
</p>
<div class="py-4" />
<input
id="input"
v-model="name"
placeholder="What's your name?"
type="text"
autocomplete="false"
p="x-4 y-2"
w="250px"
text="center"
bg="transparent"
border="~ rounded gray-200 dark:gray-700"
outline="none active:none"
@keydown.enter="go"
>
<div>
<button
class="m-3 text-sm btn"
:disabled="!name"
@click="go"
>
Go
</button>
</div>
</div>
</template>

View File

@ -1,27 +0,0 @@
<script setup lang="ts">
const props = defineProps<{ name: string }>()
const router = useRouter()
</script>
<template>
<div>
<p class="text-4xl">
<carbon-pedestrian class="inline-block" />
</p>
<p>
Hi, {{ props.name }}
</p>
<p class="text-sm opacity-50">
<em>Dynamic route!</em>
</p>
<div>
<button
class="btn m-3 text-sm mt-8"
@click="router.back()"
>
Back
</button>
</div>
</div>
</template>

View File

@ -1,235 +0,0 @@
// eslint-disable-next-line no-unused-vars
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
// import { defineAsyncComponent } from 'vue'
import { setupLayouts } from 'virtual:generated-layouts'
import generatedRoutes from 'virtual:generated-pages'
// import generatedRoutes from 'pages-generated'
// import { setupLayouts } from 'layouts-generated'
import useState from '~/hooks/useState'
// const Login = defineAsyncComponent(() => import('./views/Login.vue'))
import store from '~/store'
import Home from '~/views/Home.vue'
import About from '~/views/about.md'
// import Register from '~/views/auth/Register.vue'
import Login from '~/views/Login.vue'
import Logout from '~/views/Logout.vue'
import Profile from '~/components/Profile.vue'
import { verify_auth, check_credentials } from '~/hooks/utils'
// import {
// lang_url,
// req_lang,
// } from '~/defs/ta_defs'
// const DataGrid = () => import('~/views/DataGrid.vue')
//const SambaModel = () => import('~/views/SambaModel.vue')
const layoutsRoutes = setupLayouts(generatedRoutes)
/*
// import routes generated by Voie
import pgRoutes from 'voie-pages'
const UIElements = defineAsyncComponent(() => import('./views/UIElements.vue'))
const Tables = defineAsyncComponent(() => import('./views/Tables.vue'))
const Dashboard = defineAsyncComponent(() => import('./views/Dashboard.vue'))
const Forms = defineAsyncComponent(() => import('./views/Forms.vue'))
const Input = defineAsyncComponent(() => import('./views/Input.vue'))
const Home = defineAsyncComponent(() => import('./views/Home.vue'))
const Modal = defineAsyncComponent(() => import('./views/Modal.vue'))
const Blank = defineAsyncComponent(() => import('./views/Blank.vue'))
const OLogin = defineAsyncComponent(() => import('./views/OLogin.vue'))
const Entry = defineAsyncComponent(() => import('./views/Entry.vue'))
*/
// https://medium.com/swlh/adding-meta-fields-and-transitions-to-vue-router-routes-f5cb78a7ed97
// router.beforeEach((to, from, next) => {
// if (to.meta.requireAuth) {
// if (!localStorage.getItem("auth")) {
// next('/notfound')
// } else {
// next();
// }
// } else {
// next();
// }
// });
// const get_lang = (_to: any, _from: any, next: any) => {
// req_lang(lang_url, (lang: any) => { lng: lang })
// // req_lang(lang_url, () => next())
// }
const rooturl = window.ROOT_LOCATION || location.origin
const check_auth = async(to: any, _from: any, next: any) => {
useState().bcPath.value = ''
const auth = localStorage.getItem('auth') || ''
const check_url = `${window.ROOT_LOCATION || location.origin}/checkin`
const login_url = `${location.origin}/ui/login`
const login_route = '/login'
const mapkey = to.meta.uimapkey || 'ui'
const map_route_to = () => {
if (to.meta.requireAuth) {
return login_route
}
if (to.meta.pubLayout) {
to.meta.layout = to.meta.pubLayout
to.meta.useNav = !to.meta.useNav
}
return
}
if (auth !== '') {
const defs = store.state.app_defs.main.get(mapkey)
if (defs && defs.checkin && useState().checkin.value) {
next()
}
else {
useState().checkin.value = true
const res = await verify_auth(mapkey, check_url, login_url)
// if (useState().connection.value.state === '')
// TODO redirect to a connection error page or consider PWA offline mode
if (res && res.defs)
next()
else {
const route=map_route_to()
next(route)
}
}
}
else {
const route=map_route_to()
next(route)
}
}
const get_defs = async(mapkey: string) => {
const auth = localStorage.getItem('auth') || ''
const url = `${window.ROOT_LOCATION || location.origin}/checkin`
if (auth !== '') {
const res = await check_credentials(url, { data: auth, mapkey })
if (res.token === auth)
return res.defs || {}
else
return {}
}
else {
return {}
}
}
const routes: RouteRecordRaw[] = [
/*
{
path: '/home',
alias: '/',
name: 'Home',
component: Home,
meta: { layout: 'empty' },
},
{
path: '/ui/samba',
name: 'Samba',
component: SambaModel,
meta: { layout: 'AppLayout' },
},
*/
{
path: '/',
name: 'Home',
component: Home,
meta: {
requireAuth: false,
layout: 'AppLayout',
ctx: 'home',
// useNav: false,
// pubLayout: 'SimpleLayout',
mapkey: 'kloud',
uiMapkey: 'ui',
rooturl,
},
beforeEnter: check_auth,
// (_to: any, _from: any, next: any) => {
// req_lang(lang_url, () => next())
// },
},
{
path: '/login',
name: 'Login',
component: Login,
meta: { layout: 'empty', rooturl, use_logo: true, allow_register: false, allow_reset: false },
},
{
path: '/logout',
name: 'Logout',
component: Logout,
meta: { layout: 'empty', rooturl, use_logo: true },
},
{
path: '/about',
name: 'About',
meta: {
layout: 'AppLayout',
ctx: 'about',
rooturl,
use_loog: true,
},
component: About,
},
{
path: '/profile',
name: 'Profile',
meta: {
layout: 'AppLayout',
ctx: 'profile',
rooturl,
use_loog: true,
},
component: Profile,
},
// {
// path: '/auth/register',
// name: 'Register',
// component: Register,
// meta: { layout: 'GuestLayout' },
// },
/*
{
path: '/datalist',
name: 'DataGrid',
component: DataGrid,
meta: {
requireAuth: true,
layout: 'AppLayout',
uiMapkey: 'ui',
mapkey: 'kloud',
rooturl,
bcpath: '#fa-book/librecloud/klouds',
},
beforeEnter: check_auth,
// props: { lang: 'es' }, // get_lang,
// beforeEnter: get_lang,
// (_to: any, _from: any, next: any) => {
// req_lang(lang_url, () => next())
// },
},
*/
{
path: '/:catchAll(.*)',
name: '404',
meta: { layout: 'Page404' },
component: () => import('./views/404.vue'),
},
...layoutsRoutes,
]
// const routes: RouteRecordRaw[] = pgRoutes
const router: any = createRouter({
history: createWebHistory(),
routes,
})
// routes,
export default router

57
src/shims.d.ts vendored
View File

@ -1,57 +0,0 @@
/* eslint-disable import/no-duplicates */
declare interface Window {
// extend the window
ROOT_LOCATION: string
}
// with vite-plugin-md, markdowns can be treat as Vue components
declare module '*.md' {
import { ComponentOptions } from 'vue'
const component: ComponentOptions
export default component
}
/*
declare module '*.vue' {
import Vue from 'vue'
export default Vue
}
*/
declare const _APP_VERSION: string
/*
* Keep states in the global scope to be reusable across Vue instances.
*
* @see {@link /createGlobalState}
* @param stateFactory A factory function to create the state
*/
/*
declare function createGlobalState<T extends object>(
stateFactory: () => T
): () => T
*/
interface EventTarget {
value: EventTarget|null
name: string| null
/**
* Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched.
*
* The options argument sets listener-specific options. For compatibility this can be a boolean, in which case the method behaves exactly as if the value was specified as options's capture.
*
* When set to true, options's capture prevents callback from being invoked when the event's eventPhase attribute value is BUBBLING_PHASE. When false (or not present), callback will not be invoked when event's eventPhase attribute value is CAPTURING_PHASE. Either way, callback will be invoked if event's eventPhase attribute value is AT_TARGET.
*
* When set to true, options's passive indicates that the callback will not cancel the event by invoking preventDefault(). This is used to enable performance optimizations described in § 2.8 Observing event listeners.
*
* When set to true, options's once indicates that the callback will only be invoked once after which the event listener will be removed.
*
* The event listener is appended to target's event listener list and is not appended if it has the same type, callback, and capture.
*/
addEventListener(type: string, listener: EventListenerOrEventListenerObject | null, options?: boolean | AddEventListenerOptions): void
/**
* Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise.
*/
dispatchEvent(event: Event): boolean
/**
* Removes the event listener in target's event listener list with the same type, callback, and options.
*/
removeEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void
}

View File

@ -1,61 +0,0 @@
import { InjectionKey } from 'vue'
import {
createStore,
createLogger,
Store as VuexStore,
useStore as baseUseStore,
} from 'vuex'
import {
app_data,
AppDataState,
app_check,
AppCheckState,
app_defs,
AppDefsState,
app_profile,
AppProfileState,
AppLangState,
app_lang,
} from './modules'
import { Store as AppDataStore } from './modules/app/data'
import { Store as AppCheckStore } from './modules/app/check'
import { Store as AppDefsStore } from './modules/app/defs'
import { Store as AppProfileStore } from './modules/app/profile'
import { Store as AppLangStore } from './modules/app/lang'
export interface RootState {
data: AppDataState
check: AppCheckState
defs: AppDefsState
profile: AppProfileState
lang: AppLangState
}
export type RootStore = AppDataStore<Pick<RootState, 'data'>>
& AppCheckStore<Pick<RootState, 'check'>>
& AppDefsStore<Pick<RootState, 'defs'>>
& AppProfileStore<Pick<RootState, 'profile'>>
& AppLangStore<Pick<RootState, 'lang'>>
// eslint-disable-next-line symbol-description
export const key: InjectionKey<VuexStore<RootState>> = Symbol()
const debug = process.env.NODE_ENV !== 'production'
export default createStore<RootState>({
modules: {
app_data,
app_check,
app_defs,
app_profile,
app_lang,
},
strict: debug,
plugins: debug ? [createLogger()] : [],
})
// export const useStore = (): RootStore => {
// return baseUseStore(key)
// }

View File

@ -1,44 +0,0 @@
import { ActionContext, ActionTree } from 'vuex'
import { Mutations, MutationTypes } from './mutations'
import { State } from './index'
import { RootState } from '~/store/index'
export enum ActionTypes {
addCheck = 'addCheck',
removeCheck = 'removeCheck',
editCheck = 'editCheck'
}
type AppCheckActionContext = {
commit<K extends keyof Mutations>(
key: K,
payload: Parameters<Mutations[K]>[1]
): ReturnType<Mutations[K]>
} & Omit<ActionContext<State, RootState>, 'commit'>
export interface Actions {
[ActionTypes.addCheck](
{ commit }: AppCheckActionContext,
payload: any
): void
[ActionTypes.removeCheck](
{ commit }: AppCheckActionContext,
payload: any
): void
[ActionTypes.editCheck](
{ commit }: AppCheckActionContext,
payload: any
): void
}
export const actions: ActionTree<State, RootState> & Actions = {
[ActionTypes.addCheck]({ commit }, payload) {
commit(MutationTypes.addCheck, payload)
},
[ActionTypes.removeCheck]({ commit }, payload) {
commit(MutationTypes.removeCheck, payload)
},
[ActionTypes.editCheck]({ commit }, payload) {
commit(MutationTypes.editCheck, payload)
},
}

View File

@ -1,13 +0,0 @@
import { GetterTree } from 'vuex'
import { State } from './index'
import { RootState } from '~/store/index'
export type Getters<S = State> = {
check(state: S, key: string): any
}
export const getters: GetterTree<State, RootState> & Getters = {
check: (state, key: string) => {
return state.check.get(key)
},
}

View File

@ -1,49 +0,0 @@
import {
Store as VuexStore,
Module,
CommitOptions,
DispatchOptions,
} from 'vuex'
import { getters, Getters } from './getters'
import { mutations, Mutations, MutationTypes } from './mutations'
import { actions, Actions, ActionTypes } from './actions'
import { RootState } from '~/store/index'
interface State {
check: Map<string, any>
}
const state: State = {
check: new Map(),
}
const data_module: Module<State, RootState> = {
state,
mutations,
actions,
getters,
}
export default data_module
type Store<S = State> = Omit<VuexStore<S>, 'commit' | 'getters' | 'dispatch' > & {
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
key: K,
payload: P,
options?: CommitOptions
): ReturnType<Mutations[K]>
} & {
getters: {
[K in keyof Getters]: ReturnType<Getters[K]>
}
} & {
dispatch<K extends keyof Actions>(
key: K,
payload: Parameters<Actions[K]>[1],
options?: DispatchOptions
): ReturnType<Actions[K]>
}
export { State, ActionTypes, MutationTypes, Store }

View File

@ -1,48 +0,0 @@
import { MutationTree } from 'vuex'
import { State } from './index'
import { AppCheck } from '~/store/types'
export enum MutationTypes {
addCheck = 'addCheck',
removeCheck = 'removeCheck',
editCheck = 'editCheck'
}
interface CheckMap {
key: string
check: any
}
export type Mutations<S = State> = {
[MutationTypes.addCheck](state: S, check_map: CheckMap): void
[MutationTypes.removeCheck](state: S, check_map: CheckMap): void
[MutationTypes.editCheck](state: S, check_map: CheckMap, key: string): void
}
export const mutations: MutationTree<State> & Mutations = {
[MutationTypes.addCheck](state: State, check_map: CheckMap) {
if (check_map.key && check_map.check)
state.check.set(check_map.key, check_map.check)
},
[MutationTypes.removeCheck](state: State, check_map: CheckMap) {
if (check_map.key && check_map.check) {
const check = state.check.get(check_map.key)
check.splice(check.indexOf(check_map.check), 1)
state.check.set(check_map.key, check)
}
},
[MutationTypes.editCheck](state: State, check_map: CheckMap) {
if (check_map.key && check_map.check) {
const new_check = [] as unknown as any
const check = state.check.get(check_map.key)
const key = check_map.check.id
check.forEach((it: any) => {
if (it.id === key)
new_check.push(check)
else
new_check.push(it)
})
state.check.set(check_map.key, new_check)
}
},
}

View File

@ -1,44 +0,0 @@
import { ActionContext, ActionTree } from 'vuex'
import { Mutations, MutationTypes } from './mutations'
import { State } from './index'
import { RootState } from '~/store/index'
export enum ActionTypes {
addData = 'addData',
removeData = 'removeData',
editData = 'editData'
}
type AppDataActionContext = {
commit<K extends keyof Mutations>(
key: K,
payload: Parameters<Mutations[K]>[1]
): ReturnType<Mutations[K]>
} & Omit<ActionContext<State, RootState>, 'commit'>
export interface Actions {
[ActionTypes.addData](
{ commit }: AppDataActionContext,
payload: any
): void
[ActionTypes.removeData](
{ commit }: AppDataActionContext,
payload: any
): void
[ActionTypes.editData](
{ commit }: AppDataActionContext,
payload: any
): void
}
export const actions: ActionTree<State, RootState> & Actions = {
[ActionTypes.addData]({ commit }, payload) {
commit(MutationTypes.addData, payload)
},
[ActionTypes.removeData]({ commit }, payload) {
commit(MutationTypes.removeData, payload)
},
[ActionTypes.editData]({ commit }, payload) {
commit(MutationTypes.editData, payload)
},
}

View File

@ -1,13 +0,0 @@
import { GetterTree } from 'vuex'
import { State } from './index'
import { RootState } from '~/store/index'
export type Getters<S = State> = {
data(state: S, key: string): any
}
export const getters: GetterTree<State, RootState> & Getters = {
data: (state, key: string) => {
return state.data.get(key)
},
}

View File

@ -1,49 +0,0 @@
import {
Store as VuexStore,
Module,
CommitOptions,
DispatchOptions,
} from 'vuex'
import { getters, Getters } from './getters'
import { mutations, Mutations, MutationTypes } from './mutations'
import { actions, Actions, ActionTypes } from './actions'
import { RootState } from '~/store/index'
interface State {
data: Map<string, any>
}
const state: State = {
data: new Map(),
}
const data_module: Module<State, RootState> = {
state,
mutations,
actions,
getters,
}
export default data_module
type Store<S = State> = Omit<VuexStore<S>, 'commit' | 'getters' | 'dispatch' > & {
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
key: K,
payload: P,
options?: CommitOptions
): ReturnType<Mutations[K]>
} & {
getters: {
[K in keyof Getters]: ReturnType<Getters[K]>
}
} & {
dispatch<K extends keyof Actions>(
key: K,
payload: Parameters<Actions[K]>[1],
options?: DispatchOptions
): ReturnType<Actions[K]>
}
export { State, ActionTypes, MutationTypes, Store }

View File

@ -1,48 +0,0 @@
import { MutationTree } from 'vuex'
import { State } from './index'
import { AppData } from '~/store/types'
export enum MutationTypes {
addData = 'addData',
removeData = 'removeData',
editData = 'editData'
}
interface DataMap {
key: string
data: any
}
export type Mutations<S = State> = {
[MutationTypes.addData](state: S, data_map: DataMap): void
[MutationTypes.removeData](state: S, data_map: DataMap): void
[MutationTypes.editData](state: S, data_map: DataMap, key: string): void
}
export const mutations: MutationTree<State> & Mutations = {
[MutationTypes.addData](state: State, data_map: DataMap) {
if (data_map.key && data_map.data)
state.data.set(data_map.key, data_map.data)
},
[MutationTypes.removeData](state: State, data_map: DataMap) {
if (data_map.key && data_map.data) {
const data = state.data.get(data_map.key)
data.splice(data.indexOf(data_map.data), 1)
state.data.set(data_map.key, data)
}
},
[MutationTypes.editData](state: State, data_map: DataMap) {
if (data_map.key && data_map.data) {
const new_data = [] as unknown as any
const data = state.data.get(data_map.key)
const key = data_map.data.id
data.forEach((it: any) => {
if (it.id === key)
new_data.push(data)
else
new_data.push(it)
})
state.data.set(data_map.key, new_data)
}
},
}

View File

@ -1,44 +0,0 @@
import { ActionContext, ActionTree } from 'vuex'
import { Mutations, MutationTypes } from './mutations'
import { State } from './index'
import { RootState } from '~/store/index'
export enum ActionTypes {
addDefs = 'addDefs',
removeDefs = 'removeDefs',
editDefs = 'editDefs'
}
type AppDefsActionContext = {
commit<K extends keyof Mutations>(
key: K,
payload: Parameters<Mutations[K]>[1]
): ReturnType<Mutations[K]>
} & Omit<ActionContext<State, RootState>, 'commit'>
export interface Actions {
[ActionTypes.addDefs](
{ commit }: AppDefsActionContext,
payload: any
): void
[ActionTypes.removeDefs](
{ commit }: AppDefsActionContext,
payload: any
): void
[ActionTypes.editDefs](
{ commit }: AppDefsActionContext,
payload: any
): void
}
export const actions: ActionTree<State, RootState> & Actions = {
[ActionTypes.addDefs]({ commit }, payload) {
commit(MutationTypes.addDefs, payload)
},
[ActionTypes.removeDefs]({ commit }, payload) {
commit(MutationTypes.removeDefs, payload)
},
[ActionTypes.editDefs]({ commit }, payload) {
commit(MutationTypes.editDefs, payload)
},
}

View File

@ -1,13 +0,0 @@
import { GetterTree } from 'vuex'
import { State } from './index'
import { RootState } from '~/store/index'
export type Getters<S = State> = {
defs(state: S, key: string): any
}
export const getters: GetterTree<State, RootState> & Getters = {
defs: (state, key: string) => {
return state.main.get(key)
},
}

View File

@ -1,49 +0,0 @@
import {
Store as VuexStore,
Module,
CommitOptions,
DispatchOptions,
} from 'vuex'
import { getters, Getters } from './getters'
import { mutations, Mutations, MutationTypes } from './mutations'
import { actions, Actions, ActionTypes } from './actions'
import { RootState } from '~/store/index'
interface State {
main: Map<string, any>
}
const state: State = {
main: new Map(),
}
const data_module: Module<State, RootState> = {
state,
mutations,
actions,
getters,
}
export default data_module
type Store<S = State> = Omit<VuexStore<S>, 'commit' | 'getters' | 'dispatch' > & {
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
key: K,
payload: P,
options?: CommitOptions
): ReturnType<Mutations[K]>
} & {
getters: {
[K in keyof Getters]: ReturnType<Getters[K]>
}
} & {
dispatch<K extends keyof Actions>(
key: K,
payload: Parameters<Actions[K]>[1],
options?: DispatchOptions
): ReturnType<Actions[K]>
}
export { State, ActionTypes, MutationTypes, Store }

View File

@ -1,47 +0,0 @@
import { MutationTree } from 'vuex'
import { State } from './index'
export enum MutationTypes {
addDefs = 'addDefs',
removeDefs = 'removeDefs',
editDefs = 'editDefs'
}
interface DefsMap {
key: string
defs: any
}
export type Mutations<S = State> = {
[MutationTypes.addDefs](state: S, defs_map: DefsMap): void
[MutationTypes.removeDefs](state: S, defs_map: DefsMap): void
[MutationTypes.editDefs](state: S, defs_map: DefsMap, key: string): void
}
export const mutations: MutationTree<State> & Mutations = {
[MutationTypes.addDefs](state: State, defs_map: DefsMap) {
if (defs_map.key && defs_map.defs)
state.main.set(defs_map.key, defs_map.defs)
},
[MutationTypes.removeDefs](state: State, defs_map: DefsMap) {
if (defs_map.key && defs_map.defs) {
const defs = state.main.get(defs_map.key)
defs.splice(defs.indexOf(defs_map.defs), 1)
state.main.set(defs_map.key, defs)
}
},
[MutationTypes.editDefs](state: State, defs_map: DefsMap) {
if (defs_map.key && defs_map.defs) {
const new_defs = [] as unknown as any
const defs = state.main.get(defs_map.key)
const key = defs_map.defs.id
defs.forEach((it: any) => {
if (it.id === key)
new_defs.push(defs)
else
new_defs.push(it)
})
state.main.set(defs_map.key, new_defs)
}
},
}

View File

@ -1,35 +0,0 @@
import data_module, { State as DataState, MutationTypes as DataMutationTypes, ActionTypes as DataActionTypes, Store as DataStore } from './data'
import check_module, { State as CheckState, MutationTypes as CheckMutationTypes, ActionTypes as CheckActionTypes, Store as CheckStore } from './check'
import defs_module, { State as DefsState, MutationTypes as DefsMutationTypes, ActionTypes as DefsActionTypes, Store as DefsStore } from './defs'
import profile_module, { State as ProfileState, MutationTypes as ProfileMutationTypes, ActionTypes as ProfileActionTypes, Store as ProfileStore } from './profile'
import lang_module, { State as LangState, MutationTypes as LangMutationTypes, ActionTypes as LangActionTypes, Store as LangStore } from './lang'
export const AppDataMutationTypes = DataMutationTypes
export const AppCheckMutationTypes = CheckMutationTypes
export const AppDefsMutationTypes = DefsMutationTypes
export const AppProfileMutationTypes = ProfileMutationTypes
export const AppLangMutationTypes = LangMutationTypes
export const AppDataActionTypes = DataActionTypes
export const AppCheckActionTypes = CheckActionTypes
export const AppDefsActionTypes = DefsActionTypes
export const AppProfileActionTypes = ProfileActionTypes
export const AppLangActionTypes = LangActionTypes
export type AppDataState= DataState
export type AppCheckState= CheckState
export type AppDefsState= DefsState
export type AppProfileState= ProfileState
export type AppLangState= LangState
export type AppDataStore = DataStore
export type AppCheckStore = CheckStore
export type AppDefsStore = DefsStore
export type AppProfileStore = ProfileStore
export type AppLangStore = LangStore
export const app_data = data_module
export const app_check = check_module
export const app_defs = defs_module
export const app_profile = profile_module
export const app_lang = lang_module

View File

@ -1,68 +0,0 @@
import { ActionContext, ActionTree } from 'vuex'
import { Mutations, MutationTypes } from './mutations'
import { State } from './index'
import { RootState } from '~/store/index'
export enum ActionTypes {
addLang = 'addLang',
addLangMain = 'addLangMain',
addLangData = 'addLangData',
addLangForms = 'addLangForms',
removeLang = 'removeLang',
editLang = 'editLang'
}
type AppLangActionContext = {
commit<K extends keyof Mutations>(
key: K,
payload: Parameters<Mutations[K]>[1]
): ReturnType<Mutations[K]>
} & Omit<ActionContext<State, RootState>, 'commit'>
export interface Actions {
[ActionTypes.addLang](
{ commit }: AppLangActionContext,
payload: any
): void
[ActionTypes.addLangMain](
{ commit }: AppLangActionContext,
payload: any
): void
[ActionTypes.addLangData](
{ commit }: AppLangActionContext,
payload: any
): void
[ActionTypes.addLangForms](
{ commit }: AppLangActionContext,
payload: any
): void
[ActionTypes.removeLang](
{ commit }: AppLangActionContext,
payload: any
): void
[ActionTypes.editLang](
{ commit }: AppLangActionContext,
payload: any
): void
}
export const actions: ActionTree<State, RootState> & Actions = {
[ActionTypes.addLang]({ commit }, payload) {
commit(MutationTypes.addLang, payload)
},
[ActionTypes.addLangMain]({ commit }, payload) {
commit(MutationTypes.addLangMain, payload)
},
[ActionTypes.addLangData]({ commit }, payload) {
commit(MutationTypes.addLangData, payload)
},
[ActionTypes.addLangForms]({ commit }, payload) {
commit(MutationTypes.addLangForms, payload)
},
[ActionTypes.removeLang]({ commit }, payload) {
commit(MutationTypes.removeLang, payload)
},
[ActionTypes.editLang]({ commit }, payload) {
commit(MutationTypes.editLang, payload)
},
}

View File

@ -1,25 +0,0 @@
import { GetterTree } from 'vuex'
import { State } from './index'
import { RootState } from '~/store/index'
export type Getters<S = State> = {
lang(state: S, key: string): any
langMain(state: S, key: string): any
langData(state: S, key: string): any
langForms(state: S, key: string): any
}
export const getters: GetterTree<State, RootState> & Getters = {
lang: (state: State, key: string) => {
return state.lang.get(key)
},
langMain: (state: State, key: string) => {
return state.lang.get(key)?.main || null
},
langData: (state: State, key: string) => {
return state.lang.get(key)?.data || null
},
langForms: (state: State, key: string) => {
return state.lang.get(key)?.forms || null
},
}

View File

@ -1,51 +0,0 @@
import {
Store as VuexStore,
Module,
CommitOptions,
DispatchOptions,
} from 'vuex'
import { getters, Getters } from './getters'
import { mutations, Mutations, MutationTypes } from './mutations'
import { actions, Actions, ActionTypes } from './actions'
import { RootState } from '~/store/index'
import { AppLang } from '~/store/types'
interface State {
lang: Map<string, AppLang>
}
const state: State = {
lang: new Map(),
}
const data_module: Module<State, RootState> = {
state,
mutations,
actions,
getters,
}
export default data_module
type Store<S = State> = Omit<VuexStore<S>, 'commit' | 'getters' | 'dispatch' > & {
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
key: K,
payload: P,
options?: CommitOptions
): ReturnType<Mutations[K]>
} & {
getters: {
[K in keyof Getters]: ReturnType<Getters[K]>
}
} & {
dispatch<K extends keyof Actions>(
key: K,
payload: Parameters<Actions[K]>[1],
options?: DispatchOptions
): ReturnType<Actions[K]>
}
export { State, ActionTypes, MutationTypes, Store }

View File

@ -1,108 +0,0 @@
import { MutationTree } from 'vuex'
import { State } from './index'
import { AppLang, AppCtxLang, LangMain, LangData, LangForms } from '~/store/types'
export enum MutationTypes {
addLang = 'addLang',
addLangMain = 'addLangMain',
addLangData = 'addLangData',
addLangForms = 'addLangForms',
removeLang = 'removeLang',
editLang = 'editLang'
}
interface LangMap {
key: string
lang: AppLang
}
interface LangSection {
key: string
section: any
}
interface CtxLangMap {
key: string
lang: AppCtxLang
}
export type Mutations<S = State> = {
[MutationTypes.addLang](state: S, lang_map: LangMap): void
[MutationTypes.addLangMain](state: S, lang_map: LangSection): void
[MutationTypes.addLangData](state: S, lang_map: LangSection): void
[MutationTypes.addLangForms](state: S, lang_map: LangSection): void
[MutationTypes.removeLang](state: S, lang_map: CtxLangMap): void
[MutationTypes.editLang](state: S, lang_map: CtxLangMap): void
}
const get_lang_map = (state: State, mapkey: string): AppLang => {
const lng = state.lang.get(mapkey)
return lng || { main: {}, data: {}, forms: {} }
}
export const mutations: MutationTree<State> & Mutations = {
[MutationTypes.addLang](state: State, lang_map: LangMap) {
state.lang.set(lang_map.key, lang_map.lang)
},
[MutationTypes.addLangMain](state, lang_map: LangSection) {
const lng = get_lang_map(state, lang_map.key)
lng.main = lang_map.section
state.lang.set(lang_map.key, lng)
},
[MutationTypes.addLangData](state, lang_map: LangSection) {
const lng = get_lang_map(state, lang_map.key)
lng.data = lang_map.section
state.lang.set(lang_map.key, lng)
},
[MutationTypes.addLangForms](state, lang_map: LangSection) {
const lng = get_lang_map(state, lang_map.key)
lng.data = lang_map.section
state.lang.set(lang_map.key, lng)
},
[MutationTypes.removeLang](state: State, lang_map: CtxLangMap) {
const lang = get_lang_map(state, lang_map.key)
const key = lang_map.lang.lng.key
switch (lang_map.lang.ctx) {
case 'main':
if (lang.main[key]) {
delete lang.main[key]
state.lang.set(lang_map.key, lang)
}
break
case 'data':
if (lang.data[key]) {
delete lang.data[key]
state.lang.set(lang_map.key, lang)
}
break
case 'forms':
if (lang.forms[key]) {
delete lang.forms[key]
state.lang.set(lang_map.key, lang)
}
break
}
},
[MutationTypes.editLang](state: State, lang_map: CtxLangMap) {
const lang = get_lang_map(state, lang_map.key)
const key = lang_map.lang.lng.key
const val = lang_map.lang.lng.text
switch (lang_map.lang.ctx) {
case 'main':
if (lang.main[key]) {
lang.main[key] = val
state.lang.set(lang_map.key, lang)
}
break
case 'data':
if (lang.data[key]) {
lang.data[key] = val
state.lang.set(lang_map.key, lang)
}
break
case 'forms':
if (lang.forms[key]) {
lang.forms[key] = val
state.lang.set(lang_map.key, lang)
}
break
}
},
}

View File

@ -1,44 +0,0 @@
import { ActionContext, ActionTree } from 'vuex'
import { Mutations, MutationTypes } from './mutations'
import { State } from './index'
import { RootState } from '~/store/index'
export enum ActionTypes {
addProfile = 'addProfile',
removeProfile = 'removeProfile',
editProfile = 'editProfile'
}
type AppProfileActionContext = {
commit<K extends keyof Mutations>(
key: K,
payload: Parameters<Mutations[K]>[1]
): ReturnType<Mutations[K]>
} & Omit<ActionContext<State, RootState>, 'commit'>
export interface Actions {
[ActionTypes.addProfile](
{ commit }: AppProfileActionContext,
payload: any
): void
[ActionTypes.removeProfile](
{ commit }: AppProfileActionContext,
payload: any
): void
[ActionTypes.editProfile](
{ commit }: AppProfileActionContext,
payload: any
): void
}
export const actions: ActionTree<State, RootState> & Actions = {
[ActionTypes.addProfile]({ commit }, payload) {
commit(MutationTypes.addProfile, payload)
},
[ActionTypes.removeProfile]({ commit }, payload) {
commit(MutationTypes.removeProfile, payload)
},
[ActionTypes.editProfile]({ commit }, payload) {
commit(MutationTypes.editProfile, payload)
},
}

View File

@ -1,13 +0,0 @@
import { GetterTree } from 'vuex'
import { State } from './index'
import { RootState } from '~/store/index'
export type Getters<S = State> = {
profile(state: S): any
}
export const getters: GetterTree<State, RootState> & Getters = {
profile: (state: State) => {
return state.profile
},
}

View File

@ -1,49 +0,0 @@
import {
Store as VuexStore,
Module,
CommitOptions,
DispatchOptions,
} from 'vuex'
import { getters, Getters } from './getters'
import { mutations, Mutations, MutationTypes } from './mutations'
import { actions, Actions, ActionTypes } from './actions'
import { RootState } from '~/store/index'
interface State {
profile: any
}
const state: State = {
profile: {},
}
const data_module: Module<State, RootState> = {
state,
mutations,
actions,
getters,
}
export default data_module
type Store<S = State> = Omit<VuexStore<S>, 'commit' | 'getters' | 'dispatch' > & {
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
key: K,
payload: P,
options?: CommitOptions
): ReturnType<Mutations[K]>
} & {
getters: {
[K in keyof Getters]: ReturnType<Getters[K]>
}
} & {
dispatch<K extends keyof Actions>(
key: K,
payload: Parameters<Actions[K]>[1],
options?: DispatchOptions
): ReturnType<Actions[K]>
}
export { State, ActionTypes, MutationTypes, Store }

View File

@ -1,37 +0,0 @@
import { MutationTree } from 'vuex'
import { State } from './index'
export enum MutationTypes {
addProfile = 'addProfile',
removeProfile = 'removeProfile',
editProfile = 'editProfile'
}
export type Mutations<S = State> = {
[MutationTypes.addProfile](state: S, profile: any): void
[MutationTypes.removeProfile](state: S, target: any): void
[MutationTypes.editProfile](state: S, target: any, key: string): void
}
export const mutations: MutationTree<State> & Mutations = {
[MutationTypes.addProfile](state: State, profile: any) {
state.profile = profile
},
[MutationTypes.removeProfile](state: State, target: any) {
const profile = state.profile as any
const key = target.key
if (profile[key]) {
delete profile[key]
state.profile = profile
}
},
[MutationTypes.editProfile](state: State, target: any) {
const profile = state.profile as any
const key = target.key
const data = target.data
if (profile[key]) {
profile[key] = data
state.profile = profile
}
},
}

View File

@ -1 +0,0 @@
export * from './app'

View File

@ -1,97 +0,0 @@
import { useStore, Store } from 'vuex'
interface InternalModule<S, A, M, G> {
state: S
actions: A
mutations: M
getters: G
}
/**
* This function allows us to access the internal vuex properties and
* maps them in a way which removes the module prefix.
*/
function getFromStoreByType<T>(
moduleName: string,
type: unknown,
isNamespaced: boolean,
) {
if (isNamespaced) {
return Object.keys(type)
.filter(t => t.startsWith(`${moduleName}/`))
.reduce((acc, curr) => {
const typeName = curr.split('/').pop()
const typeValue = type[curr][0]
return { [typeName]: typeValue, ...acc }
}, {}) as T
}
return Object.keys(type).reduce((acc, curr) => {
const typeValue = type[curr][0]
return { [curr]: typeValue, ...acc }
}, {}) as T
}
/*
* We have to wrap the getters in a Proxy because we only want to
* "access" the getter if it actually being accessed.
*
* We could technically use the getFromStoreByType function but
* the getter would be invoked multiple types on store instantiation.
*
* This is just a little cheeky workaround. Proxy <3
*/
function wrapGettersInProxy<G>(
moduleName: string,
getters: G,
isNamespaced: boolean,
) {
return new Proxy(getters as Object, {
get(_, prop: string) {
if (isNamespaced)
return getters[`${moduleName}/${prop}`]
return getters[prop]
},
}) as G
}
function isModuleNamespaced<S>(moduleName: string, store: Store<S>): boolean {
// @ts-ignore internal Vuex object that isn't typed.
return Boolean(store._modulesNamespaceMap[`${moduleName}/`])
}
export default function useStoreModule<S = any, A = any, M = any, G = any>(
moduleName: string,
storeName?: string,
): InternalModule<S, A, M, G> {
// @ts-ignore useStore doesn't yet accept a key as arg
const store = storeName ? useStore(storeName) : useStore()
const state = store.state[moduleName]
const isNamespaced = isModuleNamespaced(moduleName, store)
const actions = getFromStoreByType<A>(
moduleName,
// @ts-ignore internal Vuex object that isn't typed.
store._actions,
isNamespaced,
)
const mutations = getFromStoreByType<M>(
moduleName,
// @ts-ignore internal Vuex object that isn't typed.
store._mutations,
isNamespaced,
)
const getters = wrapGettersInProxy<G>(moduleName, store.getters, isNamespaced)
return {
actions,
mutations,
state,
getters,
}
}

View File

@ -1,78 +0,0 @@
import {
AppDataMutationTypes,
AppDataActionTypes,
AppCheckMutationTypes,
AppCheckActionTypes,
AppDefsMutationTypes,
AppDefsActionTypes,
AppProfileMutationTypes,
AppProfileActionTypes,
AppLangMutationTypes,
AppLangActionTypes,
} from './modules/app/index'
export const AppDataMutation = AppDataMutationTypes
export const AppDataAction = AppDataActionTypes
export const AppCheckMutation = AppCheckMutationTypes
export const AppCheckAction = AppCheckActionTypes
export const AppDefsMutation = AppDefsMutationTypes
export const AppDefsAction = AppDefsActionTypes
export const AppProfileMutation = AppProfileMutationTypes
export const AppProfileAction = AppProfileActionTypes
export const AppLangMutation = AppLangMutationTypes
export const AppLangAction = AppLangActionTypes
export interface LangCtxKey {
ctx: string
key: string
}
export interface LangItem {
key: string
text: string
}
export interface LangMain {
[key: string]: string
}
export interface LangData {
[key: string]: string
}
export interface LangForms {
[key: string]: string
}
export interface AppLang {
main: LangMain
data: LangData
forms: LangForms
}
export interface AppCtxLang {
ctx: string
lng: LangItem
}
export interface AppDefs {
[key: string]: string
}
export interface AppProfile {
[key: string]: string
}
export interface AppData {
[key: string]: string
}
export interface AppCheck {
[key: string]: string
}
/*
export interface AppStore {
defs: AppDefs
profile: AppProfile
data: [AppData]
lang: AppLang
}
*/

View File

@ -1,43 +0,0 @@
html,
body,
#app {
height: 100%;
margin: 0;
padding: 0;
}
html.dark {
background: #121212;
}
.markdown-body {
margin: 2em;
}
.markdown-body p {
margin-top: 1em;;
font-size: 1em;
}
.markdown-body pre {
padding: 2em;
background: rgba(243,244,246);
}
.dark .markdown-body pre {
background: rgba(75, 85, 99,var(--tw-bg-opacity))
}
.markdown-body a {
color: rgba(37, 99, 235);
}
.btn {
@apply px-4 py-1 rounded inline-block
bg-teal-600 text-white cursor-pointer
hover:bg-teal-700
disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50;
}
.icon-btn {
@apply inline-block cursor-pointer select-none
opacity-75 transition duration-200 ease-in-out
hover:opacity-100 hover:text-teal-600;
font-size: 0.9em;
}

View File

@ -1,86 +0,0 @@
export const enum LanguageType {
en = 'en',
es = 'es',
None = 'None',
}
export interface StatusItemType {
title: string
content: string
lang: LanguageType
datetime: string
isOpen: boolean
}
export interface StatusItemDataType {
[key: string]: any
title: string
content: string
lang: LanguageType
datetime: string
}
export const enum ReqType {
tcp = 'tcp',
https = 'https',
NotSet = 'NotSet',
}
export const enum CriticalType {
yes = 'yes',
cloud = 'cloud',
group = 'group',
ifresized = 'ifresized',
no = 'no',
}
export interface SrvcType {
name: string
path: string
req: ReqType
target: string
liveness: string
critical: CriticalType
}
export interface SrvcInfoType {
[key: string]: any
name: string
info: string
srvc: SrvcType
}
export interface CloudGroupItemType {
[key: string]: any
hostname: string
tsksrvcs: SrvcType[]
appsrvcs: SrvcType[]
}
export interface CloudGroupServcType {
[key: string]: any
hostname: string
name: string
tsksrvcs: SrvcInfoElemType[]
appsrvcs: SrvcInfoElemType[]
}
export interface CloudDataCheck {
[key: string]: any
name: string
apps: Map<string, Map<string, CloudGroupServcType>>
cloud: Map<string, Map<string, CloudGroupServcType>>
infos: StatusItemType[]
}
export interface CloudOptionType {
name: string
option: number
}
export interface CloudGroupDataType {
[key: string]: CloudGroupItemType[] | any
}
export interface ResCloudDataCheck {
[key: string]: any
name: string
cloud: CloudGroupDataType
apps: CloudGroupDataType
// cloud: CloudGroupSrvcType
// statusentries: StatusItemDataType[]
}
export interface ResCloudDataCheckDefs {
[key: string]: any
check: ResCloudDataCheck[]
defs: any
}

View File

@ -1,23 +0,0 @@
export enum MessageType {
Show,
Success,
Error,
Warning,
Info,
}
export interface MenuItemType {
id: string
title: string
active: boolean
link: string
}
export enum NavItemType {
router_link = 'router_link',
app_link = 'app_link',
a_blank = 'a_blank',
a_link = 'a_link',
cloud_link = 'cloud_link',
module_label = 'module_label',
separator = 'separator',
}

View File

@ -1,26 +0,0 @@
<script setup lang="ts">
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
const router = useRouter()
const { t } = useI18n()
</script>
<template>
<main class="px-4 py-10 text-center text-teal-700 dark:text-gray-200">
<div>
<p class="text-4xl">
<carbon-warning class="inline-block" />
</p>
</div>
<router-view />
<div>
<button
class="btn m-3 text-sm mt-8"
@click="router.back()"
>
{{ t('button.back') }}
</button>
</div>
</main>
</template>

View File

@ -1,21 +0,0 @@
---
title: About
---
<div class="text-center">
<!-- You can use Vue components inside markdown -->
<carbon-dicom-overlay class="text-4xl mb-6 m-auto" />
<h3>About</h3>
</div>
[Vitesse](https://github.com/antfu/vitesse) is an opinionated [Vite](https://github.com/vitejs/vite) starter template made by [@antfu](https://github.com/antfu) for mocking apps swiftly. With **file-based routing**, **components auto importing**, **markdown support**, I18n, PWA and uses **Tailwind** v2 for UI.
```js
// syntax highlighting example
function vitesse() {
const foo = 'bar'
console.log(foo)
}
```
heck out the [GitHub repo](https://github.com/antfu/vitesse) for more details.

View File

@ -1,329 +0,0 @@
<template>
<NavMenu v-if="use_nav" :usetitle="false" :title="title" navtitle="" :items="navMenuItems" @on-nav-menu="onNavMenu">
<template #opslist v-if="clds_groups.length > 0 ">
<li class="mr-3">
<select id="cld-select" class="rounded-xl bg-light-300 form-select p-2 mt-1 block w-full ddark:hover:bg-gray-800 ddark:bg-gray-500 ddark:text-gray-200 bg-gray-200 text-gray-800" @change="update_cloud_selection">
<option
v-for="(cld, index) in clouds_options"
:key="index"
class="bg-gray-200 text-gray-800 appearance-none border-none inline-block py-3 pl-3 pr-8 rounded leading-tight ddark:hover:bg-gray-800 ddark:bg-gray-500 ddark:text-gray-200"
:selected="cld_sel_idx === index"
>
{{ cld.name }}
</option>
</select>
</li>
</template>
<template #search v-if="(cld_selected.cloud && cld_selected.cloud.size > 0 ) || cld_selected.apps && cld_selected.apps.size > 0">
<input id="search" v-model="search" class="rounded-l-full w-full py-2 px-2 text-gray-700 leading-tight focus:outline-none" type="text" :placeholder="t('nav.Search','Search')">
<div class="p-1">
<button
class="bg-blue-500 text-white rounded-full p-2 hover:bg-blue-400 focus:outline-none flex items-center justify-center"
@click="on_search"
>
<span class="text-xs">
<carbon-search class="align-bottom" />
</span>
</button>
</div>
</template>
<template #lastitems>
<li class="mr-3">
<MenuLocales :label-mode="localesLabelMode" :include-current="includeCurrLocale" />
</li>
</template>
</NavMenu>
<Profile v-if="show_profile" />
<div id="tophome">
<div v-if="cld_selected.cloud && cld_selected.cloud.size > 0" class="-mt-2 text-gray-800 lg:p-1">
<CloudGroups
:title="t('nav.Tasks','Services')"
target="tsksrvcs"
:groups="cld_selected.cloud"
:search="search"
:hide="tasks_hide"
@on-cloud-group="onCloudGroup"
/>
</div>
<div v-if="cld_selected.apps && cld_selected.apps.size > 0" class="mt-1 text-gray-800 p-2 lg:p-4">
<CloudGroups
:title="t('nav.Apps','Apps')"
target="appsrvcs"
:groups="cld_selected.apps"
:search="search"
:hide="apps_hide"
@on-cloud-group="onCloudGroup"
/>
</div>
<div v-if="cld_selected.infos && cld_selected.infos.length > 0" class="shadow-lg mx-auto bg-gray-100 text-gray-800 mt-4 md:mt-2 bg-light-800 dark:bg-gray-600 w-full p-2 rounded-l">
<Infos :items="cld_selected.infos" :title="t('nav.Informations','Informations')"
@on-cloud-info-item="onCloudInfoItem"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useStore } from 'vuex'
import CloudGroups from '~/components/CloudGroups.vue'
// import ProfileView from '~/components/ProfileView.vue'
import NavMenu from '~/components/NavMenu.vue'
import Infos from '~/views/Infos.vue'
import Profile from '~/components/Profile.vue'
import { load_data } from '~/hooks/utils'
// import { translate, show_message } from '~/hooks/utils'
import useState from '~/hooks/useState'
import { StatusItemType, StatusItemDataType, ResCloudDataCheckDefs, CloudGroupServcType, CloudDataCheck,CloudOptionType } from '~/typs/clouds'
import { SideMenuItemType } from '~/typs/cmpnts'
import MenuLocales from '@/menus/MenuLocales.vue'
import { AppDefsAction } from '~/store/types'
// import { AppDataAction, AppCheckAction, AppDefsAction } from '~/store/types'
enum LocalesLabelModes {
value = 'val',
translation = 'trans',
}
const router = useRouter()
const map_key = router.currentRoute.value.meta.mapkey as string || 'ui'
const use_nav = router.currentRoute.value.meta.useNav as boolean
const ctx = router.currentRoute.value.meta.ctx || ''
const localesLabelMode = ref(LocalesLabelModes.translation)
const includeCurrLocale = true
const store = useStore()
const { t } = useI18n()
const title = ref('Services Status')
const search = useState().search
// const router = useRouter()
// const go = () => {
// if (name.value)
// router.push(`/hi/${encodeURIComponent(name.value)}`)
// }
const show_profile = computed(() => useState().show_profile.value)
const defs = computed(() => store.state.app_defs.main.get(map_key) || {})
const menu_items = computed((): SideMenuItemType[] => {
const defsMenuItems = defs.value && defs.value.sidebar && defs.value.sidebar.menu_items ? defs.value.sidebar.menu_items : [] as SideMenuItemType[]
const all_items = [].concat(defsMenuItems || []) // .concat(useState().sidebarMenuItems.value as SideMenuItemType[] | any)
useState().sidebarMenuItems.value = all_items.filter((itm: SideMenuItemType) => {
if (itm.ctx && itm.ctx === ctx) {
return true
} else if (itm.ctx && itm.ctx !== ctx) {
return false
} else {
return true
}
})
return useState().sidebarMenuItems.value
})
const navMenuItems = computed(() => {
const menu_items_active = menu_items.value.filter(menuitem => {
switch (menuitem.click) {
case 'tsksrvcs':
return cld_selected.value.cloud && cld_selected.value.cloud.size > 0
break
case 'appsrvcs':
return cld_selected.value.apps && cld_selected.value.apps.size > 0
break
case 'srvcstatus':
return cld_selected.value.infos && cld_selected.value.infos.length > 0
break
default:
return false
}
})
return menu_items_active
})
const on_search = () => {
}
const tasks_hide = ref(false)
const apps_hide = ref(false)
const onCloudGroup = (target: string) => {
if (target) {
switch (target) {
case useState().tsksrvcs:
tasks_hide.value = !tasks_hide.value
break
case useState().appsrvcs:
apps_hide.value = !apps_hide.value
break
default:
}
}
}
const onAppHome = () => {
const dom_id = document.getElementById('tophome')
if (dom_id) {
dom_id.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' })
setTimeout(() => window.scrollBy(0, -40), 1000)
}
}
useState().app_home_click.value = onAppHome
useState().backdrop_blur.value = 2
useState().back_opacity.value = 100
useState().panels.value.search = { style: 'h-auto'}
const onNavMenu = (item: SideMenuItemType) => {
if (item) {
const dom_id = document.getElementById(item.click as string)
if (dom_id) {
dom_id.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' })
setTimeout(() => window.scrollBy(0, -40), 1000)
}
// const new_defs = JSON.parse(JSON.stringify(store.state.app_defs.main.get(map_key)))
// new_defs.sidebar.menu_items = menu_items.value.map(i => ({ ...i, active: i.click !== item.click? false : !i.active }))
// store.dispatch(AppDefsAction.addDefs, new_defs)
switch (item.click) {
case useState().tsksrvcs:
tasks_hide.value = false
break
case useState().appsrvcs:
apps_hide.value = false
break
default:
}
}
}
useState().side_menu_click.value = onNavMenu
const cld_default_name = 'ma'
const clds_groups = ref([] as CloudDataCheck[])
const cld_sel_idx= ref(0)
const cld_selected = ref({} as CloudDataCheck)
const clouds_options = computed(() => {
const options = [] as CloudOptionType[]
clds_groups.value.forEach((it,idx) => {
options.push({
name: it.name,
option: idx,
})
})
return options
})
const update_cloud_selection = (e: any) => {
if (clds_groups.value[e.target.selectedIndex]) {
cld_sel_idx.value=e.target.selectedIndex
cld_selected.value = clds_groups.value[cld_sel_idx.value]
}
}
const onCloudInfoItem = (item: StatusItemType) => {
if (item) {
clds_groups.value[cld_sel_idx.value].infos = clds_groups.value[cld_sel_idx.value].infos.map((i: StatusItemType) => ({
...i, isOpen: i.title === item.title && i.datetime === item.datetime ? !i.isOpen : false
}))
cld_selected.value = clds_groups.value[cld_sel_idx.value]
}
}
const sortInfos = (data: StatusItemType[], rev: boolean): StatusItemType[] => {
const mapped = data.map(function(el, i) {
return { index: i, value: parseInt(el.datetime.replaceAll(' ','').replaceAll('/','').replaceAll(':',''),0) || 0 };
})
mapped.sort(function(a, b) {
if (a.value > b.value) {
return rev ? -1 : 1;
}
if (a.value < b.value) {
return rev ? 1 : -1;
}
return 0;
});
const result = mapped.map(function(el){
return data[el.index];
});
return result
}
onBeforeUnmount(() => {
useState().sidebarMenuItems.value = useState().sidebarMenuItems.value.filter((itm: SideMenuItemType) => {
if (itm.ctx && itm.ctx === ctx) {
return false
} else if (itm.ctx && itm.ctx !== ctx) {
return false
} else {
return true
}
})
useState().side_menu_click.value = () => router.push('/')
useState().app_home_click.value = () => router.push('/')
})
onMounted(async() => {
// await nextTick()
const use_local = false
let url = 'groups.json'
const rooturl = window.ROOT_LOCATION || location.origin
if (!use_local)
url = `${rooturl}/info`
clds_groups.value = [] as CloudDataCheck[]
await load_data(url, 0, 2000, (res: ResCloudDataCheckDefs) => {
// use Map to keep objects order
// use Object.keys + sort to map same result order
const clouds_groups = [] as CloudDataCheck[]
res.check.forEach((kld,kldidx) => {
if (kld.name === cld_default_name)
cld_sel_idx.value=kldidx
const check_data: Map<string, Map<string, CloudGroupServcType>> = new Map()
clouds_groups[kldidx] = {} as CloudDataCheck
Object.keys(kld.apps).sort().forEach((grp_key) => {
const data: Map<string, CloudGroupServcType> = new Map()
Object.keys(kld.apps[grp_key]).sort().forEach((key) => {
const grp_res: CloudGroupServcType[] = kld.apps[grp_key][key].filter((it:CloudGroupServcType) => it.tsksrvcs.length > 0 || it.appsrvcs.length > 0)
if (grp_res.length > 0)
data.set(key, kld.apps[grp_key][key])
})
if (data.size > 0)
check_data.set(grp_key, data)
})
clouds_groups[kldidx] = {
name: kld.name,
apps: check_data,
cloud: kld.cloud ? new Map() : check_data,
infos: [] as StatusItemType[],
}
if (kld.cloud) {
Object.keys(kld.cloud).sort().forEach((grp_key) => {
Object.keys(kld.cloud[grp_key]).sort().forEach((key) => {
const data: CloudGroupServcType[] = kld.cloud[grp_key][key]
data.forEach((it, index) => {
if (clouds_groups[kldidx].apps.get(grp_key)) {
const m = clouds_groups[kldidx].apps.get(grp_key)
if (m && m.size > 0 && m.get(key) && it.tsksrvcs) {
const m_data = m.get(key)
if (m_data && m_data[index]) {
m_data[index].tsksrvcs = it.tsksrvcs
const new_data: Map<string, CloudGroupServcType> = new Map()
new_data.set(key, m_data)
clouds_groups[kldidx].cloud.set(grp_key, new_data)
}
}
}
})
})
})
}
let infos: StatusItemType[] = []
if (kld.infos) {
kld.infos.forEach((it: StatusItemDataType) => {
infos.push({ ...it, isOpen: false })
})
infos = sortInfos(infos,true)
}
clouds_groups[kldidx].infos = infos
})
clds_groups.value = clouds_groups
cld_selected.value = clds_groups.value[cld_sel_idx.value]
if (res.defs) {
store.dispatch(AppDefsAction.addDefs, { key: map_key, defs: res.defs })
}
useState().sidebarMenuItems.value = res.defs.sidebar.menu_items.filter((itm: SideMenuItemType) => {
if (itm.ctx && itm.ctx === ctx) {
return true
} else if (itm.ctx && itm.ctx !== ctx) {
return false
} else {
return true
}
})
})
})
</script>

Some files were not shown because too many files have changed in this diff Show More