@xen-orchestra/web-core 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/env.d.ts +2 -0
  2. package/lib/assets/no-result.svg +81 -0
  3. package/lib/assets/under-construction.svg +195 -0
  4. package/lib/components/CardNumbers.vue +94 -0
  5. package/lib/components/DonutChart.vue +92 -0
  6. package/lib/components/LegendTitle.vue +31 -0
  7. package/lib/components/StatusPill.vue +2 -2
  8. package/lib/components/UiCard.vue +29 -0
  9. package/lib/components/UiLegend.vue +68 -0
  10. package/lib/components/UiSeparator.vue +11 -0
  11. package/lib/components/card/CardSubtitle.vue +24 -0
  12. package/lib/components/card/CardTitle.vue +52 -0
  13. package/lib/components/chip/UiChip.vue +2 -2
  14. package/lib/components/console/RemoteConsole.vue +119 -0
  15. package/lib/components/dropdown/DropdownTitle.vue +7 -3
  16. package/lib/components/icon/VmIcon.vue +1 -1
  17. package/lib/components/menu/MenuItem.vue +1 -1
  18. package/lib/components/menu/MenuList.vue +5 -5
  19. package/lib/components/stacked-bar/StackedBar.vue +49 -0
  20. package/lib/components/stacked-bar/StackedBarSegment.vue +73 -0
  21. package/lib/components/state-hero/ComingSoonHero.vue +9 -0
  22. package/lib/components/state-hero/LoadingHero.vue +9 -0
  23. package/lib/components/state-hero/ObjectNotFoundHero.vue +13 -0
  24. package/lib/components/state-hero/StateHero.vue +53 -0
  25. package/lib/components/table/ColumnTitle.vue +150 -0
  26. package/lib/components/table/UiTable.vue +58 -0
  27. package/lib/components/tooltip/TooltipList.vue +0 -2
  28. package/lib/components/tree/TreeItemLabel.vue +4 -0
  29. package/lib/composables/tree/types.ts +1 -1
  30. package/lib/i18n.ts +33 -1
  31. package/lib/layouts/CoreLayout.vue +6 -97
  32. package/lib/locales/de.json +31 -4
  33. package/lib/locales/en.json +45 -13
  34. package/lib/locales/fr.json +45 -13
  35. package/lib/types/iterable-backoff.d.ts +1 -0
  36. package/lib/types/utility.type.ts +2 -0
  37. package/lib/utils/if-else.utils.ts +3 -3
  38. package/package.json +19 -6
@@ -0,0 +1,58 @@
1
+ <template>
2
+ <table :class="{ 'vertical-border': verticalBorder }" class="ui-table typo p2-regular">
3
+ <slot />
4
+ </table>
5
+ </template>
6
+
7
+ <script lang="ts" setup>
8
+ import { provide } from 'vue'
9
+
10
+ const props = defineProps<{
11
+ name?: string
12
+ verticalBorder?: boolean
13
+ }>()
14
+
15
+ provide('tableName', props.name)
16
+ </script>
17
+
18
+ <style lang="postcss" scoped>
19
+ .ui-table {
20
+ width: 100%;
21
+ border-spacing: 0;
22
+ background-color: var(--background-color-primary);
23
+ line-height: 2.4rem;
24
+ color: var(--color-grey-200);
25
+
26
+ :deep(th),
27
+ :deep(td) {
28
+ padding: 1rem;
29
+ border-top: 0.1rem solid var(--color-grey-500);
30
+ text-align: left;
31
+ }
32
+
33
+ :deep(th) {
34
+ font-weight: 700;
35
+ }
36
+
37
+ :deep(thead) {
38
+ th,
39
+ td {
40
+ color: var(--color-purple-base);
41
+ font-size: 1.4rem;
42
+ font-weight: 400;
43
+ text-transform: uppercase;
44
+ }
45
+ }
46
+
47
+ &.vertical-border {
48
+ :deep(th),
49
+ :deep(td) {
50
+ border-right: 0.1rem solid var(--color-grey-500);
51
+
52
+ &:last-child {
53
+ border-right: none;
54
+ }
55
+ }
56
+ }
57
+ }
58
+ </style>
@@ -11,5 +11,3 @@ import { storeToRefs } from 'pinia'
11
11
  const tooltipStore = useTooltipStore()
