version-0.1 #1
@@ -319,6 +319,7 @@ interface Props {
|
|||||||
modelValue: boolean;
|
modelValue: boolean;
|
||||||
feature: FeatureResponse | null;
|
feature: FeatureResponse | null;
|
||||||
featureState: FeatureStateResponse | null;
|
featureState: FeatureStateResponse | null;
|
||||||
|
initialTab?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
const props = defineProps<Props>();
|
||||||
@@ -472,7 +473,7 @@ watch(
|
|||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
(open) => {
|
(open) => {
|
||||||
if (open) {
|
if (open) {
|
||||||
activeTab.value = 'value';
|
activeTab.value = props.initialTab ?? 'value';
|
||||||
valueErrorMessage.value = null;
|
valueErrorMessage.value = null;
|
||||||
settingsErrorMessage.value = null;
|
settingsErrorMessage.value = null;
|
||||||
segmentsErrorMessage.value = null;
|
segmentsErrorMessage.value = null;
|
||||||
|
|||||||
@@ -1,14 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<div data-testid="feature-value-editor">
|
<div data-testid="feature-value-editor">
|
||||||
<!-- Type selector -->
|
<!-- Type selector -->
|
||||||
<v-btn-toggle
|
<div class="d-flex mb-3" data-testid="value-mode-toggle">
|
||||||
v-model="detectedMode"
|
<v-btn
|
||||||
density="compact"
|
size="small"
|
||||||
data-testid="value-mode-toggle"
|
:variant="detectedMode === 'text' ? 'flat' : 'outlined'"
|
||||||
>
|
color="primary"
|
||||||
<v-btn value="text" size="small">Text</v-btn>
|
rounded="0"
|
||||||
<v-btn value="json" size="small">JSON</v-btn>
|
style="border-radius: 4px 0 0 4px"
|
||||||
</v-btn-toggle>
|
@click="detectedMode = 'text'"
|
||||||
|
>Text</v-btn>
|
||||||
|
<v-btn
|
||||||
|
size="small"
|
||||||
|
:variant="detectedMode === 'json' ? 'flat' : 'outlined'"
|
||||||
|
color="primary"
|
||||||
|
rounded="0"
|
||||||
|
style="border-radius: 0 4px 4px 0; margin-left: -1px"
|
||||||
|
@click="detectedMode = 'json'"
|
||||||
|
>JSON</v-btn>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- JSON mode -->
|
<!-- JSON mode -->
|
||||||
<v-textarea
|
<v-textarea
|
||||||
@@ -83,11 +93,3 @@ const rules = {
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
/* Materio forces square icon-toggle sizing; override for text-label toggles */
|
|
||||||
:deep(.v-btn-toggle .v-btn) {
|
|
||||||
block-size: auto !important;
|
|
||||||
inline-size: auto !important;
|
|
||||||
padding-inline: 16px !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -3,18 +3,26 @@
|
|||||||
<!-- AND / OR toggle -->
|
<!-- AND / OR toggle -->
|
||||||
<div class="d-flex align-center ga-2 mb-3">
|
<div class="d-flex align-center ga-2 mb-3">
|
||||||
<span class="text-body-2 font-weight-medium text-medium-emphasis">Match</span>
|
<span class="text-body-2 font-weight-medium text-medium-emphasis">Match</span>
|
||||||
<v-btn-toggle
|
<div class="d-flex" data-testid="rule-type-toggle">
|
||||||
:model-value="rule.type"
|
<v-btn
|
||||||
density="compact"
|
size="small"
|
||||||
mandatory
|
:variant="rule.type === 'All' ? 'flat' : 'outlined'"
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="outlined"
|
rounded="0"
|
||||||
data-testid="rule-type-toggle"
|
style="border-radius: 4px 0 0 4px"
|
||||||
@update:model-value="onTypeChange"
|
data-testid="rule-type-and"
|
||||||
>
|
@click="onTypeChange('All')"
|
||||||
<v-btn value="All" size="small" data-testid="rule-type-and">ALL (AND)</v-btn>
|
>ALL (AND)</v-btn>
|
||||||
<v-btn value="Any" size="small" data-testid="rule-type-or">ANY (OR)</v-btn>
|
<v-btn
|
||||||
</v-btn-toggle>
|
size="small"
|
||||||
|
:variant="rule.type === 'Any' ? 'flat' : 'outlined'"
|
||||||
|
color="primary"
|
||||||
|
rounded="0"
|
||||||
|
style="border-radius: 0 4px 4px 0; margin-left: -1px"
|
||||||
|
data-testid="rule-type-or"
|
||||||
|
@click="onTypeChange('Any')"
|
||||||
|
>ANY (OR)</v-btn>
|
||||||
|
</div>
|
||||||
<v-spacer />
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
v-if="removable"
|
v-if="removable"
|
||||||
|
|||||||
@@ -53,7 +53,26 @@
|
|||||||
<!-- Name + description -->
|
<!-- Name + description -->
|
||||||
<template #item.name="{ item }: { item: FeatureResponse }">
|
<template #item.name="{ item }: { item: FeatureResponse }">
|
||||||
<div>
|
<div>
|
||||||
<span class="text-body-2 font-weight-medium">{{ item.name }}</span>
|
<div class="d-flex align-center ga-1">
|
||||||
|
<span class="text-subtitle-1 font-weight-bold">{{ item.name }}</span>
|
||||||
|
<v-tooltip
|
||||||
|
v-if="(featureSegmentsMap.get(item.id) ?? []).length > 0"
|
||||||
|
text="Has segment overrides"
|
||||||
|
location="top"
|
||||||
|
>
|
||||||
|
<template #activator="{ props: tooltipProps }">
|
||||||
|
<v-btn
|
||||||
|
v-bind="tooltipProps"
|
||||||
|
icon="ri-donut-chart-fill"
|
||||||
|
size="small"
|
||||||
|
variant="text"
|
||||||
|
color="secondary"
|
||||||
|
:data-testid="`segment-override-icon-${item.id}`"
|
||||||
|
@click.stop="openDetailOnSegments(item)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</v-tooltip>
|
||||||
|
</div>
|
||||||
<p v-if="item.description" class="text-caption text-medium-emphasis mb-0">
|
<p v-if="item.description" class="text-caption text-medium-emphasis mb-0">
|
||||||
{{ item.description }}
|
{{ item.description }}
|
||||||
</p>
|
</p>
|
||||||
@@ -158,6 +177,7 @@
|
|||||||
v-model="showDetail"
|
v-model="showDetail"
|
||||||
:feature="selectedFeature"
|
:feature="selectedFeature"
|
||||||
:feature-state="selectedFeatureState"
|
:feature-state="selectedFeatureState"
|
||||||
|
:initial-tab="detailInitialTab"
|
||||||
@updated="onFeatureUpdated"
|
@updated="onFeatureUpdated"
|
||||||
@deleted="onFeatureDeleted"
|
@deleted="onFeatureDeleted"
|
||||||
@state-updated="onStateUpdated"
|
@state-updated="onStateUpdated"
|
||||||
@@ -236,6 +256,7 @@ function showError(message: string): void {
|
|||||||
const showDialog = ref(false);
|
const showDialog = ref(false);
|
||||||
const showDetail = ref(false);
|
const showDetail = ref(false);
|
||||||
const selectedFeature = ref<FeatureResponse | null>(null);
|
const selectedFeature = ref<FeatureResponse | null>(null);
|
||||||
|
const detailInitialTab = ref('value');
|
||||||
|
|
||||||
// Delete dialog state
|
// Delete dialog state
|
||||||
const showDeleteDialog = ref(false);
|
const showDeleteDialog = ref(false);
|
||||||
@@ -333,6 +354,13 @@ function openCreateDialog(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onRowClick(_event: Event, { item }: { item: FeatureResponse }): void {
|
function onRowClick(_event: Event, { item }: { item: FeatureResponse }): void {
|
||||||
|
detailInitialTab.value = 'value';
|
||||||
|
selectedFeature.value = item;
|
||||||
|
showDetail.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function openDetailOnSegments(item: FeatureResponse): void {
|
||||||
|
detailInitialTab.value = 'segments';
|
||||||
selectedFeature.value = item;
|
selectedFeature.value = item;
|
||||||
showDetail.value = true;
|
showDetail.value = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user