@xen-orchestra/web-core 0.50.0 → 0.52.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 (38) hide show
  1. package/lib/assets/css/_reset.pcss +8 -1
  2. package/lib/components/column/VtsColumn.vue +5 -1
  3. package/lib/components/columns/VtsColumns.vue +17 -8
  4. package/lib/components/console/VtsRemoteConsole.vue +18 -16
  5. package/lib/components/{quick-info-column/VtsQuickInfoColumn.vue → key-value-list/VtsKeyValueList.vue} +3 -3
  6. package/lib/components/key-value-pair/VtsKeyValuePair.vue +48 -0
  7. package/lib/components/key-value-row/VtsKeyValueRow.vue +45 -0
  8. package/lib/components/menu/MenuTrigger.vue +1 -0
  9. package/lib/components/modal/VtsErrorModal.vue +36 -0
  10. package/lib/components/status/VtsStatus.vue +4 -0
  11. package/lib/components/table/cells/VtsDoubleLinkCell.vue +53 -0
  12. package/lib/components/tabular-key-value-list/VtsTabularKeyValueList.vue +29 -0
  13. package/lib/components/tabular-key-value-row/VtsTabularKeyValueRow.vue +42 -0
  14. package/lib/icons/fa-icons.ts +2 -0
  15. package/lib/icons/object-icons.ts +2 -0
  16. package/lib/locales/cs.json +52 -30
  17. package/lib/locales/da.json +0 -1
  18. package/lib/locales/de.json +1 -2
  19. package/lib/locales/en.json +53 -1
  20. package/lib/locales/es.json +8 -8
  21. package/lib/locales/fa.json +1 -1
  22. package/lib/locales/fr.json +53 -1
  23. package/lib/locales/nl.json +1 -2
  24. package/lib/locales/pl.json +1 -1
  25. package/lib/locales/pt-BR.json +3 -4
  26. package/lib/locales/pt.json +1 -2
  27. package/lib/locales/ru.json +0 -1
  28. package/lib/locales/sk.json +294 -3
  29. package/lib/locales/sv.json +1 -2
  30. package/lib/locales/zh-Hans.json +10 -1
  31. package/lib/packages/job/define-job.ts +1 -1
  32. package/lib/tables/column-definitions/double-link-column.ts +14 -0
  33. package/lib/tables/column-sets/host-columns.ts +1 -1
  34. package/lib/tables/column-sets/network-columns.ts +3 -1
  35. package/lib/tables/column-sets/snapshot-columns.ts +2 -2
  36. package/lib/tables/column-sets/traffic-rules-columns.ts +29 -0
  37. package/package.json +1 -1
  38. package/lib/components/quick-info-row/VtsQuickInfoRow.vue +0 -59
@@ -25,7 +25,10 @@ h5,
25
25
  h6,
26
26
  p,
27
27
  ol,