12
12
  const { tooltips } = storeToRefs(tooltipStore)
13
13
  </script>
14
-
15
- <style scoped></style>
@@ -51,6 +51,10 @@ import { faAngleDown, faAngleRight } from '@fortawesome/free-solid-svg-icons'
51
51
  import { inject, ref } from 'vue'
52
52
  import type { RouteLocationRaw } from 'vue-router'
53
53
 
54
+ defineOptions({
55
+ inheritAttrs: false,
56
+ })
57
+
54
58
  defineProps<{
55
59
  icon?: IconDefinition
56
60
  route: RouteLocationRaw
@@ -1,9 +1,9 @@
1
- import { useTree } from '@core/composables/tree.composable'
2
1
  import type { Branch } from '@core/composables/tree/branch'
3
2
  import type { BranchDefinition } from '@core/composables/tree/branch-definition'
4
3
  import type { Leaf } from '@core/composables/tree/leaf'
5
4
  import type { LeafDefinition } from '@core/composables/tree/leaf-definition'
6
5
  import type { TreeNodeBase } from '@core/composables/tree/tree-node-base'
6
+ import { useTree } from '@core/composables/tree.composable'
7
7
 
8
8
  export type TreeNodeId = string | number
9
9
 
package/lib/i18n.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { createI18n } from 'vue-i18n'
2
1
  import messages from '@intlify/unplugin-vue-i18n/messages'
2
+ import { createI18n } from 'vue-i18n'
3
3
 
4
4
  interface Locales {
5
5
  [key: string]: {
@@ -27,6 +27,15 @@ export default createI18n({
27
27
  locale: localStorage.getItem('lang') ?? 'en',
28
28
  fallbackLocale: 'en',
29
29
  messages,
30
+ missing: (locale, key, vm) => {
31
+ if (!import.meta.env.DEV) {
32
+ return key
33
+ }
34
+
35
+ console.warn(`i18n key not found: ${key}`, `Used in ${vm?.type.__name ?? 'unknown component'}`)
36
+
37
+ return `🌎❗⟨${key}⟩`
38
+ },
30
39
  datetimeFormats: {
31
40
  en: {
32
41
  date_short: {
@@ -155,4 +164,27 @@ export default createI18n({
155
164
  },
156
165
  },
157
166
  },
167
+ numberFormats: {
168
+ en: {
169
+ percent: {
170
+ style: 'percent',
171
+ minimumFractionDigits: 0,
172
+ maximumFractionDigits: 2,
173
+ },
174
+ },
175
+ fr: {
176
+ percent: {
177
+ style: 'percent',
178
+ minimumFractionDigits: 0,
179
+ maximumFractionDigits: 2,
180
+ },
181
+ },
182
+ de: {
183
+ percent: {
184
+ style: 'percent',
185
+ minimumFractionDigits: 0,
186
+ maximumFractionDigits: 2,
187
+ },
188
+ },
189
+ },
158
190
  })
@@ -16,7 +16,7 @@
16
16
  <div class="container">
17
17
  <div
18
18
  v-if="sidebarStore.isExpanded && !sidebarStore.isLocked"
19
- class="sidebar-overlay"
19
+ class="sidebar-close-backdrop"
20
20
  @click="sidebarStore.toggleExpand(false)"
21
21
  />
22
22
  <LayoutSidebar class="sidebar">
@@ -30,30 +30,9 @@
30
30
  <slot name="sidebar-footer" />
31
31
  </template>
32
32
  </LayoutSidebar>
33
- <div class="main-container">
34
- <header>
35
- <slot name="content-header" />
36
- </header>
37
- <main class="main">
38
- <div class="content">
39
- <slot name="content" />
40
- </div>
41
- <div v-if="isPanelVisible" :class="{ mobile: uiStore.isMobile }" class="panel">
42
- <header v-if="$slots['panel-header'] || uiStore.isMobile" class="panel-header">
43
- <UiButtonIcon
44
- v-if="uiStore.isMobile"
45
- :icon="faAngleLeft"
46
- class="panel-close-icon"
47
- @click="panelStore.close()"
48
- />
49
- <slot name="panel-header" />
50
- </header>
51
- <div v-if="$slots['panel-content']" class="panel-content">
52
- <slot name="panel-content" />
53
- </div>
54
- </div>
55
- </main>
56
- </div>
33
+ <main class="main-container">
34
+ <slot name="content" />
35
+ </main>
57
36
  </div>
58
37
  </div>
59
38
  </template>
@@ -62,39 +41,14 @@
62
41
  import UiButtonIcon from '@core/components/button/ButtonIcon.vue'
63
42
  import LayoutSidebar from '@core/components/layout/LayoutSidebar.vue'
64
43
  import { vTooltip } from '@core/directives/tooltip.directive'
65
- import { usePanelStore } from '@core/stores/panel.store'
66
44
  import { useSidebarStore } from '@core/stores/sidebar.store'
67
- import { useUiStore } from '@core/stores/ui.store'
68
- import { faAngleDoubleLeft, faAngleLeft, faBars } from '@fortawesome/free-solid-svg-icons'
69
- import { computed } from 'vue'
45
+ import { faAngleDoubleLeft, faBars } from '@fortawesome/free-solid-svg-icons'
70
46
 
71
47
  const sidebarStore = useSidebarStore()
72
- const panelStore = usePanelStore()
73
- const uiStore = useUiStore()
74
-
75
- const slots = defineSlots<{
76
- 'app-logo'(): any
77
- 'app-header'(): any
78
- 'sidebar-header'(): any
79
- 'sidebar-content'(): any
80
- 'sidebar-footer'(): any
81
- 'content-header'(): any
82
- content(): any
83
- 'panel-header'(): any
84
- 'panel-content'(): any
85
- }>()
86
-
87
- const isPanelVisible = computed(() => {
88
- if (!slots['panel-header'] && !slots['panel-content']) {
89
- return false
90
- }
91
-
92
- return panelStore.isExpanded
93
- })
94
48
  </script>
95
49
 
96
50
  <style lang="postcss" scoped>
97
- .sidebar-overlay {
51
+ .sidebar-close-backdrop {
98
52
  position: fixed;
99
53
  inset: 0;
100
54
  z-index: 1000;
@@ -132,51 +86,6 @@ const isPanelVisible = computed(() => {
132
86
  overflow: auto;
133
87
  display: flex;
134
88
  flex-direction: column;
135
- }
136
-
137
- .main {
138
- background-color: var(--background-color-secondary);
139
- display: flex;
140
- flex: 1;
141
- }
142
-
143
- .content {
144
- padding: 0.8rem;
145
- flex: 1;
146
- border-right: 0.1rem solid var(--color-grey-500);
147
- }
148
-
149
- .panel {
150
- display: flex;
151
- flex-direction: column;
152
- width: 40rem;
153
89
  background-color: var(--background-color-secondary);
154
-
155
- &.mobile {
156
- width: 100%;
157
- position: fixed;
158
- inset: 0 0 0 auto;
159
- z-index: 1000;
160
- }
161
- }
162
-
163
- .panel-header {
164
- display: flex;
165
- align-items: center;
166
- padding: 0.4rem 1.6rem;
167
- background-color: var(--background-color-primary);
168
- border-bottom: 0.1rem solid var(--color-grey-500);
169
- min-height: 4.8rem;
170
- }
171
-
172
- .panel-close-icon {
173
- margin-right: auto;
174
- }
175
-
176
- .panel-content {
177
- flex: 1;
178
- padding: 0.8rem;
179
- overflow: auto;
180
- min-height: 0;
181
90
  }
182
91
  </style>
@@ -1,6 +1,33 @@
1
1
  {
2
- "core": {
3
- "close": "Schließen",
4
- "log-out": "Abmelden"
5
- }
2
+ "alarms": "Alarme",
3
+
4
+ "bytes.ki": "KiB",
5
+ "bytes.mi": "MiB",
6
+ "bytes.gi": "GiB",
7
+
8
+ "coming-soon": "Bald verfügbar!",
9
+ "console": "Konsole",
10
+
11
+ "core.close": "Schließen",
12
+
13
+ "core.select.all": "Alles auswählen",
14
+ "core.select.none": "Alle abwählen",
15
+
16
+ "dark-mode.enable": "Aktivieren Sie den Dunkelmodus",
17
+ "dark-mode.disable": "Deaktivieren Sie den Dunkelmodus",
18
+ "dark-mode.auto": "Automatischer Dunkelmodus",
19
+
20
+ "dashboard": "Dashboard",
21
+ "documentation-name": "{name} Dokumentation",
22
+ "loading-in-progress": "Ladevorgang läuft…",
23
+ "log-out": "Abmelden",
24
+ "master": "Primärer Host",
25
+ "network": "Netzwerk",
26
+ "object-not-found": "Objekt {id} wurde nicht gefunden…",
27
+ "power-on-for-console": "Konsole ist nach Start der VM verfügbar",
28
+ "stats": "Statistiken",
29
+ "storage": "Speicher",
30
+ "support-name": "{name} pro support",
31
+ "system": "System",
32
+ "tasks": "Aufgaben"
6
33
  }
@@ -1,15 +1,47 @@
1
1
  {
2
- "core": {
3
- "close": "Close",
4
- "log-out": "Log out",
5
- "master": "Primary host",
6
- "open": "Open",
7
- "quick-actions": "Quick actions",
8
- "sidebar": {
9
- "close": "Close sidebar",
10
- "lock": "Lock sidebar open",
11
- "open": "Open sidebar",
12
- "unlock": "Unlock sidebar"
13
- }
14
- }
2
+ "alarms": "Alarms",
3
+
4
+ "bytes.ki": "KiB",
5
+ "bytes.mi": "MiB",
6
+ "bytes.gi": "GiB",
7
+
8
+ "coming-soon": "Coming soon!",
9
+ "console": "Console",
10
+
11
+ "core.close": "Close",
12
+ "core.current": "Current",
13
+ "core.filter": "Filter",
14
+ "core.group": "Group",
15
+ "core.hide": "Hide",
16
+ "core.open": "Open",
17
+ "core.quick-actions": "Quick actions",
18
+
19
+ "core.select.all": "Select all",
20
+ "core.select.none": "Select none",
21
+
22
+ "core.sidebar.close": "Close sidebar",
23
+ "core.sidebar.lock": "Lock sidebar open",
24
+ "core.sidebar.open": "Open sidebar",
25
+ "core.sidebar.unlock": "Unlock sidebar",
26
+
27
+ "core.sort.ascending": "Sort ascending",
28
+ "core.sort.descending": "Sort descending",
29
+
30
+ "dark-mode.enable": "Enable dark mode",
31
+ "dark-mode.disable": "Disable dark mode",
32
+ "dark-mode.auto": "Auto dark mode",
33
+
34
+ "dashboard": "Dashboard",
35
+ "documentation-name": "{name} documentation",
36
+ "loading-in-progress": "Loading in progress…",
37
+ "log-out": "Log out",
38
+ "master": "Primary host",
39
+ "network": "Network",
40
+ "object-not-found": "Object {id} can't be found…",
41
+ "power-on-for-console": "Power on your VM to access its console",
42
+ "stats": "Stats",
43
+ "storage": "Storage",
44
+ "support-name": "{name} pro support",
45
+ "system": "System",
46
+ "tasks": "Tasks"
15
47
  }
@@ -1,15 +1,47 @@
1
1
  {
2
- "core": {
3
- "close": "Fermer",
4
- "log-out": "Se déconnecter",
5
- "master": "Hôte primaire",
6
- "open": "Ouvrir",
7
- "quick-actions": "Actions rapides",
8
- "sidebar": {
9
- "close": "Fermer la barre latérale",
10
- "lock": "Verrouiller la barre latérale",
11
- "open": "Ouvrir la barre latérale",
12
- "unlock": "Déverrouiller la barre latérale"
13
- }
14
- }
2
+ "alarms": "Alarmes",
3
+
4
+ "bytes.ki": "Kio",
5
+ "bytes.mi": "Mio",
6
+ "bytes.gi": "Gio",
7
+
8
+ "coming-soon": "Bientôt disponible !",
9
+ "console": "Console",
10
+
11
+ "core.close": "Fermer",
12
+ "core.current": "Actuel",
13
+ "core.filter": "Filtrer",
14
+ "core.group": "Grouper",
15
+ "core.hide": "Masquer",
16
+ "core.open": "Ouvrir",
17
+ "core.quick-actions": "Actions rapides",
18
+
19
+ "core.select.all": "Tout sélectionner",
20
+ "core.select.none": "Tout désélectionner",
21
+
22
+ "core.sidebar.close": "Fermer la barre latérale",
23
+ "core.sidebar.lock": "Verrouiller la barre latérale",
24
+ "core.sidebar.open": "Ouvrir la barre latérale",
25
+ "core.sidebar.unlock": "Déverrouiller la barre latérale",
26
+
27
+ "core.sort.ascending": "Trier par ordre croissant",
28
+ "core.sort.descending": "Trier par ordre décroissant",
29
+
30
+ "dark-mode.enable": "Activer le mode sombre",
31
+ "dark-mode.disable": "Désactiver le mode sombre",
32
+ "dark-mode.auto": "Mode sombre automatique",
33
+
34
+ "dashboard": "Tableau de bord",
35
+ "documentation-name": "Documentation {name}",
36
+ "loading-in-progress": "Chargement en cours…",
37
+ "log-out": "Se déconnecter",
38
+ "master": "Hôte primaire",
39
+ "network": "Réseau",
40
+ "object-not-found": "L'objet {id} est introuvable…",
41
+ "power-on-for-console": "Allumez votre VM pour accéder à sa console",
42
+ "stats": "Stats",
43
+ "storage": "Stockage",
44
+ "support-name": "Support pro {name}",
45
+ "system": "Système",
46
+ "tasks": "Tâches"
15
47
  }
@@ -0,0 +1 @@
1
+ declare module 'iterable-backoff'
@@ -1 +1,3 @@
1
1
  export type MaybeArray<T> = T | T[]
2
+
3
+ export type Noop = () => void
@@ -1,4 +1,4 @@
1
- import type { MaybeArray } from '@core/types/utility.type'
1
+ import type { MaybeArray, Noop } from '@core/types/utility.type'
2
2
  import { toArray } from '@core/utils/to-array.utils'
3
3
  import { watch, type WatchOptions, type WatchSource } from 'vue'
4
4
 
@@ -6,8 +6,8 @@ export interface IfElseOptions extends Pick<WatchOptions, 'immediate'> {}
6
6
 
7
7
  export function ifElse(
8
8
  source: WatchSource<boolean>,
9
- onTrue: MaybeArray<VoidFunction>,
10
- onFalse: MaybeArray<VoidFunction>,
9
+ onTrue: MaybeArray<Noop>,
10
+ onFalse: MaybeArray<Noop>,
11
11
  options?: IfElseOptions
12
12
  ) {
13
13
  const onTrueFunctions = toArray(onTrue)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xen-orchestra/web-core",
3
3
  "type": "module",
4
- "version": "0.0.1",
4
+ "version": "0.0.3",
5
5
  "private": false,
6
6
  "exports": {
7
7
  "./*": {
@@ -9,17 +9,30 @@
9
9
  "import": "./lib/*"
10
10
  }
11
11
  },
12
- "devDependencies": {
13
- "@fortawesome/fontawesome-svg-core": "^6.5.1",
12
+ "dependencies": {
13
+ "@fontsource/poppins": "^5.0.14",
14
+ "@fortawesome/fontawesome-common-types": "^6.5.1",
14
15
  "@fortawesome/free-regular-svg-icons": "^6.5.1",
15
16
  "@fortawesome/free-solid-svg-icons": "^6.5.1",
16
17
  "@fortawesome/vue-fontawesome": "^3.0.5",
17
- "@types/lodash-es": "^4.17.12",
18
- "@vue/tsconfig": "^0.5.1",
18
+ "@novnc/novnc": "^1.4.0",
19
19
  "@vueuse/core": "^10.7.1",
20
+ "@vueuse/shared": "^10.7.1",
21
+ "iterable-backoff": "^0.1.0",
20
22
  "lodash-es": "^4.17.21",
23
+ "placement.js": "^1.0.0-beta.5"
24
+ },
25
+ "peerDependencies": {
26
+ "pinia": "^2.1.7",
27
+ "vue": "^3.4.13",
28
+ "vue-i18n": "^9.9.0",
29
+ "vue-router": "^4.2.5"
30
+ },
31
+ "devDependencies": {
32
+ "@types/lodash-es": "^4.17.12",
33
+ "@types/novnc__novnc": "^1.3.5",
34
+ "@vue/tsconfig": "^0.5.1",
21
35
  "pinia": "^2.1.7",
22
- "placement.js": "^1.0.0-beta.5",
23
36
  "vue": "^3.4.13",
24
37
  "vue-i18n": "^9.9.0",
25
38
  "vue-router": "^4.2.5"