@xen-orchestra/web-core 0.54.0 → 0.55.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.
Files changed (74) hide show
  1. package/lib/components/button-group/VtsButtonGroup.vue +11 -1
  2. package/lib/components/drawer/VtsDrawer.vue +85 -0
  3. package/lib/components/drawer/VtsDrawerButton.vue +21 -0
  4. package/lib/components/drawer/VtsDrawerCancelButton.vue +33 -0
  5. package/lib/components/drawer/VtsDrawerConfirmButton.vue +30 -0
  6. package/lib/components/drawer/VtsDrawerList.vue +34 -0
  7. package/lib/components/layout/VtsLayoutSidebar.vue +5 -2
  8. package/lib/components/modal/VtsModalButton.vue +0 -1
  9. package/lib/components/query-builder/VtsQueryBuilderModal.vue +0 -1
  10. package/lib/components/state-hero/VtsStateHero.vue +17 -7
  11. package/lib/components/table/cells/VtsHeaderCell.vue +1 -17
  12. package/lib/components/table/cells/VtsTagCell.vue +4 -2
  13. package/lib/components/ui/drawer/UiDrawer.vue +123 -0
  14. package/lib/components/ui/modal/UiModal.vue +10 -18
  15. package/lib/composables/default-tab.composable.ts +4 -0
  16. package/lib/icons/action-icons.ts +6 -2
  17. package/lib/icons/custom-icons.ts +16 -0
  18. package/lib/icons/object-icons.ts +33 -18
  19. package/lib/locales/cs.json +56 -12
  20. package/lib/locales/da.json +1 -3
  21. package/lib/locales/de.json +0 -12
  22. package/lib/locales/en.json +54 -10
  23. package/lib/locales/es.json +6 -7
  24. package/lib/locales/fr.json +54 -10
  25. package/lib/locales/ko.json +0 -4
  26. package/lib/locales/nb-NO.json +18 -20
  27. package/lib/locales/nl.json +0 -12
  28. package/lib/locales/pt-BR.json +0 -3
  29. package/lib/locales/pt.json +0 -3
  30. package/lib/locales/sk.json +56 -12
  31. package/lib/locales/sv.json +1 -13
  32. package/lib/locales/zh-Hans.json +0 -12
  33. package/lib/packages/drawer/DrawerProvider.vue +17 -0
  34. package/lib/packages/drawer/README.md +189 -0
  35. package/lib/packages/drawer/create-drawer-opener.ts +119 -0
  36. package/lib/packages/drawer/drawer.store.ts +22 -0
  37. package/lib/packages/drawer/types.ts +93 -0
  38. package/lib/packages/drawer/use-drawer.ts +53 -0
  39. package/lib/packages/modal/create-modal-opener.ts +12 -10
  40. package/lib/tables/column-definitions/action-column.ts +1 -1
  41. package/lib/tables/column-definitions/address-column.ts +1 -1
  42. package/lib/tables/column-definitions/button-column.ts +1 -1
  43. package/lib/tables/column-definitions/button-icon-column.ts +1 -1
  44. package/lib/tables/column-definitions/collapsed-list-column.ts +1 -1
  45. package/lib/tables/column-definitions/date-column.ts +1 -1
  46. package/lib/tables/column-definitions/double-link-column.ts +1 -1
  47. package/lib/tables/column-definitions/info-column.ts +1 -1
  48. package/lib/tables/column-definitions/input-column.ts +1 -5
  49. package/lib/tables/column-definitions/link-column.ts +1 -1
  50. package/lib/tables/column-definitions/link-or-text-column.ts +1 -1
  51. package/lib/tables/column-definitions/literal-column.ts +1 -1
  52. package/lib/tables/column-definitions/number-column.ts +1 -1
  53. package/lib/tables/column-definitions/percent-column.ts +1 -1
  54. package/lib/tables/column-definitions/progress-bar-column.ts +1 -1
  55. package/lib/tables/column-definitions/select-column.ts +1 -1
  56. package/lib/tables/column-definitions/status-column.ts +2 -2
  57. package/lib/tables/column-definitions/tag-column.ts +3 -2
  58. package/lib/tables/column-definitions/text-column.ts +1 -1
  59. package/lib/tables/column-definitions/truncated-text-column.ts +1 -1
  60. package/lib/tables/column-sets/backup-job-schedule-columns.ts +2 -2
  61. package/lib/tables/column-sets/backup-log-columns.ts +1 -1
  62. package/lib/tables/column-sets/new-vm-network-columns.ts +0 -2
  63. package/lib/tables/column-sets/new-vm-sr-columns.ts +0 -1
  64. package/lib/tables/column-sets/server-columns.ts +1 -1
  65. package/lib/tables/column-sets/snapshot-columns.ts +1 -1
  66. package/lib/tables/column-sets/sr-columns.ts +2 -2
  67. package/lib/tables/column-sets/traffic-rules-columns.ts +5 -7
  68. package/lib/tables/column-sets/vif-network-columns.ts +24 -0
  69. package/lib/tables/helpers/render-head-cell.ts +2 -4
  70. package/lib/tables/types.ts +0 -2
  71. package/lib/types/connection.ts +14 -0
  72. package/lib/types/storage-repository.type.ts +14 -0
  73. package/lib/utils/sr.utils.ts +34 -0
  74. package/package.json +4 -4
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="vts-button-group">
2
+ <div class="vts-button-group" :class="{ 'no-stack': noStack }">
3
3
  <div class="line">
