mirror of
https://github.com/vatesfr/xen-orchestra.git
synced 2026-09-10 22:14:48 -05:00
feat(xo6): update input version (#10009)
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<div class="inputs">
|
||||
<UiInput v-if="newFilter.isAdvanced" v-model="filterContent" accent="brand" class="advanced-input" />
|
||||
<template v-else>
|
||||
<VtsSelect :id="builderPropertySelectId" accent="brand" :icon="currentFilterIcon" />
|
||||
<VtsSelect :id="builderPropertySelectId" accent="brand" />
|
||||
<VtsSelect v-if="hasComparisonSelect" :id="builderComparisonSelectId" accent="brand" />
|
||||
<VtsSelect v-if="currentFilter?.type === 'enum'" :id="builderValueSelectId" accent="brand" />
|
||||
<UiInput v-else-if="hasValueInput" v-model="newFilter.builder.value" accent="brand" />
|
||||
@@ -20,7 +20,6 @@
|
||||
<script lang="ts" setup>
|
||||
import UiActionButton from '@/components/ui/UiActionButton.vue'
|
||||
import { buildComplexMatcherNode } from '@/libs/complex-matcher.utils'
|
||||
import { getFilterIcon } from '@/libs/utils'
|
||||
import type { Filter, FilterComparisons, FilterComparisonType, Filters, FilterType, NewFilter } from '@/types/filter'
|
||||
import VtsSelect from '@core/components/select/VtsSelect.vue'
|
||||
import UiInput from '@core/components/ui/input/UiInput.vue'
|
||||
@@ -104,8 +103,6 @@ function getDefaultComparisonType(property: string) {
|
||||
|
||||
const currentFilter = computed<Filter | undefined>(() => availableFilters[builderProperty.value])
|
||||
|
||||
const currentFilterIcon = computed(() => getFilterIcon(currentFilter.value))
|
||||
|
||||
const hasValueInput = computed(() =>
|
||||
currentFilter.value ? ['string', 'number'].includes(currentFilter.value?.type) : false
|
||||
)
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
<VtsKeyValueList>
|
||||
<VtsKeyValueRow>
|
||||
<template #label>
|
||||
<VtsSelect :id="localeSelectId" icon="fa:earth-americas" accent="brand" />
|
||||
<VtsSelect :id="localeSelectId" accent="brand" />
|
||||
</template>
|
||||
<template #value>
|
||||
<UiLink size="medium" href="https://translate.vates.tech/engage/xen-orchestra/">
|
||||
|
||||
@@ -6,13 +6,19 @@
|
||||
prop('accent').enum('brand', 'warning', 'danger').required().preset('brand').widget(),
|
||||
prop('id').str().widget(),
|
||||
prop('required').bool().widget(),
|
||||
prop('selected').bool().widget(),
|
||||
prop('readonly').bool().widget(),
|
||||
prop('type').enum('text', 'number', 'password', 'search').preset('text').widget(),
|
||||
prop('rightIcon').widget(
|
||||
choice({ label: 'Search', value: 'fa:magnifying-glass' }, { label: 'AngleDown', value: 'fa:angle-down' })
|
||||
),
|
||||
prop('clearable').bool().widget(),
|
||||
prop('disabled').bool().widget().help('Not defined as component prop'),
|
||||
slot('rightIcon').help('Can be used in place of rightIcon prop'),
|
||||
prop('prefix').str().widget(),
|
||||
prop('suffix').str().widget(),
|
||||
prop('disabled').bool().widget(),
|
||||
slot('right-icon').help('Can be used in place of rightIcon prop'),
|
||||
slot('prefix').help('Can be used in place of prefix prop'),
|
||||
slot('suffix').help('Can be used in place of suffix prop'),
|
||||
]"
|
||||
>
|
||||
<UiInput placeholder="Enter your search" v-bind="properties" />
|
||||
|
||||
@@ -51,10 +51,10 @@ const unsortedMessages = useArrayMap(
|
||||
})
|
||||
)
|
||||
|
||||
const messages = useRanked(unsortedMessages, ({ accent }) => accent, ['danger', 'warning', 'success', 'info'])
|
||||
const messages = useRanked(unsortedMessages, ({ accent }) => accent, ['muted', 'info', 'success', 'warning', 'danger'])
|
||||
|
||||
const labelAccent = useMapper<InfoAccent, LabelAccent>(
|
||||
() => messages.value[0]?.accent,
|
||||
() => messages.value.at(-1)?.accent,
|
||||
{
|
||||
info: 'neutral',
|
||||
success: 'neutral',
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
ref="triggerRef"
|
||||
:accent
|
||||
:disabled="isDisabled"
|
||||
:icon
|
||||
:model-value="selectedLabel"
|
||||
:placeholder
|
||||
:required="isRequired"
|
||||
@@ -47,7 +46,6 @@ import VtsOption from '@core/components/select/VtsOption.vue'
|
||||
import UiDropdown from '@core/components/ui/dropdown/UiDropdown.vue'
|
||||
import UiDropdownList from '@core/components/ui/dropdown/UiDropdownList.vue'
|
||||
import UiInput from '@core/components/ui/input/UiInput.vue'
|
||||
import type { IconName } from '@core/icons'
|
||||
import {
|
||||
type FormSelect,
|
||||
type FormSelectId,
|
||||
@@ -62,7 +60,6 @@ import { useI18n } from 'vue-i18n'
|
||||
const { accent, id } = defineProps<{
|
||||
accent: 'brand' | 'warning' | 'danger'
|
||||
id: TSelectId
|
||||
icon?: IconName
|
||||
}>()
|
||||
|
||||
defineSlots<{
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<!-- v5 -->
|
||||
<!-- v9 -->
|
||||
<template>
|
||||
<div :class="toVariants({ accent, disabled })" class="ui-input" @click.self="focus()">
|
||||
<div :class="toVariants({ accent, disabled, selected })" class="ui-input" @click.self="focus()">
|
||||
<span v-if="slots.prefix || prefix" class="prefix">
|
||||
<slot name="prefix">
|
||||
{{ prefix }}
|
||||
</slot>
|
||||
</span>
|
||||
<span v-if="readonly" class="typo-body-regular input text-ellipsis">
|
||||
<input ref="inputRef" class="readonly-input" readonly type="text" />
|
||||
{{ modelValue }}
|
||||
@@ -19,14 +24,19 @@
|
||||
/>
|
||||
<UiButtonIcon
|
||||
v-if="!disabled && modelValue && clearable"
|
||||
icon="fa:xmark"
|
||||
accent="brand"
|
||||
size="small"
|
||||
icon="action:close-cancel-clear"
|
||||
accent="brand"
|
||||
@click="clear()"
|
||||
/>
|
||||
<slot v-if="slots['right-icon'] || rightIcon" name="right-icon">
|
||||
<VtsIcon :name="rightIcon" size="medium" class="right-icon" />
|
||||
</slot>
|
||||
<span v-if="slots.suffix || suffix" class="suffix">
|
||||
<slot name="suffix">
|
||||
{{ suffix }}
|
||||
</slot>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -58,12 +68,14 @@ const {
|
||||
id?: string
|
||||
required?: boolean
|
||||
disabled?: boolean
|
||||
selected?: boolean
|
||||
readonly?: boolean
|
||||
detached?: boolean
|
||||
type?: InputType
|
||||
icon?: IconName
|
||||
rightIcon?: IconName
|
||||
clearable?: boolean
|
||||
prefix?: string
|
||||
suffix?: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -74,6 +86,8 @@ const modelValue = defineModel<string | number | undefined>({ required: true })
|
||||
|
||||
const slots = defineSlots<{
|
||||
'right-icon'?(): any
|
||||
prefix?(): any
|
||||
suffix?(): any
|
||||
}>()
|
||||
|
||||
function handleInput(event: Event) {
|
||||
@@ -135,6 +149,31 @@ defineExpose({ focus })
|
||||
color: var(--color-brand-txt-base);
|
||||
}
|
||||
|
||||
.prefix,
|
||||
.suffix {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
align-self: stretch;
|
||||
background-color: var(--color-neutral-background-secondary);
|
||||
padding: 0.8rem 1.6rem;
|
||||
color: var(--color-neutral-txt-secondary);
|
||||
}
|
||||
|
||||
.prefix {
|
||||
border-end-start-radius: 0.4rem;
|
||||
border-start-start-radius: 0.4rem;
|
||||
border-inline-end: 0.1rem solid var(--color-neutral-border);
|
||||
margin-inline-start: -1.6rem;
|
||||
}
|
||||
|
||||
.suffix {
|
||||
border-end-end-radius: 0.4rem;
|
||||
border-start-end-radius: 0.4rem;
|
||||
border-inline-start: 0.1rem solid var(--color-neutral-border);
|
||||
margin-inline-end: -1.6rem;
|
||||
}
|
||||
|
||||
&.disabled .right-icon {
|
||||
color: var(--color-neutral-txt-secondary);
|
||||
}
|
||||
@@ -163,12 +202,9 @@ defineExpose({ focus })
|
||||
/* VARIANT */
|
||||
|
||||
&.accent--brand {
|
||||
--selected-color: var(--color-brand-item-base);
|
||||
border-color: var(--color-neutral-border);
|
||||
|
||||
&:focus-within {
|
||||
border-color: var(--color-brand-item-base);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: var(--color-brand-item-hover);
|
||||
}
|
||||
@@ -184,6 +220,7 @@ defineExpose({ focus })
|
||||
}
|
||||
|
||||
&.accent--warning {
|
||||
--selected-color: var(--color-warning-item-base);
|
||||
border-color: var(--color-warning-item-base);
|
||||
|
||||
&:hover {
|
||||
@@ -201,6 +238,7 @@ defineExpose({ focus })
|
||||
}
|
||||
|
||||
&.accent--danger {
|
||||
--selected-color: var(--color-danger-item-base);
|
||||
border-color: var(--color-danger-item-base);
|
||||
|
||||
&:hover {
|
||||
@@ -216,5 +254,11 @@ defineExpose({ focus })
|
||||
background-color: var(--color-neutral-background-disabled);
|
||||
}
|
||||
}
|
||||
|
||||
&:focus-within,
|
||||
&.selected {
|
||||
border-color: var(--selected-color);
|
||||
border-width: 0.2rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
type="text"
|
||||
accent="brand"
|
||||
:aria-label="uiStore.isSmall ? t('query-search-bar:label') : undefined"
|
||||
:icon="!uiStore.isSmall ? 'fa:magnifying-glass' : undefined"
|
||||
:placeholder="t('query-search-bar:placeholder')"
|
||||
/>
|
||||
<template v-if="!uiStore.isSmall">
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
- [REST API] Expose `/rest/v0/acl-roles/:id/groups` (PR [#10085](https://github.com/vatesfr/xen-orchestra/pull/10085))
|
||||
- [XO6] Fix some design inconsistency between pages (PR [#10109](https://github.com/vatesfr/xen-orchestra/pull/10109))
|
||||
- [XO6/Users] Add Users Table (PR [#10029](https://github.com/vatesfr/xen-orchestra/pull/10029))
|
||||
- [XO6] Input fields now support prefix/suffix sections, and display validation messages ordered by severity (PR [#10009](https://github.com/vatesfr/xen-orchestra/pull/10009))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user