28
- ul {
28
+ ul,
29
+ dl,
30
+ dt,
31
+ dd {
29
32
  margin: 0;
30
33
  padding: 0;
31
34
  font-weight: inherit;
@@ -36,6 +39,10 @@ ul {
36
39
  list-style: none;
37
40
  }
38
41
 
42
+ dd {
43
+ margin-inline-start: 0;
44
+ }
45
+
39
46
  img {
40
47
  max-width: 100%;
41
48
  height: auto;
@@ -13,9 +13,13 @@ defineSlots<{
13
13
  <style lang="postcss" scoped>
14
14
  .vts-column {
15
15
  flex: 1;
16
- flex-basis: 0;
17
16
  display: flex;
18
17
  flex-direction: column;
19
18
  gap: 0.8rem;
19
+ min-width: 0;
20
+
21
+ @container vts-columns (max-width: 90rem) {
22
+ flex-basis: 100%;
23
+ }
20
24
  }
21
25
  </style>
@@ -1,16 +1,16 @@
1
1
  <template>
2
- <div class="vts-columns" :class="{ mobile: uiStore.isSmall }">
2
+ <div class="vts-columns" :class="{ 'extra-space-around': extraSpaceAround }">
3
3
  <component :is="nodes[index - 1] ?? VtsColumn" v-for="index of columns" :key="index" />
4
4
  </div>
5
5
  </template>
6
6
 
7
7
  <script lang="ts" setup>
8
8
  import VtsColumn from '@core/components/column/VtsColumn.vue'
9
- import { useUiStore } from '@core/stores/ui.store.ts'
10
9
  import { computed } from 'vue'
11
10
 
12
11
  const { columns: _columns = 2 } = defineProps<{
13
12
  columns?: number
13
+ extraSpaceAround?: boolean
14
14
  }>()
15
15
 
16
16
  const slots = defineSlots<{
@@ -20,19 +20,28 @@ const slots = defineSlots<{
20
20
  const nodes = computed(() => slots.default())
21
21
 
22
22
  const columns = computed(() => Math.max(_columns, nodes.value.length))
23
-
24
- const uiStore = useUiStore()
25
23
  </script>
26
24
 
27
25
  <style lang="postcss" scoped>
28
26
  .vts-columns {
27
+ container-type: inline-size;
28
+ container-name: vts-columns;
29
29
  display: flex;
30
+ flex-wrap: wrap;
30
31
  gap: 0.8rem;
31
- padding: 0.8rem;
32
- flex-direction: row;
33
32
 
34
- &.mobile {
35
- flex-direction: column;
33
+ &.extra-space-around {
34
+ margin: 0.8rem;
35
+ }
36
+
37
+ & > * {
38
+ flex: 1 0 0;
39
+ }
40
+
41
+ @container vts-columns (max-width: 60rem) {
42
+ & > * {
43
+ flex-basis: 100%;
44
+ }
36
45
  }
37
46
  }
38
47
  </style>
@@ -12,10 +12,10 @@ import VncClient from '@novnc/novnc/lib/rfb'
12
12
  import { whenever } from '@vueuse/core'
13
13
  import { promiseTimeout } from '@vueuse/shared'
14
14
  import { fibonacci } from 'iterable-backoff'
15
- import { onBeforeUnmount, ref, useTemplateRef, watchEffect } from 'vue'
15
+ import { onBeforeUnmount, ref, useTemplateRef, watch } from 'vue'
16
16
  import { useI18n } from 'vue-i18n'
17
17
 
18
- const props = defineProps<{
18
+ const { url, isConsoleAvailable } = defineProps<{
19
19
  url: URL
20
20
  isConsoleAvailable: boolean
21
21
  }>()
@@ -35,18 +35,16 @@ let nConnectionAttempts = 0
35
35
 
36
36
  function handleDisconnectionEvent() {
37
37
  clearVncClient()
38
- if (props.isConsoleAvailable) {
38
+ if (isConsoleAvailable) {
39
39
  nConnectionAttempts++
40
40
 
41
41
  if (nConnectionAttempts > N_TOTAL_TRIES) {
42
- console.error('The number of reconnection attempts has been exceeded for:', props.url)
42
+ console.error('The number of reconnection attempts has been exceeded for:', url)
43
43
  return
44
44
  }
45
45
 
46
46
  console.error(
47
- `Connection lost for the remote console: ${props.url}. New attempt in ${
48
- FIBONACCI_MS_ARRAY[nConnectionAttempts - 1]
49
- }ms`
47
+ `Connection lost for the remote console: ${url}. New attempt in ${FIBONACCI_MS_ARRAY[nConnectionAttempts - 1]}ms`
50
48
  )
51
49
  createVncConnection()
52
50
  }
@@ -80,7 +78,7 @@ async function createVncConnection() {
80
78
  }
81
79
  }
82
80
 
83
- vncClient = new VncClient(consoleContainer.value!, props.url.toString(), {
81
+ vncClient = new VncClient(consoleContainer.value!, url.toString(), {
84
82
  wsProtocols: ['binary'],
85
83
  })
86
84
  vncClient.scaleViewport = true
@@ -114,16 +112,20 @@ whenever(
114
112
  }
115
113
  )
116
114
 
117
- watchEffect(() => {
118
- if (consoleContainer.value === null || !props.isConsoleAvailable) {
119
- return
120
- }
115
+ watch(
116
+ [consoleContainer, () => isConsoleAvailable, () => url.toString()],
117
+ ([container, isAvailable]) => {
118
+ if (container === null || !isAvailable) {
119
+ return
120
+ }
121
121
 
122
- nConnectionAttempts = 0
122
+ nConnectionAttempts = 0
123
123
 
124
- clearVncClient()
125
- createVncConnection()
126
- })
124
+ clearVncClient()
125
+ createVncConnection()
126
+ },
127
+ { immediate: true }
128
+ )
127
129
 
128
130
  onBeforeUnmount(() => {
129
131
  clearVncClient()
@@ -1,11 +1,11 @@
1
1
  <template>
2
- <div class="vts-quick-info-column">
2
+ <dl class="vts-key-value-list">
3
3
  <slot />
4
- </div>
4
+ </dl>
5
5
  </template>
6
6
 
7
7
  <style lang="postcss" scoped>
8
- .vts-quick-info-column {
8
+ .vts-key-value-list {
9
9
  display: flex;
10
10
  flex-direction: column;
11
11
  gap: 1.6rem;
@@ -0,0 +1,48 @@
1
+ <template>
2
+ <dt class="typo-body-regular label">
3
+ <slot name="label">
4
+ {{ label }}
5
+ </slot>
6
+ </dt>
7
+ <dd class="typo-body-regular value">
8
+ <span v-tooltip class="text-ellipsis">
9
+ <slot name="value">
10
+ {{ value }}
11
+ </slot>
12
+ </span>
13
+ </dd>
14
+ </template>
15
+
16
+ <script lang="ts" setup>
17
+ import { vTooltip } from '@core/directives/tooltip.directive'
18
+
19
+ defineProps<{
20
+ label?: string
21
+ value?: string
22
+ }>()
23
+
24
+ defineSlots<{
25
+ label?(): any
26
+ value?(): any
27
+ }>()
28
+ </script>
29
+
30
+ <style lang="postcss" scoped>
31
+ .label {
32
+ color: var(--color-neutral-txt-secondary);
33
+ }
34
+
35
+ .value {
36
+ color: var(--color-neutral-txt-primary);
37
+ display: flex;
38
+ align-items: center;
39
+ gap: 0.8rem;
40
+ min-width: 0;
41
+
42
+ .text-ellipsis {
43
+ &:empty::before {
44
+ content: '-';
45
+ }
46
+ }
47
+ }
48
+ </style>
@@ -0,0 +1,45 @@
1
+ <template>
2
+ <div class="vts-key-value-row" :class="{ mobile: uiStore.isSmallOrMedium }">
3
+ <VtsKeyValuePair :label :value>
4
+ <template v-if="slots.label" #label>
5
+ <slot name="label" />
6
+ </template>
7
+ <template v-if="slots.value" #value>
8
+ <slot name="value" />
9
+ </template>
10
+ </VtsKeyValuePair>
11
+ </div>
12
+ </template>
13
+
14
+ <script lang="ts" setup>
15
+ import VtsKeyValuePair from '@core/components/key-value-pair/VtsKeyValuePair.vue'
16
+ import { useUiStore } from '@core/stores/ui.store.ts'
17
+
18
+ defineProps<{
19
+ label?: string
20
+ value?: string
21
+ }>()
22
+
23
+ const slots = defineSlots<{
24
+ label?(): any
25
+ value?(): any
26
+ }>()
27
+
28
+ const uiStore = useUiStore()
29
+ </script>
30
+
31
+ <style lang="postcss" scoped>
32
+ .vts-key-value-row {
33
+ display: flex;
34
+ gap: 2.4rem;
35
+
36
+ &.mobile {
37
+ flex-direction: column;
38
+ gap: 0.8rem;
39
+ }
40
+
41
+ :deep(dt) {
42
+ flex-shrink: 0;
43
+ }
44
+ }
45
+ </style>
@@ -28,6 +28,7 @@ defineProps<{
28
28
 
29
29
  &.disabled {
30
30
  color: var(--color-neutral-txt-secondary);
31
+ background-color: var(--color-neutral-background-disabled);
31
32
  }
32
33
 
33
34
  &:not(.disabled) {
@@ -0,0 +1,36 @@
1
+ <template>
2
+ <VtsModal accent="danger" icon="status:danger-picto" dismissible>
3
+ <template #title>
4
+ {{ title }}
5
+ </template>
6
+
7
+ <template #content>
8
+ <slot name="content">
9
+ {{ error }}
10
+ </slot>
11
+ </template>
12
+
13
+ <template #buttons>
14
+ <VtsModalConfirmButton>
15
+ {{ t('action:close') }}
16
+ </VtsModalConfirmButton>
17
+ </template>
18
+ </VtsModal>
19
+ </template>
20
+
21
+ <script lang="ts" setup>
22
+ import VtsModal from '@core/components/modal/VtsModal.vue'
23
+ import VtsModalConfirmButton from '@core/components/modal/VtsModalConfirmButton.vue'
24
+ import { useI18n } from 'vue-i18n'
25
+
26
+ defineProps<{
27
+ title: string
28
+ error?: string
29
+ }>()
30
+
31
+ defineSlots<{
32
+ content?(): any
33
+ }>()
34
+
35
+ const { t } = useI18n()
36
+ </script>
@@ -25,6 +25,8 @@ export type Status =
25
25
  | 'pending'
26
26
  | 'enabled'
27
27
  | 'disabled'
28
+ | 'allow'
29
+ | 'drop'
28
30
  | true
29
31
  | false
30
32
 
@@ -52,6 +54,8 @@ const currentStatus = useMapper<Status, { text: string; accent: InfoAccent }>(
52
54
  ['pending', { text: t('in-progress'), accent: 'info' }],
53
55
  ['enabled', { text: t('enabled'), accent: 'success' }],
54
56
  ['disabled', { text: t('disabled'), accent: 'muted' }],
57
+ ['allow', { text: t('allow'), accent: 'success' }],
58
+ ['drop', { text: t('drop'), accent: 'danger' }],
55
59
  [true, { text: t('enabled'), accent: 'success' }],
56
60
  [false, { text: t('disabled'), accent: 'muted' }],
57
61
  ],
@@ -0,0 +1,53 @@
1
+ <template>
2
+ <UiTableCell>
3
+ <div class="vts-double-link-cell">
4
+ <UiLink size="medium" :icon :to :href :target class="link">
5
+ <slot />
6
+ </UiLink>
7
+ <UiLink
8
+ v-if="suffix"
9
+ size="medium"
10
+ :icon="suffix.icon"
11
+ :to="suffix.to"
12
+ :href="suffix.href"
13
+ :target="suffix.target"
14
+ class="link"
15
+ >
16
+ {{ suffix.label }}
17
+ </UiLink>
18
+ </div>
19
+ </UiTableCell>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import UiLink from '@core/components/ui/link/UiLink.vue'
24
+ import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
25
+ import type { LinkOptions } from '@core/composables/link-component.composable.ts'
26
+ import type { IconName } from '@core/icons'
27
+
28
+ export type VtsDoubleLinkCellProps = LinkOptions & {
29
+ icon?: IconName
30
+ suffix?: LinkOptions & {
31
+ label: string
32
+ icon?: IconName
33
+ }
34
+ }
35
+
36
+ defineProps<VtsDoubleLinkCellProps>()
37
+
38
+ defineSlots<{
39
+ default(): any
40
+ }>()
41
+ </script>
42
+
43
+ <style scoped lang="postcss">
44
+ .vts-double-link-cell {
45
+ display: flex;
46
+ align-items: center;
47
+ gap: 0.8rem;
48
+ }
49
+
50
+ .link {
51
+ line-height: 1.5;
52
+ }
53
+ </style>
@@ -0,0 +1,29 @@
1
+ <template>
2
+ <dl class="vts-tabular-key-value-list" :class="{ 'full-height': fullHeight }">
3
+ <slot />
4
+ </dl>
5
+ </template>
6
+
7
+ <script lang="ts" setup>
8
+ defineProps<{
9
+ fullHeight?: boolean
10
+ }>()
11
+ </script>
12
+
13
+ <style lang="postcss" scoped>
14
+ .vts-tabular-key-value-list {
15
+ container-type: inline-size;
16
+ container-name: vts-tabular-key-value-list;
17
+ display: grid;
18
+ grid-template-columns: minmax(min-content, 20rem) 1fr;
19
+ row-gap: 1.6rem;
20
+ column-gap: 2.4rem;
21
+ align-items: start;
22
+ align-self: flex-start;
23
+ width: 100%;
24
+
25
+ &.full-height {
26
+ height: 100%;
27
+ }
28
+ }
29
+ </style>
@@ -0,0 +1,42 @@
1
+ <template>
2
+ <div class="vts-tabular-key-value-row">
3
+ <VtsKeyValuePair :label :value>
4
+ <template v-if="slots.label" #label>
5
+ <slot name="label" />
6
+ </template>
7
+ <template v-if="slots.value" #value>
8
+ <slot name="value" />
9
+ </template>
10
+ </VtsKeyValuePair>
11
+ </div>
12
+ </template>
13
+
14
+ <script lang="ts" setup>
15
+ import VtsKeyValuePair from '@core/components/key-value-pair/VtsKeyValuePair.vue'
16
+
17
+ defineProps<{
18
+ label?: string
19
+ value?: string
20
+ }>()
21
+
22
+ const slots = defineSlots<{
23
+ label?(): any
24
+ value?(): any
25
+ }>()
26
+ </script>
27
+
28
+ <style lang="postcss" scoped>
29
+ .vts-tabular-key-value-row {
30
+ display: grid;
31
+ grid-template-columns: subgrid;
32
+ grid-column: span 2;
33
+ align-items: start;
34
+
35
+ @container vts-tabular-key-value-list (max-width: 40rem) {
36
+ display: flex;
37
+ flex-direction: column;
38
+ align-items: stretch;
39
+ gap: 0.8rem;
40
+ }
41
+ }
42
+ </style>
@@ -99,6 +99,7 @@ import {
99
99
  faRoute,
100
100
  faSatellite,
101
101
  faServer,
102
+ faShieldHalved,
102
103
  faSliders,
103
104
  faSpinner,
104
105
  faSquare,
@@ -226,6 +227,7 @@ export const faIcons = defineIconPack({
226
227
  time: { icon: faClock },
227
228
  'thumb-tack': { icon: faThumbTack },
228
229
  'thumb-tack-slash': { icon: faThumbTackSlash },
230
+ 'traffic-rule': { icon: faShieldHalved },
229
231
  trash: { icon: faTrash },
230
232
  'triangle-exclamation': { icon: faTriangleExclamation },
231
233
  'up-right-and-down-left-from-center': { icon: faUpRightAndDownLeftFromCenter },
@@ -12,6 +12,7 @@ import {
12
12
  faClock,
13
13
  faDatabase,
14
14
  faDesktop,
15
+ faEthernet,
15
16
  faHdd,
16
17
  faNetworkWired,
17
18
  faPlay,
@@ -209,6 +210,7 @@ export const objectIcons = defineIconPack({
209
210
  'vdi:disabled': [constructIcon(faHdd), ...constructCircleStatus('disabled')],
210
211
  'vdi:warning': [constructIcon(faHdd), ...constructCircleStatus('warning-circle')],
211
212
  'vdi:detached': [constructIcon(faHdd), ...constructCircleStatus('danger-circle')],
213
+ vif: constructIcon(faEthernet),
212
214
  network: constructIcon(faNetworkWired),
213
215
  'network:unknown': [
214
216
  {