4
4
  <slot />
5
5
  </div>
@@ -10,6 +10,10 @@
10
10
  </template>
11
11
 
12
12
  <script lang="ts" setup>
13
+ defineProps<{
14
+ noStack?: boolean
15
+ }>()
16
+
13
17
  const slots = defineSlots<{
14
18
  default(): any
15
19
  tertiary?(): any
@@ -34,5 +38,11 @@ const slots = defineSlots<{
34
38
  flex-direction: column-reverse;
35
39
  }
36
40
  }
41
+
42
+ &.no-stack .line {
43
+ @media (--small) {
44
+ flex-direction: row;
45
+ }
46
+ }
37
47
  }
38
48
  </style>
@@ -0,0 +1,85 @@
1
+ <template>
2
+ <UiDrawer
3
+ :is-open="effectiveIsOpen"
4
+ :is-dismissible="dismissible"
5
+ v-on="{ dismiss: handleDismiss, afterLeave: onAfterLeave }"
6
+ >
7
+ <template v-if="slots.title" #title>
8
+ <slot name="title" />
9
+ </template>
10
+
11
+ <template #content>
12
+ <slot name="content" />
13
+ </template>
14
+
15
+ <template v-if="slots.buttons" #buttons>
16
+ <slot name="buttons" />
17
+ </template>
18
+ </UiDrawer>
19
+ </template>
20
+
21
+ <script lang="ts" setup>
22
+ import UiDrawer from '@core/components/ui/drawer/UiDrawer.vue'
23
+ import { IK_DRAWER } from '@core/packages/drawer/types.ts'
24
+ import { useMagicKeys, whenever } from '@vueuse/core'
25
+ import { computed, inject, onMounted, ref } from 'vue'
26
+
27
+ const { dismissible, isOpen, current } = defineProps<{
28
+ dismissible?: boolean
29
+ isOpen?: boolean
30
+ current?: boolean
31
+ }>()
32
+
33
+ const emit = defineEmits<{
34
+ dismiss: []
35
+ }>()
36
+
37
+ const slots = defineSlots<{
38
+ content(): any
39
+ title?(): any
40
+ buttons?(): any
41
+ }>()
42
+
43
+ const drawer = inject(IK_DRAWER, undefined)
44
+
45
+ const internalVisible = ref(false)
46
+
47
+ onMounted(() => {
48
+ if (isOpen === undefined) {
49
+ internalVisible.value = true
50
+ }
51
+ })
52
+
53
+ const effectiveIsOpen = computed(() => isOpen ?? internalVisible.value)
54
+
55
+ let afterLeaveCallback: (() => void) | undefined
56
+
57
+ function onAfterLeave() {
58
+ afterLeaveCallback?.()
59
+ afterLeaveCallback = undefined
60
+ }
61
+
62
+ const handleDismiss = computed(() => {
63
+ if (!dismissible) {
64
+ return undefined
65
+ }
66
+
67
+ return () => {
68
+ if (isOpen !== undefined) {
69
+ emit('dismiss')
70
+ return
71
+ }
72
+
73
+ afterLeaveCallback = () => drawer?.value.onCancel()
74
+ internalVisible.value = false
75
+ }
76
+ })
77
+
78
+ const { escape } = useMagicKeys()
79
+
80
+ whenever(escape, () => {
81
+ if (dismissible && current) {
82
+ handleDismiss.value?.()
83
+ }
84
+ })
85
+ </script>
@@ -0,0 +1,21 @@
1
+ <template>
2
+ <UiButton accent="brand" :busy="drawer?.isBusy.value" :variant size="medium">
3
+ <slot />
4
+ </UiButton>
5
+ </template>
6
+
7
+ <script lang="ts" setup>
8
+ import UiButton, { type ButtonVariant } from '@core/components/ui/button/UiButton.vue'
9
+ import { IK_DRAWER } from '@core/packages/drawer/types.ts'
10
+ import { inject } from 'vue'
11
+
12
+ defineProps<{
13
+ variant: ButtonVariant
14
+ }>()
15
+
16
+ defineSlots<{
17
+ default(): any
18
+ }>()
19
+
20
+ const drawer = inject(IK_DRAWER)
21
+ </script>
@@ -0,0 +1,33 @@
1
+ <template>
2
+ <VtsDrawerButton variant="secondary" @click="handleClick()">
3
+ <slot>{{ t('cancel') }}</slot>
4
+ </VtsDrawerButton>
5
+ </template>
6
+
7
+ <script lang="ts" setup>
8
+ import VtsDrawerButton from '@core/components/drawer/VtsDrawerButton.vue'
9
+ import { IK_DRAWER } from '@core/packages/drawer/types.ts'
10
+ import { inject } from 'vue'
11
+ import { useI18n } from 'vue-i18n'
12
+
13
+ const { onClick } = defineProps<{
14
+ onClick?: () => void
15
+ }>()
16
+
17
+ defineSlots<{
18
+ default?(): any
19
+ }>()
20
+
21
+ const { t } = useI18n()
22
+
23
+ const drawer = inject(IK_DRAWER)
24
+
25
+ function handleClick() {
26
+ if (onClick) {
27
+ onClick()
28
+ return
29
+ }
30
+
31
+ drawer?.value.onCancel()
32
+ }
33
+ </script>
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <VtsDrawerButton variant="primary" @click="handleClick()">
3
+ <slot />
4
+ </VtsDrawerButton>
5
+ </template>
6
+
7
+ <script lang="ts" setup>
8
+ import VtsDrawerButton from '@core/components/drawer/VtsDrawerButton.vue'
9
+ import { IK_DRAWER } from '@core/packages/drawer/types.ts'
10
+ import { inject } from 'vue'
11
+
12
+ const { onClick } = defineProps<{
13
+ onClick?: () => void
14
+ }>()
15
+
16
+ defineSlots<{
17
+ default(): any
18
+ }>()
19
+
20
+ const drawer = inject(IK_DRAWER)
21
+
22
+ function handleClick() {
23
+ if (onClick) {
24
+ onClick()
25
+ return
26
+ }
27
+
28
+ drawer?.value.onConfirm()
29
+ }
30
+ </script>
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <div v-if="drawerStore.drawers.length > 0" class="vts-drawer-list">
3
+ <DrawerProvider v-for="(drawer, index) of drawerStore.drawers" :key="drawer.id" :drawer>
4
+ <component
5
+ :is="drawer.component"
6
+ class="drawer-component"
7
+ v-bind="drawer.props"
8
+ :current="index === drawerStore.drawers.length - 1"
9
+ @confirm="drawer.onConfirm"
10
+ @cancel="drawer.onCancel"
11
+ />
12
+ </DrawerProvider>
13
+ </div>
14
+ </template>
15
+
16
+ <script lang="ts" setup>
17
+ import { useDrawerStore } from '@core/packages/drawer/drawer.store.ts'
18
+ import DrawerProvider from '@core/packages/drawer/DrawerProvider.vue'
19
+
20
+ const drawerStore = useDrawerStore()
21
+ </script>
22
+
23
+ <style lang="postcss" scoped>
24
+ .vts-drawer-list {
25
+ position: fixed;
26
+ inset: 0;
27
+ background-color: var(--color-opacity-primary);
28
+ z-index: 1020;
29
+
30
+ .drawer-component:not(:last-child) {
31
+ filter: brightness(0.8);
32
+ }
33
+ }
34
+ </style>
@@ -59,6 +59,7 @@ const ui = useUiStore()
59
59
 
