Skip to content

Commit dc6081b

Browse files
Devesh0129github-code-quality[bot]Logende
authored
669 reference helping feature (#971)
* add autocomplete support for schema references - GUI View * apply formatting changes * updated autoref only for schemamode * apply formatting changes * Potential fix for pull request finding 'Unused variable, import, function or class' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> * Reference Autocomplete working when selected with mouse * if ref - External value and when cleared it still shows the internal ref * apply formatting changes * Dialog box open twice issue resolved * remove unused import --------- Co-authored-by: Devesh0129 <Devesh0129@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> Co-authored-by: Felix Neubauer <felix@neuby.de>
1 parent 58f2df9 commit dc6081b

4 files changed

Lines changed: 133 additions & 3 deletions

File tree

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<script setup lang="ts">
2+
import {ref, watch, nextTick} from 'vue';
3+
import AutoComplete from 'primevue/autocomplete';
4+
import type {PathElement} from '@/utility/path';
5+
import type {ValidationResult} from '@/schema/validationUtils';
6+
import {JsonSchemaWrapper} from '@/schema/jsonSchemaWrapper';
7+
import {isReadOnly} from '@/components/panels/gui-editor/configTreeNodeReadingUtils';
8+
import {getDataForMode} from '@/data/useDataLink';
9+
import {useSettings} from '@/settings/useSettings';
10+
import type {SessionMode} from '@/store/sessionMode';
11+
import {SessionMode as SessionModeEnum} from '@/store/sessionMode';
12+
import {getAvailableDefinitionPaths} from '@/schema/schemaReadingUtils';
13+
14+
const props = defineProps<{
15+
propertyName: PathElement;
16+
propertyData: string | undefined;
17+
propertySchema: JsonSchemaWrapper;
18+
validationResults: ValidationResult;
19+
sessionMode: SessionMode;
20+
}>();
21+
22+
const settings = useSettings();
23+
24+
const emit = defineEmits<{
25+
(e: 'update:propertyData', newValue: string | undefined): void;
26+
}>();
27+
28+
const currentValue = ref(props.propertyData ?? '');
29+
const filteredSuggestions = ref<string[]>([]);
30+
const autoCompleteRef = ref();
31+
32+
watch(
33+
() => props.propertyData,
34+
newVal => {
35+
currentValue.value = newVal ?? '';
36+
}
37+
);
38+
39+
function getDefinitions() {
40+
const userSchemaData = getDataForMode(SessionModeEnum.SchemaEditor).data.value;
41+
return getAvailableDefinitionPaths(userSchemaData);
42+
}
43+
44+
function onFocus() {
45+
filteredSuggestions.value = getDefinitions();
46+
nextTick(() => autoCompleteRef.value?.show());
47+
}
48+
49+
function onInput(event: Event) {
50+
const val = (event.target as HTMLInputElement).value;
51+
currentValue.value = val;
52+
const query = val.toLowerCase();
53+
filteredSuggestions.value =
54+
query === '' ? getDefinitions() : getDefinitions().filter(p => p.toLowerCase().includes(query));
55+
}
56+
57+
function searchSuggestions(event: {query: string}) {
58+
const query = event.query.toLowerCase();
59+
filteredSuggestions.value =
60+
query === '' ? getDefinitions() : getDefinitions().filter(p => p.toLowerCase().includes(query));
61+
}
62+
63+
function onItemSelect(event: {value: string}) {
64+
currentValue.value = event.value;
65+
emit('update:propertyData', event.value);
66+
nextTick(() => autoCompleteRef.value?.hide());
67+
}
68+
69+
function onBlur() {
70+
emit('update:propertyData', currentValue.value || undefined);
71+
}
72+
</script>
73+
74+
<template>
75+
<AutoComplete
76+
ref="autoCompleteRef"
77+
class="tableInput w-full"
78+
:class="{'underline decoration-wavy decoration-red-600': !props.validationResults.valid}"
79+
v-model="currentValue"
80+
:suggestions="filteredSuggestions"
81+
:editable="true"
82+
:disabled="isReadOnly(props.propertySchema)"
83+
:input-style="{width: '100%'}"
84+
:min-length="0"
85+
placeholder="#/$defs/MyType or external URL"
86+
@complete="searchSuggestions"
87+
@focus="onFocus"
88+
@input="onInput"
89+
@item-select="onItemSelect"
90+
@blur="onBlur"
91+
@keyup.enter="emit('update:propertyData', currentValue || undefined)"
92+
@keydown.down.stop
93+
@keydown.up.stop
94+
@keydown.left.stop
95+
@keydown.right.stop>
96+
<template #option="{option}">
97+
<div @mousedown.prevent="onItemSelect({value: option})">
98+
{{ option }}
99+
</div>
100+
</template>
101+
</AutoComplete>
102+
</template>
103+
104+
<style scoped>
105+
.tableInput {
106+
border: v-bind("settings.guiEditor.showBorderAroundInputFields ? '1px solid #d1d5db' : 'none'");
107+
box-shadow: none;
108+
}
109+
</style>

meta_configurator/src/components/panels/gui-editor/resolveCorrespondingComponent.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {getDataForMode, getSessionForMode, getValidationForMode} from '@/data/us
1717
import {typeSchema} from '@/schema/schemaProcessingUtils';
1818
import type {SessionMode} from '@/store/sessionMode';
1919
import OntologyUriProperty from '@/components/panels/gui-editor/properties/OntologyUriProperty.vue';
20+
import ReferenceProperty from '@/components/panels/gui-editor/properties/ReferenceProperty.vue';
2021

2122
/**
2223
* Resolves the corresponding component for a given node.
@@ -61,7 +62,13 @@ export function resolveCorrespondingComponent(
6162
isTypeUnion: true,
6263
});
6364
}
64-
65+
if (mode == 'schemaEditor' && nodeData.schema.hasType('string') && nodeData.name === '$ref') {
66+
// @ts-ignore
67+
return h(ReferenceProperty, {
68+
...propsObject,
69+
sessionMode: mode,
70+
});
71+
}
6572
if (nodeData.schema.hasType('string') && hasTwoOrMoreExamples(nodeData.schema)) {
6673
// @ts-ignore
6774
return h(EnumProperty, {

meta_configurator/src/data/managedJsonSchema.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import {clearPreprocessedRefSchemaCache} from '@/schema/schemaLazyResolver';
1414
import {writeSchemaRequiredDefaultsToData} from '@/schema/writeDefaultsToData';
1515
import {useDataSource} from '@/data/dataSource';
1616
import {detectSchemaFeatures, type SchemaFeatures} from '@/schema/detectSchemaFeatures.ts';
17-
1817
/**
1918
* This class manages the schema and provides easy access to its content.
2019
*/
@@ -126,7 +125,6 @@ export class ManagedJsonSchema {
126125
this.mode
127126
);
128127
this._schemaFeatures!.value = detectSchemaFeatures(this._schemaRaw.value);
129-
130128
if (useDataSource().newSchemaWasFetched) {
131129
// add defaults to user data, but only when new schema was fetched, not after every schema edit
132130
const data = getDataForMode(this.mode);

meta_configurator/src/schema/schemaReadingUtils.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,23 @@ export function getTypeDescription(schema: JsonSchemaObjectType): string {
3636

3737
return type;
3838
}
39+
export function getAvailableDefinitionPaths(schema: any): string[] {
40+
const paths: string[] = [];
3941

42+
if (schema?.$defs) {
43+
Object.keys(schema.$defs).forEach(key => {
44+
paths.push(`#/$defs/${key}`);
45+
});
46+
}
47+
48+
if (schema?.definitions) {
49+
Object.keys(schema.definitions).forEach(key => {
50+
paths.push(`#/definitions/${key}`);
51+
});
52+
}
53+
54+
return paths.sort();
55+
}
4056
export function isSchemaEmpty(schema: JsonSchemaType): boolean {
4157
if (schema === undefined || schema === null) {
4258
return true;

0 commit comments

Comments
 (0)