feat(lite/components): rework of CollectionFilterRow to be i18n-able (#6619)
This commit is contained in:
committed by
GitHub
parent
1f6e29084f
commit
4beb49041d
@@ -19,74 +19,59 @@
|
||||
</option>
|
||||
</select>
|
||||
</FormWidget>
|
||||
<template v-if="hasComparisonSelect">
|
||||
<FormWidget v-if="currentFilter?.type === 'string'">
|
||||
<select v-model="newFilter.builder.negate">
|
||||
<option :value="false">does</option>
|
||||
<option :value="true">does not</option>
|
||||
</select>
|
||||
</FormWidget>
|
||||
<FormWidget v-if="hasComparisonSelect">
|
||||
<select v-model="newFilter.builder.comparison">
|
||||
<option
|
||||
v-for="(label, type) in comparisons"
|
||||
:key="type"
|
||||
:value="type"
|
||||
>
|
||||
{{ label }}
|
||||
</option>
|
||||
</select>
|
||||
</FormWidget>
|
||||
</template>
|
||||
<FormWidget v-if="hasComparisonSelect">
|
||||
<select v-model="newFilter.builder.comparison">
|
||||
<option
|
||||
v-for="(label, type) in comparisons"
|
||||
:key="type"
|
||||
:value="type"
|
||||
>
|
||||
{{ label }}
|
||||
</option>
|
||||
</select>
|
||||
</FormWidget>
|
||||
<FormWidget v-if="currentFilter?.type === 'enum'">
|
||||
<select v-model="newFilter.builder.value">
|
||||
<option v-if="!newFilter.builder.value" value="" />
|
||||
<option v-for="choice in enumChoices" :key="choice" :value="choice">
|
||||
{{ choice }}
|
||||
</option>
|
||||
</select>
|
||||
</FormWidget>
|
||||
<FormWidget
|
||||
v-if="hasValueInput"
|
||||
v-else-if="hasValueInput"
|
||||
:after="valueInputAfter"
|
||||
:before="valueInputBefore"
|
||||
>
|
||||
<input v-model="newFilter.builder.value" />
|
||||
</FormWidget>
|
||||
<template v-else-if="currentFilter?.type === 'enum'">
|
||||
<FormWidget>
|
||||
<select v-model="newFilter.builder.negate">
|
||||
<option :value="false">is</option>
|
||||
<option :value="true">is not</option>
|
||||
</select>
|
||||
</FormWidget>
|
||||
<FormWidget>
|
||||
<select v-model="newFilter.builder.value">
|
||||
<option v-if="!newFilter.builder.value" value="" />
|
||||
<option v-for="choice in enumChoices" :key="choice" :value="choice">
|
||||
{{ choice }}
|
||||
</option>
|
||||
</select>
|
||||
</FormWidget>
|
||||
</template>
|
||||
</template>
|
||||
<UiActionButton
|
||||
v-if="!newFilter.isAdvanced"
|
||||
@click="enableAdvancedMode"
|
||||
:icon="faPencil"
|
||||
@click="enableAdvancedMode"
|
||||
/>
|
||||
<UiActionButton @click="emit('remove', newFilter.id)" :icon="faRemove" />
|
||||
<UiActionButton :icon="faRemove" @click="emit('remove', newFilter.id)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from "vue";
|
||||
import type {
|
||||
Filter,
|
||||
FilterComparisonType,
|
||||
FilterComparisons,
|
||||
FilterType,
|
||||
Filters,
|
||||
NewFilter,
|
||||
} from "@/types/filter";
|
||||
import { faPencil, faRemove } from "@fortawesome/free-solid-svg-icons";
|
||||
import { useVModel } from "@vueuse/core";
|
||||
import FormWidget from "@/components/FormWidget.vue";
|
||||
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 { faPencil, faRemove } from "@fortawesome/free-solid-svg-icons";
|
||||
import { useVModel } from "@vueuse/core";
|
||||
import { computed, type Ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const props = defineProps<{
|
||||
availableFilters: Filters;
|
||||
@@ -98,14 +83,16 @@ const emit = defineEmits<{
|
||||
(event: "remove", filterId: number): void;
|
||||
}>();
|
||||
|
||||
const newFilter = useVModel(props, "modelValue", emit);
|
||||
const { t } = useI18n();
|
||||
|
||||
const newFilter: Ref<NewFilter> = useVModel(props, "modelValue", emit);
|
||||
|
||||
const getDefaultComparisonType = () => {
|
||||
const defaultTypes: { [key in FilterType]: FilterComparisonType } = {
|
||||
string: "stringContains",
|
||||
boolean: "booleanTrue",
|
||||
number: "numberEquals",
|
||||
enum: "stringEquals",
|
||||
enum: "enumIs",
|
||||
};
|
||||
|
||||
return defaultTypes[
|
||||
@@ -118,7 +105,6 @@ watch(
|
||||
() => {
|
||||
newFilter.value.builder.comparison = getDefaultComparisonType();
|
||||
newFilter.value.builder.value = "";
|
||||
newFilter.value.builder.negate = false;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -133,7 +119,7 @@ const hasValueInput = computed(() =>
|
||||
);
|
||||
|
||||
const hasComparisonSelect = computed(
|
||||
() => newFilter.value.builder.property && currentFilter.value?.type !== "enum"
|
||||
() => newFilter.value.builder.property !== ""
|
||||
);
|
||||
|
||||
const enumChoices = computed(() => {
|
||||
@@ -164,8 +150,7 @@ const generatedFilter = computed(() => {
|
||||
const node = buildComplexMatcherNode(
|
||||
newFilter.value.builder.comparison,
|
||||
newFilter.value.builder.property,
|
||||
newFilter.value.builder.value,
|
||||
newFilter.value.builder.negate
|
||||
newFilter.value.builder.value
|
||||
);
|
||||
|
||||
if (node) {
|
||||
@@ -190,15 +175,20 @@ watch(generatedFilter, (value) => {
|
||||
const comparisons = computed<FilterComparisons>(() => {
|
||||
const comparisonsByType = {
|
||||
string: {
|
||||
stringContains: "contain",
|
||||
stringEquals: "equal",
|
||||
stringStartsWith: "start with",
|
||||
stringEndsWith: "end with",
|
||||
stringMatchesRegex: "match regex",
|
||||
stringContains: t("filter.comparison.contains"),
|
||||
stringEquals: t("filter.comparison.equals"),
|
||||
stringStartsWith: t("filter.comparison.starts-with"),
|
||||
stringEndsWith: t("filter.comparison.ends-with"),
|
||||
stringMatchesRegex: t("filter.comparison.matches-regex"),
|
||||
stringDoesNotContain: t("filter.comparison.not-contain"),
|
||||
stringDoesNotEqual: t("filter.comparison.not-equal"),
|
||||
stringDoesNotStartWith: t("filter.comparison.not-start-with"),
|
||||
stringDoesNotEndWith: t("filter.comparison.not-end-with"),
|
||||
stringDoesNotMatchRegex: t("filter.comparison.not-match-regex"),
|
||||
},
|
||||
boolean: {
|
||||
booleanTrue: "is true",
|
||||
booleanFalse: "is false",
|
||||
booleanTrue: t("filter.comparison.is-true"),
|
||||
booleanFalse: t("filter.comparison.is-false"),
|
||||
},
|
||||
number: {
|
||||
numberLessThan: "<",
|
||||
@@ -207,23 +197,22 @@ const comparisons = computed<FilterComparisons>(() => {
|
||||
numberGreaterThanOrEquals: ">=",
|
||||
numberGreaterThan: ">",
|
||||
},
|
||||
enum: {},
|
||||
enum: {
|
||||
enumIs: t("filter.comparison.is"),
|
||||
enumIsNot: t("filter.comparison.is-not"),
|
||||
},
|
||||
};
|
||||
|
||||
return comparisonsByType[currentFilter.value.type];
|
||||
});
|
||||
|
||||
const valueInputBefore = computed(() => {
|
||||
return newFilter.value.builder.comparison === "stringMatchesRegex"
|
||||
? "/"
|
||||
: undefined;
|
||||
});
|
||||
const valueInputBefore = computed(() =>
|
||||
newFilter.value.builder.comparison === "stringMatchesRegex" ? "/" : undefined
|
||||
);
|
||||
|
||||
const valueInputAfter = computed(() => {
|
||||
return newFilter.value.builder.comparison === "stringMatchesRegex"
|
||||
? "/i"
|
||||
: undefined;
|
||||
});
|
||||
const valueInputAfter = computed(() =>
|
||||
newFilter.value.builder.comparison === "stringMatchesRegex" ? "/i" : undefined
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { escapeRegExp } from "@/libs/utils";
|
||||
import type { FilterComparisonType } from "@/types/filter";
|
||||
import type { ComparisonOperator, ComplexMatcherNode } from "complex-matcher";
|
||||
import * as CM from "complex-matcher";
|
||||
import type { FilterComparisonType } from "@/types/filter";
|
||||
import { escapeRegExp } from "@/libs/utils";
|
||||
|
||||
function buildStringNode(property: string, value: string, negate = false) {
|
||||
if (!value) {
|
||||
@@ -81,20 +81,63 @@ function buildBooleanNode(property: string, value: boolean) {
|
||||
export function buildComplexMatcherNode(
|
||||
comparisonType: FilterComparisonType,
|
||||
property: string,
|
||||
value: string,
|
||||
negate: boolean
|
||||
value: string
|
||||
): ComplexMatcherNode | undefined {
|
||||
switch (comparisonType) {
|
||||
case "stringContains":
|
||||
return buildStringNode(property, value, negate);
|
||||
case "stringDoesNotContains":
|
||||
return buildStringNode(
|
||||
property,
|
||||
value,
|
||||
comparisonType === "stringDoesNotContains"
|
||||
);
|
||||
|
||||
case "stringStartsWith":
|
||||
return buildRegexNode(property, value, "^", "", true, negate);
|
||||
case "stringDoesNotStartWith":
|
||||
return buildRegexNode(
|
||||
property,
|
||||
value,
|
||||
"^",
|
||||
"",
|
||||
true,
|
||||
comparisonType === "stringDoesNotStartWith"
|
||||
);
|
||||
|
||||
case "stringEndsWith":
|
||||
return buildRegexNode(property, value, "", "$", true, negate);
|
||||
case "stringDoesNotEndWith":
|
||||
return buildRegexNode(
|
||||
property,
|
||||
value,
|
||||
"",
|
||||
"$",
|
||||
true,
|
||||
comparisonType === "stringDoesNotEndWith"
|
||||
);
|
||||
|
||||
case "stringEquals":
|
||||
return buildRegexNode(property, value, "^", "$", true, negate);
|
||||
case "stringDoesNotEqual":
|
||||
case "enumIs":
|
||||
case "enumIsNot":
|
||||
return buildRegexNode(
|
||||
property,
|
||||
value,
|
||||
"^",
|
||||
"$",
|
||||
true,
|
||||
["stringDoesNotEqual", "enumIsNot"].includes(comparisonType)
|
||||
);
|
||||
|
||||
case "stringMatchesRegex":
|
||||
return buildRegexNode(property, value, "", "", false, negate);
|
||||
case "stringDoesNotMatchRegex":
|
||||
return buildRegexNode(
|
||||
property,
|
||||
value,
|
||||
"",
|
||||
"",
|
||||
false,
|
||||
comparisonType === "stringDoesNotMatchRegex"
|
||||
);
|
||||
|
||||
case "numberLessThan":
|
||||
return buildNumberComparisonNode(property, value, "<");
|
||||
case "numberLessThanOrEquals":
|
||||
|
||||
@@ -22,11 +22,30 @@
|
||||
"dashboard": "Dashboard",
|
||||
"delete": "Delete",
|
||||
"descending": "descending",
|
||||
"description": "Description",
|
||||
"edit-config": "Edit config",
|
||||
"error-occured": "An error has occurred",
|
||||
"export": "Export",
|
||||
"export-table-to": "Export table to {type}",
|
||||
"export-vms": "Export VMs",
|
||||
"filter": {
|
||||
"comparison": {
|
||||
"contains": "Contains",
|
||||
"ends-with": "Ends with",
|
||||
"equals": "Equals",
|
||||
"is": "Is",
|
||||
"is-false": "Is false",
|
||||
"is-not": "Is not",
|
||||
"is-true": "Is true",
|
||||
"matches-regex": "Matches regex",
|
||||
"not-contain": "Doesn't contain",
|
||||
"not-end-with": "Doesn't end with",
|
||||
"not-equal": "Doesn't equal",
|
||||
"not-match-regex": "Doesn't match regex",
|
||||
"not-start-with": "Doesn't start with",
|
||||
"starts-with": "Starts with"
|
||||
}
|
||||
},
|
||||
"following-hosts-unreachable": "The following hosts are unreachable",
|
||||
"force-reboot": "Force reboot",
|
||||
"force-shutdown": "Force shutdown",
|
||||
@@ -53,6 +72,7 @@
|
||||
"pause": "Pause",
|
||||
"pool-cpu-usage": "Pool CPU Usage",
|
||||
"pool-ram-usage": "Pool RAM Usage",
|
||||
"power-state": "Power state",
|
||||
"property": "Property",
|
||||
"ram-usage": "RAM usage",
|
||||
"reboot": "Reboot",
|
||||
|
||||
@@ -22,11 +22,30 @@
|
||||
"dashboard": "Tableau de bord",
|
||||
"delete": "Supprimer",
|
||||
"descending": "descendant",
|
||||
"description": "Description",
|
||||
"edit-config": "Modifier config",
|
||||
"error-occured": "Une erreur est survenue",
|
||||
"export": "Exporter",
|
||||
"export-table-to": "Exporter le tableau en {type}",
|
||||
"export-vms": "Exporter les VMs",
|
||||
"filter": {
|
||||
"comparison": {
|
||||
"contains": "Contient",
|
||||
"ends-with": "Termine par",
|
||||
"equals": "Est égal à",
|
||||
"is": "Est",
|
||||
"is-false": "Est faux",
|
||||
"is-not": "N'est pas",
|
||||
"is-true": "Est vrai",
|
||||
"matches-regex": "Correspond à la regex",
|
||||
"not-contain": "Ne contient pas",
|
||||
"not-end-with": "Ne termine pas par",
|
||||
"not-equal": "N'est pas égal à",
|
||||
"not-match-regex": "Ne correspond pas à la regex",
|
||||
"not-start-with": "Ne commence pas par",
|
||||
"starts-with": "Commence par"
|
||||
}
|
||||
},
|
||||
"following-hosts-unreachable": "Les hôtes suivants sont inaccessibles",
|
||||
"force-reboot": "Forcer le redémarrage",
|
||||
"force-shutdown": "Forcer l'arrêt",
|
||||
@@ -53,6 +72,7 @@
|
||||
"pause": "Pause",
|
||||
"pool-cpu-usage": "Utilisation CPU du Pool",
|
||||
"pool-ram-usage": "Utilisation RAM du Pool",
|
||||
"power-state": "État d'alimentation",
|
||||
"property": "Propriété",
|
||||
"ram-usage": "Utilisation de la RAM",
|
||||
"reboot": "Redémarrer",
|
||||
|
||||
@@ -4,17 +4,24 @@ export type FilterType = "string" | "boolean" | "number" | "enum";
|
||||
|
||||
export type FilterComparisonType =
|
||||
| "stringContains"
|
||||
| "stringDoesNotContains"
|
||||
| "stringEquals"
|
||||
| "stringDoesNotEqual"
|
||||
| "stringStartsWith"
|
||||
| "stringDoesNotStartWith"
|
||||
| "stringEndsWith"
|
||||
| "stringDoesNotEndWith"
|
||||
| "stringMatchesRegex"
|
||||
| "stringDoesNotMatchRegex"
|
||||
| "numberLessThan"
|
||||
| "numberLessThanOrEquals"
|
||||
| "numberEquals"
|
||||
| "numberGreaterThanOrEquals"
|
||||
| "numberGreaterThan"
|
||||
| "booleanTrue"
|
||||
| "booleanFalse";
|
||||
| "booleanFalse"
|
||||
| "enumIs"
|
||||
| "enumIsNot";
|
||||
|
||||
export type FilterComparisons = {
|
||||
[key in FilterComparisonType]?: string;
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
>
|
||||
<template #header>
|
||||
<ColumnHeader :icon="faPowerOff" />
|
||||
<ColumnHeader>Name</ColumnHeader>
|
||||
<ColumnHeader>Description</ColumnHeader>
|
||||
<ColumnHeader>{{ $t("name") }}</ColumnHeader>
|
||||
<ColumnHeader>{{ $t("description") }}</ColumnHeader>
|
||||
</template>
|
||||
<template #row="{ item: vm }">
|
||||
<td>
|
||||
@@ -43,18 +43,20 @@ import type { Filters } from "@/types/filter";
|
||||
import { faPowerOff } from "@fortawesome/free-solid-svg-icons";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { allRecords: vms } = storeToRefs(useVmStore());
|
||||
const { isMobile, isDesktop } = storeToRefs(useUiStore());
|
||||
const { t } = useI18n();
|
||||
|
||||
const filters: Filters = {
|
||||
name_label: { label: "VM Name", type: "string" },
|
||||
name_description: { label: "VM Description", type: "string" },
|
||||
name_label: { label: t("name"), type: "string" },
|
||||
name_description: { label: t("description"), type: "string" },
|
||||
power_state: {
|
||||
label: "VM State",
|
||||
label: t("power-state"),
|
||||
icon: faPowerOff,
|
||||
type: "enum",
|
||||
choices: ["Running", "Halted", "Paused"],
|
||||
choices: ["Running", "Halted", "Paused", "Suspended"],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user