60
60
  <style lang="postcss" scoped>
61
61
  .vts-layout-sidebar {
62
+ position: relative;
62
63
  display: flex;
63
64
  flex-direction: column;
64
65
  height: 100%;
@@ -83,8 +84,10 @@ const ui = useUiStore()
83
84
  }
84
85
 
85
86
  .lock {
86
- text-align: right;
87
- padding: 0.8rem 0.8rem 0;
87
+ position: absolute;
88
+ inset-block-start: 0.8rem;
89
+ inset-inline-end: 1.2rem;
90
+ z-index: 1;
88
91
  }
89
92
 
90
93
  .content {
@@ -26,7 +26,6 @@ const modalAccent = inject(IK_MODAL_ACCENT)
26
26
  const buttonAccent = useMapper(
27
27
  () => modalAccent?.value,
28
28
  {
29
- success: 'brand',
30
29
  info: 'brand',
31
30
  warning: 'warning',
32
31
  danger: 'danger',
@@ -44,7 +44,6 @@ const uiStore = useUiStore()
44
44
  }
45
45
 
46
46
  &:deep(.modal) {
47
- background-color: var(--color-neutral-background-primary) !important;
48
47
  padding: 0;
49
48
  gap: 0;
50
49
 
@@ -1,8 +1,11 @@
1
1
  <template>
2
- <div :class="[className, { horizontal, error, success, 'no-background': noBackground }]" class="vts-state-hero">
2
+ <div
3
+ :class="[className, { horizontal: isHorizontal, error, success, 'no-background': noBackground }]"
4
+ class="vts-state-hero"
5
+ >
3
6
  <UiLoader v-if="type === 'busy'" class="loader" />
4
7
  <img v-else-if="imageSrc" :src="imageSrc" :alt="type" class="image" />
5
- <div v-if="slots.default || success" :class="typoClass" class="content">
8
+ <div v-if="slots.default || success" :class="[typoClass, { mobile: isMobile }]" class="content">
6
9
  <div v-if="success">{{ t('all-good!') }}</div>
7
10
  <slot />
8
11
  </div>
@@ -11,6 +14,7 @@
11
14
 
12
15
  <script lang="ts" setup>
13
16
  import UiLoader from '@core/components/ui/loader/UiLoader.vue'
17
+ import { useUiStore } from '@core/stores/ui.store'
14
18
  import { toVariants } from '@core/utils/to-variants.util.ts'
15
19
  import { computed } from 'vue'
16
20
  import { useI18n } from 'vue-i18n'
@@ -32,7 +36,7 @@ export type StateHeroType =
32
36
  | 'all-done'
33
37
  | 'creating'
34
38
 
35
- const { format, type, size } = defineProps<{
39
+ const { format, type, size, horizontal } = defineProps<{
36
40
  format: StateHeroFormat
37
41
  type: StateHeroType
38
42
  size: StateHeroSize
@@ -44,8 +48,14 @@ const slots = defineSlots<{
44
48
  default?(): any
45
49
  }>()
46
50
 
51
+ const uiStore = useUiStore()
52
+
47
53
  const { t } = useI18n()
48
54
 
55
+ const isHorizontal = computed(() => horizontal && !uiStore.isSmall)
56
+
57
+ const isMobile = computed(() => uiStore.isSmall)
58
+
49
59
  const typoClass = computed(() => (format === 'page' ? 'typo-h2' : 'typo-h4'))
50
60
 
51
61
  const className = computed(() => toVariants({ size, format }))
@@ -73,10 +83,6 @@ const imageSrc = computed(() => {
73
83
 
74
84
  &:not(.horizontal) {
75
85
  flex-direction: column;
76
-
77
- .content {
78
- align-items: center;
79
- }
80
86
  }
81
87
 
82
88
  .image {
@@ -88,6 +94,10 @@ const imageSrc = computed(() => {
88
94
  flex-direction: column;
89
95
  gap: 1.6rem;
90
96
 
97
+ &:not(.mobile) {
98
+ text-align: center;
99
+ }
100
+
91
101
  &:empty {
92
102
  display: none;
93
103
  }
@@ -1,31 +1,15 @@
1
1
  <template>
2
2
  <UiColumnHeader class="vts-header-cell">
3
- <div class="cell-content">
4
- <VtsIcon v-if="icon" :name="icon" size="medium" />
5
- <slot />
6
- </div>
3
+ <slot />
7
4
  </UiColumnHeader>
8
5
  </template>
9
6
 
10
7
  <script lang="ts" setup>
11
- import VtsIcon from '@core/components/icon/VtsIcon.vue'
12
8
  import UiColumnHeader from '@core/components/ui/column-header/UiColumnHeader.vue'
13
- import type { IconName } from '@core/icons'
14
-
15
- defineProps<{
16
- icon?: IconName
17
- }>()
18
9
  </script>
19
10
 
20
11
  <style lang="postcss" scoped>
21
12
  .vts-header-cell {
22
13
  max-width: 30rem;
23
-
24
- .cell-content {
25
- display: flex;
26
- align-items: center;
27
- gap: 0.8rem;
28
- white-space: nowrap;
29
- }
30
14
  }
31
15
  </style>
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <UiTableCell>
3
3
  <UiTagsList>
4
- <VtsTag v-for="tagItem of tags" :key="tagItem" :value="tagItem" />
4
+ <VtsTag v-for="tagItem of tags" :key="tagItem" :value="tagItem" :accent />
5
5
  </UiTagsList>
6
6
  </UiTableCell>
7
7
  </template>
@@ -9,13 +9,15 @@
9
9
  <script setup lang="ts">
10
10
  import VtsTag from '@core/components/tag/VtsTag.vue'
11
11
  import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
12
+ import type { TagAccent } from '@core/components/ui/tag/UiTag.vue'
12
13
  import UiTagsList from '@core/components/ui/tag/UiTagsList.vue'
13
14
  import type { MaybeArray } from '@core/types/utility.type'
14
15
  import { toArray } from '@core/utils/to-array.utils'
15
16
  import { computed } from 'vue'
16
17
 
17
- const { tag } = defineProps<{
18
+ const { tag, accent } = defineProps<{
18
19
  tag: MaybeArray<string>
20
+ accent: TagAccent
19
21
  }>()
20
22
 
21
23
  const tags = computed(() => toArray(tag).filter(tagItem => tagItem.trim() !== ''))
@@ -0,0 +1,123 @@
1
+ <template>
2
+ <Transition name="drawer" @after-leave="emit('afterLeave')">
3
+ <div v-if="isOpen" class="ui-drawer" aria-modal="true" role="dialog" @click.self="isDismissible && emit('dismiss')">
4
+ <aside class="drawer">
5
+ <div class="header">
6
+ <div v-if="slots.title || title !== undefined" class="typo-h4">
7
+ <slot name="title">
8
+ {{ title }}
9
+ </slot>
10
+ </div>
11
+ <UiButtonIcon
12
+ v-if="isDismissible"
13
+ :target-scale="2"
14
+ icon="action:close-cancel-clear"
15
+ accent="brand"
16
+ size="small"
17
+ @click="emit('dismiss')"
18
+ />
19
+ </div>
20
+ <div class="content">
21
+ <slot name="content" />
22
+ </div>
23
+ <VtsButtonGroup v-if="slots.buttons" no-stack class="buttons">
24
+ <slot name="buttons" />
25
+ </VtsButtonGroup>
26
+ </aside>
27
+ </div>
28
+ </Transition>
29
+ </template>
30
+
31
+ <script lang="ts" setup>
32
+ import VtsButtonGroup from '@core/components/button-group/VtsButtonGroup.vue'
33
+ import UiButtonIcon from '@core/components/ui/button-icon/UiButtonIcon.vue'
34
+
35
+ defineProps<{
36
+ isOpen: boolean
37
+ isDismissible?: boolean
38
+ title?: string
39
+ }>()
40
+
41
+ const emit = defineEmits<{
42
+ dismiss: []
43
+ afterLeave: []
44
+ }>()
45
+
46
+ const slots = defineSlots<{
47
+ content(): any
48
+ title?(): any
49
+ buttons?(): any
50
+ }>()
51
+ </script>
52
+
53
+ <style lang="postcss" scoped>
54
+ /* Slide-in from right */
55
+ .drawer-enter-active.ui-drawer,
56
+ .drawer-leave-active.ui-drawer {
57
+ transition: opacity 0.3s ease;
58
+ }
59
+
60
+ .drawer-enter-active .drawer,
61
+ .drawer-leave-active .drawer {
62
+ transition: transform 0.3s ease;
63
+ }
64
+
65
+ .drawer-enter-from.ui-drawer,
66
+ .drawer-leave-to.ui-drawer {
67
+ opacity: 0;
68
+ }
69
+
70
+ .drawer-enter-from .drawer,
71
+ .drawer-leave-to .drawer {
72
+ transform: translateX(100%);
73
+
74
+ &:dir(rtl) {
75
+ transform: translateX(-100%);
76
+ }
77
+ }
78
+
79
+ .ui-drawer {
80
+ position: fixed;
81
+ display: flex;
82
+ inset: 0;
83
+ justify-content: flex-end;
84
+ align-items: stretch;
85
+
86
+ .drawer {
87
+ display: flex;
88
+ flex-direction: column;
89
+ min-width: 100%;
90
+ max-width: 100%;
91
+ min-height: 100dvh;
92
+ background-color: var(--color-neutral-background-secondary);
93
+
94
+ .header {
95
+ display: flex;
96
+ justify-content: space-between;
97
+ align-items: center;
98
+ padding: 1.6rem;
99
+ background-color: var(--color-neutral-background-primary);
100
+ border-block-end: 0.1rem solid var(--color-neutral-border);
101
+ }
102
+
103
+ .content {
104
+ overflow: auto;
105
+ flex: 1;
106
+ padding: 2.4rem;
107
+ }
108
+
109
+ .buttons {
110
+ margin-block-start: auto;
111
+ padding: 1.6rem;
112
+ background-color: var(--color-neutral-background-primary);
113
+ border-block-start: 0.1rem solid var(--color-neutral-border);
114
+ }
115
+
116
+ @media (--medium-or-large) {
117
+ min-width: 50%;
118
+ max-width: 50%;
119
+ border-inline-start: 0.1rem solid var(--color-neutral-border);
120
+ }
121
+ }
122
+ }
123
+ </style>
@@ -1,4 +1,4 @@
1
- <!-- v2 -->
1
+ <!-- v4 -->
2
2
  <template>
3
3
  <form :class="className" class="ui-modal" @click.self="emit('dismiss')">
4
4
  <div class="modal">
@@ -7,8 +7,8 @@
7
7
  :accent="closeIconAccent"
8
8
  :target-scale="2"
9
9
  class="dismiss-button"
10
- icon="fa:xmark"
11
- size="small"
10
+ icon="action:close-cancel-clear"
11
+ size="medium"
12
12
  @click="emit('dismiss')"
13
13
  />
14
14
  <main class="main">
@@ -36,7 +36,7 @@ import { useMapper } from '@core/packages/mapper'
36
36
  import { toVariants } from '@core/utils/to-variants.util.ts'
37
37
  import { computed } from 'vue'
38
38
 
39
- export type ModalAccent = 'info' | 'success' | 'warning' | 'danger'
39
+ export type ModalAccent = 'info' | 'warning' | 'danger'
40
40
 
41
41
  const { accent } = defineProps<{
42
42
  accent: ModalAccent
@@ -58,7 +58,6 @@ const closeIconAccent = useMapper(
58
58
  () => accent,
59
59
  {
60
60
  info: 'brand',
61
- success: 'brand',
62
61
  warning: 'warning',
63
62
  danger: 'danger',
64
63
  },
@@ -84,7 +83,10 @@ const className = computed(() => toVariants({ accent }))
84
83
  max-height: min(90vh, 80rem);
85
84
  padding: 3.2rem 2.4rem 2.4rem;
86
85
  gap: 2.4rem;
86
+ background-color: var(--color-neutral-background-secondary);
87
87
  border-radius: 1rem;
88
+ border-width: 0.1rem;
89
+ border-style: solid;
88
90
 
89
91
  &:not(:has(.buttons)) {
90
92
  padding-bottom: 3.2rem;
@@ -122,7 +124,7 @@ const className = computed(() => toVariants({ accent }))
122
124
 
123
125
  &.accent--info {
124
126
  .modal {
125
- background-color: var(--color-info-background-selected);
127
+ border-color: var(--color-info-item-base);
126
128
  }
127
129
 
128
130
  .main .icon {
@@ -130,19 +132,9 @@ const className = computed(() => toVariants({ accent }))
130
132
  }
131
133
  }
132
134
 
133
- &.accent--success {
134
- .modal {
135
- background-color: var(--color-success-background-selected);
136
- }
137
-
138
- .main .icon {
139
- color: var(--color-success-txt-base);
140
- }
141
- }
142
-
143
135
  &.accent--warning {
144
136
  .modal {
145
- background-color: var(--color-warning-background-selected);
137
+ border-color: var(--color-warning-item-base);
146
138
  }
147
139
 
148
140
  .main .icon {
@@ -152,7 +144,7 @@ const className = computed(() => toVariants({ accent }))
152
144
 
153
145
  &.accent--danger {
154
146
  .modal {
155
- background-color: var(--color-danger-background-selected);
147
+ border-color: var(--color-danger-item-base);
156
148
  }
157
149
 
158
150
  .main .icon {
@@ -14,6 +14,10 @@ export function useDefaultTab(dispatcherRouteName: RouteRecordName & string, def
14
14
  watch(
15
15
  () => route.name as string,
16
16
  name => {
17
+ if (name == null) {
18
+ return
19
+ }
20
+
17
21
  if (name === dispatcherRouteName) {
18
22
  const isSameDispatcher = localStorage.getItem(TAB_MEMORY_DISPATCHER) === dispatcherRouteName
19
23
  const tabName = (isSameDispatcher ? localStorage.getItem(TAB_MEMORY_LAST) : null) ?? defaultTab
@@ -1,3 +1,4 @@
1
+ import { slash } from '@core/icons/custom-icons.ts'
1
2
  import { defineIconPack, type IconSingleConfig } from '@core/packages/icon'
2
3
  import { faCopy, faSquare as checkboxEmpty, type IconDefinition } from '@fortawesome/free-regular-svg-icons'
3
4
  import {
@@ -24,6 +25,7 @@ import {
24
25
  faLink,
25
26
  faLinkSlash,
26
27
  faMinus,
28
+ faPlug,
27
29
  faPowerOff,
28
30
  faRefresh,
29
31
  faRoute,
@@ -132,8 +134,10 @@ export const actionIcons = defineIconPack({
132
134
  fill: constructIcon(faFillDrip),
133
135
  duplicate: constructIcon(faClone),
134
136
  copy: constructIcon(faCopy),
135
- connect: constructIcon(faLink),
136
- disconnect: constructIcon(faLinkSlash),
137
+ attach: constructIcon(faLink),
138
+ detach: constructIcon(faLinkSlash),
139
+ connect: constructIcon(faPlug),
140
+ disconnect: [constructIcon(faPlug), { icon: slash }],
137
141
  forget: constructIcon(faEraser),
138
142
  delete: { icon: faTrash, color: 'var(--color-danger-txt-primary)' },
139
143
  'more-actions': constructIcon(faEllipsis),
@@ -0,0 +1,16 @@
1
+ import { defineIcon } from '@core/packages/icon'
2
+ import { faSlash } from '@fortawesome/free-solid-svg-icons'
3
+
4
+ export const slash = defineIcon([
5
+ {
6
+ icon: faSlash,
7
+ color: 'var(--color-neutral-background-primary)',
8
+ translate: [-0.5, 0.5],
9
+ size: 20,
10
+ },
11
+ {
12
+ icon: faSlash,
13
+ translate: [0.5, -0.5],
14
+ size: 20,
15
+ },
16
+ ])