@xen-orchestra/web-core 0.7.0 → 0.8.0
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.
- package/lib/assets/css/typography/_style.pcss +1 -0
- package/lib/components/layout/VtsLayoutSidebar.vue +1 -1
- package/lib/components/state-hero/VtsErrorNoDataHero.vue +11 -0
- package/lib/components/state-hero/VtsNoSelectionHero.vue +13 -0
- package/lib/components/state-hero/VtsObjectNotFoundHero.vue +3 -2
- package/lib/components/state-hero/VtsStateHero.vue +30 -2
- package/lib/components/ui/donut-chart/UiDonutChart.vue +2 -2
- package/lib/components/ui/dropdown-button/UiDropdownButton.vue +81 -0
- package/lib/components/ui/link/UiLink.vue +75 -0
- package/lib/components/ui/tag/UiTagsList.vue +14 -0
- package/lib/composables/link-component.composable.ts +53 -0
- package/lib/locales/cs.json +1 -0
- package/lib/locales/de.json +2 -0
- package/lib/locales/en.json +4 -0
- package/lib/locales/fa.json +2 -0
- package/lib/locales/fr.json +4 -0
- package/lib/packages/job/README.md +130 -0
- package/lib/packages/job/define-job-arg.ts +12 -0
- package/lib/packages/job/define-job.ts +130 -0
- package/lib/packages/job/index.ts +4 -0
- package/lib/packages/job/job-error.ts +14 -0
- package/lib/packages/job/use-job-store.ts +44 -0
- package/lib/packages/menu/README.md +194 -0
- package/lib/packages/menu/action.ts +101 -0
- package/lib/packages/menu/base.ts +26 -0
- package/lib/packages/menu/context.ts +27 -0
- package/lib/packages/menu/index.ts +10 -0
- package/lib/packages/menu/job.ts +15 -0
- package/lib/packages/menu/link.ts +56 -0
- package/lib/packages/menu/menu.ts +50 -0
- package/lib/packages/menu/router-link.ts +51 -0
- package/lib/packages/menu/structure.ts +88 -0
- package/lib/packages/menu/toggle-target.ts +59 -0
- package/lib/packages/menu/toggle-trigger.ts +72 -0
- package/lib/packages/menu/toggle.ts +43 -0
- package/package.json +2 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { BaseItem, type Menu, type MenuLike, parseConfigHolder } from '@core/packages/menu'
|
|
2
|
+
import { computed, markRaw, type MaybeRefOrGetter, reactive, toValue } from 'vue'
|
|
3
|
+
import { type RouteLocationRaw, RouterLink } from 'vue-router'
|
|
4
|
+
|
|
5
|
+
export interface MenuRouterLinkConfig {
|
|
6
|
+
to: MaybeRefOrGetter<RouteLocationRaw>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class MenuRouterLinkConfigHolder {
|
|
10
|
+
constructor(public config: MenuRouterLinkConfig) {}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface MenuRouterLinkProps {
|
|
14
|
+
as: typeof RouterLink
|
|
15
|
+
to: RouteLocationRaw
|
|
16
|
+
onClick: () => void
|
|
17
|
+
onMouseenter: () => void
|
|
18
|
+
'data-menu-id': string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class MenuRouterLink extends BaseItem {
|
|
22
|
+
constructor(
|
|
23
|
+
public menu: Menu,
|
|
24
|
+
public config: MenuRouterLinkConfig
|
|
25
|
+
) {
|
|
26
|
+
super(menu)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get props(): MenuRouterLinkProps {
|
|
30
|
+
return reactive({
|
|
31
|
+
as: markRaw(RouterLink),
|
|
32
|
+
onMouseenter: () => this.activate(),
|
|
33
|
+
onClick: () => this.deactivate(),
|
|
34
|
+
to: computed(() => toValue(this.config.to)),
|
|
35
|
+
'data-menu-id': this.menu.context.id,
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function routerLink(to: MaybeRefOrGetter<RouteLocationRaw>, config: Omit<MenuRouterLinkConfig, 'to'> = {}) {
|
|
41
|
+
return new MenuRouterLinkConfigHolder({
|
|
42
|
+
...config,
|
|
43
|
+
to,
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function useMenuRouterLink(config: MenuRouterLinkConfig & { parent: MenuLike }) {
|
|
48
|
+
const { parent, to, ...configRest } = config
|
|
49
|
+
|
|
50
|
+
return parseConfigHolder(parent, routerLink(to, configRest))
|
|
51
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Menu,
|
|
3
|
+
MENU_SYMBOL,
|
|
4
|
+
MenuAction,
|
|
5
|
+
type MenuActionProps,
|
|
6
|
+
MenuActionConfigHolder,
|
|
7
|
+
type MenuLike,
|
|
8
|
+
MenuLink,
|
|
9
|
+
type MenuLinkProps,
|
|
10
|
+
MenuLinkConfigHolder,
|
|
11
|
+
MenuRouterLink,
|
|
12
|
+
type MenuRouterLinkProps,
|
|
13
|
+
MenuRouterLinkConfigHolder,
|
|
14
|
+
type MenuToggleProps,
|
|
15
|
+
MenuToggleConfigHolder,
|
|
16
|
+
MenuToggleTarget,
|
|
17
|
+
MenuToggleTrigger,
|
|
18
|
+
} from '@core/packages/menu'
|
|
19
|
+
import { type MaybeRefOrGetter, toValue } from 'vue'
|
|
20
|
+
|
|
21
|
+
export type MenuStructure = {
|
|
22
|
+
[K: string]: ConfigHolder
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type ConfigHolder =
|
|
26
|
+
| MenuActionConfigHolder
|
|
27
|
+
| MenuLinkConfigHolder
|
|
28
|
+
| MenuRouterLinkConfigHolder
|
|
29
|
+
| MenuToggleConfigHolder<any>
|
|
30
|
+
|
|
31
|
+
export type ParseConfigHolder<TConfigHolder extends ConfigHolder> = TConfigHolder extends MenuActionConfigHolder
|
|
32
|
+
? MenuActionProps
|
|
33
|
+
: TConfigHolder extends MenuLinkConfigHolder
|
|
34
|
+
? MenuLinkProps
|
|
35
|
+
: TConfigHolder extends MenuRouterLinkConfigHolder
|
|
36
|
+
? MenuRouterLinkProps
|
|
37
|
+
: TConfigHolder extends MenuToggleConfigHolder<infer TItems>
|
|
38
|
+
? MenuToggleProps<TItems>
|
|
39
|
+
: never
|
|
40
|
+
|
|
41
|
+
export type ParseStructure<TStructure extends MenuStructure> = {
|
|
42
|
+
[K in keyof TStructure]: ParseConfigHolder<TStructure[K]>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function parseConfigHolder<TConfigHolder extends ConfigHolder>(
|
|
46
|
+
menuLike: MenuLike,
|
|
47
|
+
configHolder: TConfigHolder
|
|
48
|
+
): ParseConfigHolder<TConfigHolder> {
|
|
49
|
+
const menu = menuLike instanceof Menu ? menuLike : menuLike[MENU_SYMBOL]
|
|
50
|
+
|
|
51
|
+
if (configHolder instanceof MenuActionConfigHolder) {
|
|
52
|
+
return new MenuAction(menu, configHolder.config).props as ParseConfigHolder<TConfigHolder>
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (configHolder instanceof MenuLinkConfigHolder) {
|
|
56
|
+
return new MenuLink(menu, configHolder.config).props as ParseConfigHolder<TConfigHolder>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (configHolder instanceof MenuRouterLinkConfigHolder) {
|
|
60
|
+
return new MenuRouterLink(menu, configHolder.config).props as ParseConfigHolder<TConfigHolder>
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (configHolder instanceof MenuToggleConfigHolder) {
|
|
64
|
+
const trigger = new MenuToggleTrigger(menu, configHolder.config)
|
|
65
|
+
const target = new MenuToggleTarget(trigger, configHolder.config)
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
$trigger: trigger.props,
|
|
69
|
+
$target: target.props,
|
|
70
|
+
$isOpen: trigger.isOpen,
|
|
71
|
+
[MENU_SYMBOL]: trigger.subMenu,
|
|
72
|
+
...parseStructure(trigger.subMenu, configHolder.config.items),
|
|
73
|
+
} as ParseConfigHolder<TConfigHolder>
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
throw new Error('Unsupported config')
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function parseStructure<TStructure extends MenuStructure>(
|
|
80
|
+
menu: Menu,
|
|
81
|
+
structure: MaybeRefOrGetter<TStructure>
|
|
82
|
+
): ParseStructure<TStructure> {
|
|
83
|
+
return Object.fromEntries(
|
|
84
|
+
Object.entries(toValue(structure)).map(([key, configHolder]) => {
|
|
85
|
+
return [key, parseConfigHolder(menu, configHolder)]
|
|
86
|
+
})
|
|
87
|
+
) as ParseStructure<TStructure>
|
|
88
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { MenuToggleTrigger } from '@core/packages/menu'
|
|
2
|
+
import { autoUpdate, flip, type Placement, shift, useFloating, type UseFloatingReturn } from '@floating-ui/vue'
|
|
3
|
+
import { unrefElement } from '@vueuse/core'
|
|
4
|
+
import { computed, reactive, ref, type Ref, toValue, type UnwrapRef } from 'vue'
|
|
5
|
+
|
|
6
|
+
export interface MenuToggleTargetConfig {
|
|
7
|
+
placement?: Placement
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface MenuToggleTargetProps {
|
|
11
|
+
ref: (el: any) => void
|
|
12
|
+
style: {
|
|
13
|
+
display: string | undefined
|
|
14
|
+
zIndex: number
|
|
15
|
+
} & UnwrapRef<UseFloatingReturn['floatingStyles']>
|
|
16
|
+
'data-menu-id': string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class MenuToggleTarget {
|
|
20
|
+
element: Ref<HTMLElement | null> = ref(null)
|
|
21
|
+
|
|
22
|
+
styles: UseFloatingReturn['floatingStyles']
|
|
23
|
+
|
|
24
|
+
constructor(
|
|
25
|
+
public trigger: MenuToggleTrigger,
|
|
26
|
+
public config: MenuToggleTargetConfig
|
|
27
|
+
) {
|
|
28
|
+
const { floatingStyles } = useFloating(trigger.element, this.element, {
|
|
29
|
+
placement: computed(() => toValue(config.placement) ?? 'bottom-start'),
|
|
30
|
+
open: trigger.isOpen,
|
|
31
|
+
whileElementsMounted: autoUpdate,
|
|
32
|
+
middleware: [shift(), flip()],
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
this.styles = floatingStyles
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get props(): MenuToggleTargetProps {
|
|
39
|
+
return reactive({
|
|
40
|
+
as: 'button',
|
|
41
|
+
type: 'button',
|
|
42
|
+
ref: (element: HTMLElement | null | undefined) => {
|
|
43
|
+
const newElement = unrefElement(element)
|
|
44
|
+
|
|
45
|
+
if (newElement !== this.element.value) {
|
|
46
|
+
this.element.value = newElement ?? null
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
style: computed(() => {
|
|
50
|
+
return {
|
|
51
|
+
display: this.trigger.isOpen.value ? undefined : 'none',
|
|
52
|
+
zIndex: 9999,
|
|
53
|
+
...this.styles.value,
|
|
54
|
+
}
|
|
55
|
+
}),
|
|
56
|
+
'data-menu-id': this.trigger.menu.context.id,
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { BaseItem, Menu } from '@core/packages/menu'
|
|
2
|
+
import { unrefElement, whenever } from '@vueuse/core'
|
|
3
|
+
import { computed, type ComputedRef, type MaybeRefOrGetter, reactive, ref, type Ref, toValue } from 'vue'
|
|
4
|
+
|
|
5
|
+
export interface MenuToggleTriggerConfig {
|
|
6
|
+
behavior?: MaybeRefOrGetter<'click' | 'mouseenter'>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface MenuToggleTriggerProps {
|
|
10
|
+
ref: (el: any) => void
|
|
11
|
+
as: 'button'
|
|
12
|
+
type: 'button'
|
|
13
|
+
submenu: true
|
|
14
|
+
onClick: () => void
|
|
15
|
+
onMouseenter: () => void
|
|
16
|
+
selected: boolean
|
|
17
|
+
'data-menu-id': string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class MenuToggleTrigger extends BaseItem {
|
|
21
|
+
element: Ref<HTMLElement | null> = ref(null)
|
|
22
|
+
|
|
23
|
+
subMenu: Menu
|
|
24
|
+
|
|
25
|
+
isSelfOpen = ref(false)
|
|
26
|
+
|
|
27
|
+
isOpen = computed(() => this.isSelfOpen.value || this.subMenu.isActive.value)
|
|
28
|
+
|
|
29
|
+
constructor(
|
|
30
|
+
public menu: Menu,
|
|
31
|
+
public config: MenuToggleTriggerConfig
|
|
32
|
+
) {
|
|
33
|
+
super(menu)
|
|
34
|
+
this.subMenu = new Menu(menu.context)
|
|
35
|
+
|
|
36
|
+
whenever(
|
|
37
|
+
() => !this.isActive.value && !this.subMenu.isActive.value,
|
|
38
|
+
() => {
|
|
39
|
+
this.isSelfOpen.value = false
|
|
40
|
+
}
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get isActive(): ComputedRef<boolean> {
|
|
45
|
+
return computed(() => super.isActive.value || this.subMenu?.isActive.value)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get props(): MenuToggleTriggerProps {
|
|
49
|
+
return reactive({
|
|
50
|
+
ref: (element: HTMLElement | null | undefined) => {
|
|
51
|
+
const newElement = unrefElement(element)
|
|
52
|
+
|
|
53
|
+
if (newElement !== this.element.value) {
|
|
54
|
+
this.element.value = newElement ?? null
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
as: 'button',
|
|
58
|
+
type: 'button',
|
|
59
|
+
submenu: true,
|
|
60
|
+
onClick: () => (this.isSelfOpen.value = !this.isOpen.value),
|
|
61
|
+
onMouseenter: () => {
|
|
62
|
+
this.activate()
|
|
63
|
+
|
|
64
|
+
if (toValue(this.config.behavior) === 'mouseenter') {
|
|
65
|
+
this.isSelfOpen.value = true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
selected: computed(() => this.isOpen.value),
|
|
69
|
+
'data-menu-id': this.menu.context.id,
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Menu,
|
|
3
|
+
MenuContext,
|
|
4
|
+
type MenuLike,
|
|
5
|
+
type MenuStructure,
|
|
6
|
+
type MenuToggleTargetConfig,
|
|
7
|
+
type MenuToggleTargetProps,
|
|
8
|
+
type MenuToggleTriggerConfig,
|
|
9
|
+
type MenuToggleTriggerProps,
|
|
10
|
+
parseConfigHolder,
|
|
11
|
+
type ParseStructure,
|
|
12
|
+
type WithMenu,
|
|
13
|
+
} from '@core/packages/menu'
|
|
14
|
+
import { computed, type ComputedRef, type MaybeRefOrGetter } from 'vue'
|
|
15
|
+
|
|
16
|
+
export type MenuToggleConfig<TStructure extends MenuStructure> = MenuToggleTriggerConfig &
|
|
17
|
+
MenuToggleTargetConfig & {
|
|
18
|
+
items?: MaybeRefOrGetter<TStructure>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class MenuToggleConfigHolder<TStructure extends MenuStructure> {
|
|
22
|
+
constructor(public config: MenuToggleConfig<TStructure>) {}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type MenuToggleProps<TStructure extends MenuStructure> = WithMenu &
|
|
26
|
+
ParseStructure<TStructure> & {
|
|
27
|
+
$trigger: MenuToggleTriggerProps
|
|
28
|
+
$target: MenuToggleTargetProps
|
|
29
|
+
$isOpen: ComputedRef<boolean>
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function toggle<const TStructure extends MenuStructure>(config: MenuToggleConfig<TStructure>) {
|
|
33
|
+
return new MenuToggleConfigHolder(config)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function useMenuToggle<const TStructure extends MenuStructure>(
|
|
37
|
+
config: MenuToggleConfig<TStructure> & { parent?: MenuLike } = {}
|
|
38
|
+
) {
|
|
39
|
+
const { parent, ...toggleConfig } = config
|
|
40
|
+
const menu = parent ?? new Menu(new MenuContext())
|
|
41
|
+
|
|
42
|
+
return computed(() => parseConfigHolder(menu, toggle<TStructure>(toggleConfig)))
|
|
43
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xen-orchestra/web-core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"exports": {
|
|
7
7
|
"./*": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
+
"@floating-ui/vue": "^1.1.5",
|
|
13
14
|
"@fontsource/poppins": "^5.0.14",
|
|
14
15
|
"@fortawesome/fontawesome-common-types": "^6.5.1",
|
|
15
16
|
"@fortawesome/free-regular-svg-icons": "^6.5.1",
|