Skip to content

Commit 478e1b3

Browse files
authored
Merge pull request #47 from QuickFlo/docs-url-and-description-per-option
1.19.0
2 parents cc439b1 + 424689b commit 478e1b3

3 files changed

Lines changed: 84 additions & 19 deletions

File tree

packages/quasar/dev/App.vue

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ const formOptions: QuasarFormOptions = {
7676
},
7777
};
7878
79-
const formData = ref({connectionConfig: {provider: 'aws', connection: '', region: ''}});
79+
const formData = ref({
80+
connectionConfig: { provider: "aws", connection: "", region: "" },
81+
});
8082
8183
const schema: JSONSchema = {
8284
type: "object",
@@ -90,7 +92,8 @@ const schema: JSONSchema = {
9092
fieldOrderingDemo: {
9193
type: "object",
9294
title: "Field Ordering Demo (x-field-order)",
93-
description: "Fields sorted by numeric x-field-order: booleans (100), strings (200), numbers (300), enums (400), string arrays (500), object arrays (600), objects (700)",
95+
description:
96+
"Fields sorted by numeric x-field-order: booleans (100), strings (200), numbers (300), enums (400), string arrays (500), object arrays (600), objects (700)",
9497
properties: {
9598
// These fields are intentionally out of order in the schema,
9699
// but will render sorted by x-field-order
@@ -122,7 +125,11 @@ const schema: JSONSchema = {
122125
type: "object",
123126
properties: {
124127
name: { type: "string", title: "Name" },
125-
role: { type: "string", title: "Role", enum: ["Dev", "QA", "PM"] },
128+
role: {
129+
type: "string",
130+
title: "Role",
131+
enum: ["Dev", "QA", "PM"],
132+
},
126133
},
127134
},
128135
"x-item-label": "{{name}} - {{role}}",
@@ -348,6 +355,23 @@ const schema: JSONSchema = {
348355
dense: false,
349356
},
350357
},
358+
// === ENUM WITH DESCRIPTIONS ===
359+
outputDetail: {
360+
type: "string",
361+
enum: ["text", "segments", "full"],
362+
title: "Output Detail",
363+
description: "Level of detail in output",
364+
"x-enum-labels": {
365+
text: "Text",
366+
segments: "Segments",
367+
full: "Full",
368+
},
369+
"x-enum-descriptions": {
370+
text: "Only return speech text.",
371+
segments: "Speech segments with their start and end times.",
372+
full: "Includes text, speech segments, and VTT file. Useful for getting back diarized response.",
373+
},
374+
},
351375
tags: {
352376
type: "array",
353377
title: "Tags",
@@ -831,11 +855,13 @@ const schema: JSONSchema = {
831855
type: "array",
832856
title: "Report Objects",
833857
description: "Filter report results to specific objects",
834-
"x-hint": 'Include report objects to filter results. See <a href="https://example.com/docs">this article</a> for more information.',
858+
"x-hint":
859+
'Include report objects to filter results. See <a href="https://example.com/docs">this article</a> for more information.',
835860
items: {
836861
type: "object",
837862
title: "Report Object Criteria",
838-
"x-hint": "Each item defines filter criteria for a specific object type",
863+
"x-hint":
864+
"Each item defines filter criteria for a specific object type",
839865
properties: {
840866
objectNames: {
841867
type: "array",
@@ -1010,7 +1036,7 @@ const schema: JSONSchema = {
10101036
10111037
// === ONEOF WITH DESCRIPTIONS AND DOCS URLS (Discriminated Union style) ===
10121038
dateOperation: {
1013-
title: "",
1039+
title: "Date Operation",
10141040
description: "",
10151041
"x-oneof-style": "dropdown",
10161042
"x-oneof-select-label": "Operation",
@@ -1074,7 +1100,8 @@ const schema: JSONSchema = {
10741100
// Demonstrates x-oneof-docsUrls with tabs display and custom icon/tooltip
10751101
speechProvider: {
10761102
title: "Speech Provider (with Docs Links)",
1077-
description: "Select a TTS provider - note the docs icon next to the description",
1103+
description:
1104+
"Select a TTS provider - note the docs icon next to the description",
10781105
"x-oneof-style": "tabs",
10791106
"x-oneof-labels": {
10801107
openai: "OpenAI",
@@ -1111,7 +1138,11 @@ const schema: JSONSchema = {
11111138
properties: {
11121139
provider: { type: "string", const: "openai" },
11131140
apiKey: { type: "string", title: "API Key", format: "password" },
1114-
voice: { type: "string", title: "Voice", enum: ["alloy", "echo", "fable", "nova", "onyx", "shimmer"] },
1141+
voice: {
1142+
type: "string",
1143+
title: "Voice",
1144+
enum: ["alloy", "echo", "fable", "nova", "onyx", "shimmer"],
1145+
},
11151146
},
11161147
required: ["provider"],
11171148
},
@@ -1128,8 +1159,16 @@ const schema: JSONSchema = {
11281159
type: "object",
11291160
properties: {
11301161
provider: { type: "string", const: "google-cloud" },
1131-
credentials: { type: "string", title: "Service Account JSON", format: "textarea" },
1132-
languageCode: { type: "string", title: "Language", default: "en-US" },
1162+
credentials: {
1163+
type: "string",
1164+
title: "Service Account JSON",
1165+
format: "textarea",
1166+
},
1167+
languageCode: {
1168+
type: "string",
1169+
title: "Language",
1170+
default: "en-US",
1171+
},
11331172
},
11341173
required: ["provider"],
11351174
},

packages/quasar/src/components/QuasarEnumField.vue

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ const allOptions = computed(() => {
5050
| Record<string, string>
5151
| undefined;
5252
53+
// Support x-enum-descriptions for option descriptions
54+
const enumDescriptions = (props.schema as any)["x-enum-descriptions"] as
55+
| Record<string, string>
56+
| undefined;
57+
5358
return props.schema.enum.map((enumValue) => {
5459
let displayLabel = String(enumValue);
5560
@@ -58,15 +63,24 @@ const allOptions = computed(() => {
5863
displayLabel = enumLabels[enumValue];
5964
}
6065
66+
// Get description if provided
67+
const description = enumDescriptions?.[enumValue] ?? undefined;
68+
6169
return {
6270
label: displayLabel,
6371
value: enumValue,
72+
description,
6473
};
6574
});
6675
});
6776
77+
// Check if any options have descriptions
78+
const hasDescriptions = computed(() =>
79+
allOptions.value.some((opt) => opt.description)
80+
);
81+
6882
// Filtered options for autocomplete
69-
const filteredOptions = ref<Array<{ label: string; value: any }>>([]);
83+
const filteredOptions = ref<Array<{ label: string; value: any; description?: string }>>([]);
7084
7185
// Initialize and update filteredOptions when allOptions changes
7286
watch(
@@ -139,6 +153,16 @@ const filterFn = (val: string, update: (fn: () => void) => void) => {
139153
<template v-if="schema.required" #label>
140154
{{ label }} <span style="color: red">*</span>
141155
</template>
156+
<template v-if="hasDescriptions" #option="{ itemProps, opt }">
157+
<q-item v-bind="itemProps">
158+
<q-item-section>
159+
<q-item-label>{{ opt.label }}</q-item-label>
160+
<q-item-label v-if="opt.description" caption class="text-grey-7">
161+
{{ opt.description }}
162+
</q-item-label>
163+
</q-item-section>
164+
</q-item>
165+
</template>
142166
</QSelect>
143167
</div>
144168
</template>

packages/quasar/src/components/QuasarOneOfField.vue

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -461,21 +461,22 @@ const handleOptionChange = (newIndex: number) => {
461461
/>
462462
</QTabs>
463463

464-
<!-- Option description hint with optional docs link -->
464+
<!-- Option description hint with optional docs link (tabs mode) -->
465465
<div
466466
v-if="activeOptionDescription || activeOptionDocsUrl"
467-
style="font-size: 0.875rem; color: #666; margin-top: 0.5rem; display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;"
467+
class="text-caption text-grey-7"
468+
style="margin-top: 0.25rem;"
468469
>
469470
<span v-if="activeOptionDescription">{{ activeOptionDescription }}</span>
470471
<a
471472
v-if="activeOptionDocsUrl"
472473
:href="activeOptionDocsUrl"
473474
target="_blank"
474475
rel="noopener noreferrer"
475-
style="display: inline-flex; align-items: center; color: var(--q-primary, #1976d2); text-decoration: none;"
476+
style="margin-left: 0.5rem; display: inline-flex; align-items: center; color: var(--q-primary, #1976d2); text-decoration: none; vertical-align: middle;"
476477
@click.stop
477478
>
478-
<QIcon :name="activeOptionDocsIcon" size="16px" />
479+
<QIcon :name="activeOptionDocsIcon" size="14px" />
479480
<QTooltip>{{ activeOptionDocsTooltip }}</QTooltip>
480481
</a>
481482
</div>
@@ -529,21 +530,22 @@ const handleOptionChange = (newIndex: number) => {
529530
v-bind="quasarProps"
530531
/>
531532

532-
<!-- Option description hint with optional docs link -->
533+
<!-- Option description hint (always visible, outside QSelect) -->
533534
<div
534535
v-if="activeOptionDescription || activeOptionDocsUrl"
535-
style="font-size: 0.875rem; color: #666; margin-top: 0.75rem; display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;"
536+
class="text-caption text-grey-7"
537+
style="margin-top: 0.25rem; padding-left: 12px;"
536538
>
537539
<span v-if="activeOptionDescription">{{ activeOptionDescription }}</span>
538540
<a
539541
v-if="activeOptionDocsUrl"
540542
:href="activeOptionDocsUrl"
541543
target="_blank"
542544
rel="noopener noreferrer"
543-
style="display: inline-flex; align-items: center; color: var(--q-primary, #1976d2); text-decoration: none;"
545+
style="margin-left: 0.5rem; display: inline-flex; align-items: center; color: var(--q-primary, #1976d2); text-decoration: none; vertical-align: middle;"
544546
@click.stop
545547
>
546-
<QIcon :name="activeOptionDocsIcon" size="16px" />
548+
<QIcon :name="activeOptionDocsIcon" size="14px" />
547549
<QTooltip>{{ activeOptionDocsTooltip }}</QTooltip>
548550
</a>
549551
</div>

0 commit comments

Comments
 (0)