version-0.1 #1
@@ -319,6 +319,7 @@ interface Props {
|
||||
modelValue: boolean;
|
||||
feature: FeatureResponse | null;
|
||||
featureState: FeatureStateResponse | null;
|
||||
initialTab?: string;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
@@ -472,7 +473,7 @@ watch(
|
||||
() => props.modelValue,
|
||||
(open) => {
|
||||
if (open) {
|
||||
activeTab.value = 'value';
|
||||
activeTab.value = props.initialTab ?? 'value';
|
||||
valueErrorMessage.value = null;
|
||||
settingsErrorMessage.value = null;
|
||||
segmentsErrorMessage.value = null;
|
||||
|
||||
@@ -1,14 +1,24 @@
|
||||
<template>
|
||||
<div data-testid="feature-value-editor">
|
||||
<!-- Type selector -->
|
||||
<v-btn-toggle
|
||||
v-model="detectedMode"
|
||||
density="compact"
|
||||
data-testid="value-mode-toggle"
|
||||
>
|
||||
<v-btn value="text" size="small">Text</v-btn>
|
||||
<v-btn value="json" size="small">JSON</v-btn>
|
||||
</v-btn-toggle>
|
||||
<div class="d-flex mb-3" data-testid="value-mode-toggle">
|
||||
<v-btn
|
||||
size="small"
|
||||
:variant="detectedMode === 'text' ? 'flat' : 'outlined'"
|
||||
color="primary"
|
||||
rounded="0"
|
||||
style="border-radius: 4px 0 0 4px"
|
||||
@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 -->
|
||||
<v-textarea
|
||||
@@ -83,11 +93,3 @@ const rules = {
|
||||
};
|
||||
</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 -->
|
||||
<div class="d-flex align-center ga-2 mb-3">
|
||||
<span class="text-body-2 font-weight-medium text-medium-emphasis">Match</span>
|
||||
<v-btn-toggle
|
||||
:model-value="rule.type"
|
||||
density="compact"
|
||||
mandatory
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
data-testid="rule-type-toggle"
|
||||
@update:model-value="onTypeChange"
|
||||
>
|
||||
<v-btn value="All" size="small" data-testid="rule-type-and">ALL (AND)</v-btn>
|
||||
<v-btn value="Any" size="small" data-testid="rule-type-or">ANY (OR)</v-btn>
|
||||
</v-btn-toggle>
|
||||
<div class="d-flex" data-testid="rule-type-toggle">
|
||||
<v-btn
|
||||
size="small"
|
||||
:variant="rule.type === 'All' ? 'flat' : 'outlined'"
|
||||
color="primary"
|
||||
rounded="0"
|
||||
style="border-radius: 4px 0 0 4px"
|
||||
data-testid="rule-type-and"
|
||||
@click="onTypeChange('All')"
|
||||
>ALL (AND)</v-btn>
|
||||
<v-btn
|
||||
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-btn
|
||||
v-if="removable"
|
||||
|
||||
@@ -53,7 +53,26 @@
|
||||
<!-- Name + description -->
|
||||
<template #item.name="{ item }: { item: FeatureResponse }">
|
||||
<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">
|
||||
{{ item.description }}
|
||||
</p>
|
||||
@@ -158,6 +177,7 @@
|
||||
v-model="showDetail"
|
||||
:feature="selectedFeature"
|
||||
:feature-state="selectedFeatureState"
|
||||
:initial-tab="detailInitialTab"
|
||||
@updated="onFeatureUpdated"
|
||||
@deleted="onFeatureDeleted"
|
||||
@state-updated="onStateUpdated"
|
||||
@@ -236,6 +256,7 @@ function showError(message: string): void {
|
||||
const showDialog = ref(false);
|
||||
const showDetail = ref(false);
|
||||
const selectedFeature = ref<FeatureResponse | null>(null);
|
||||
const detailInitialTab = ref('value');
|
||||
|
||||
// Delete dialog state
|
||||
const showDeleteDialog = ref(false);
|
||||
@@ -333,6 +354,13 @@ function openCreateDialog(): 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;
|
||||
showDetail.value = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user