Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix complex renderers #2392

Merged
merged 8 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/core/src/util/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ const resolveSchemaWithSegments = (
return undefined;
}

if (schema.$ref) {
// use typeof because schema can by of any type - check singleSegmentResolveSchema below
if (typeof schema.$ref === 'string') {
schema = resolveSchema(rootSchema, schema.$ref, rootSchema);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/vue-vuetify/dev/components/ExampleAppBar.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { useAppStore } from '../store';
import JsonFormsLogo from '../assets/JsonFormsLogo.vue';
import { useAppStore } from '../store';
import ThemeChanger from './ThemeChanger.vue';

const appStore = useAppStore();
Expand Down
18 changes: 17 additions & 1 deletion packages/vue-vuetify/dev/components/ExampleDrawer.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { computed, ref } from 'vue';
import VuetifyLogo from '../assets/VuetifyLogo.vue';
import examples from '../examples';
import { useAppStore } from '../store';
Expand All @@ -8,6 +9,15 @@ const appStore = useAppStore();
const handleExampleClick = (exampleName: string) => {
appStore.exampleName = exampleName;
};
const search = ref(''); // Search term

const filteredExamples = computed(() => {
return examples.filter(
(example) =>
example.name.toLowerCase().includes(search.value.toLowerCase()) ||
example.label.toLowerCase().includes(search.value.toLowerCase()),
);
});
</script>

<template>
Expand All @@ -26,8 +36,14 @@ const handleExampleClick = (exampleName: string) => {
<v-divider></v-divider>

<v-list dense nav>
<v-text-field
v-model="search"
append-inner-icon="mdi-magnify"
density="compact"
label="Search examples"
/>
<v-list-item
v-for="example in examples"
v-for="example in filteredExamples"
:key="example.name"
:value="example.name"
link
Expand Down
4 changes: 2 additions & 2 deletions packages/vue-vuetify/dev/components/ExampleForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from '@jsonforms/vue';
import type { Ajv, ErrorObject } from 'ajv';
import * as JsonRefs from 'json-refs';
import { computed, onMounted, reactive, watch } from 'vue';
import { computed, onMounted, shallowReactive, watch } from 'vue';

export type ResolvedSchema = {
schema?: JsonSchema;
Expand Down Expand Up @@ -44,7 +44,7 @@ const props = defineProps<{
state: JsonFormsProps;
}>();

const resolvedSchema = reactive<ResolvedSchema>({
const resolvedSchema = shallowReactive<ResolvedSchema>({
schema: undefined,
resolved: false,
error: undefined,
Expand Down
31 changes: 30 additions & 1 deletion packages/vue-vuetify/dev/components/ExampleSettings.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { useAppStore } from '../store';
import { appstoreLayouts, useAppStore, type AppstoreLayouts } from '../store';

const appStore = useAppStore();

Expand Down Expand Up @@ -53,6 +53,16 @@ const iconsets = [
{ text: 'Material Design', value: 'mdi' },
{ text: 'Font Awesome', value: 'fa' },
];

const layoutMapping: Record<AppstoreLayouts, string> = {
'': 'Default',
'demo-and-data': 'Demo and Data',
};

const layouts = appstoreLayouts.map((value: AppstoreLayouts) => ({
text: layoutMapping[value] ?? value,
value: value,
}));
</script>

<template>
Expand Down Expand Up @@ -174,6 +184,25 @@ const iconsets = [

<v-divider />

<v-container>
<v-row><v-col>Demo Layout</v-col></v-row>
<v-row>
<v-col>
<v-select
outlined
persistent-hint
dense
v-model="appStore.layout"
:items="layouts"
item-title="text"
item-value="value"
></v-select>
</v-col>
</v-row>
</v-container>

<v-divider />

<v-container>
<v-row><v-col>Blueprints (need browser reload)</v-col></v-row>
<v-row>
Expand Down
103 changes: 87 additions & 16 deletions packages/vue-vuetify/dev/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import type { ValidationMode } from '@jsonforms/core';
import { reactive, ref, watch } from 'vue';
import { reactive, ref, watch, type Ref, type UnwrapRef } from 'vue';

export const appstoreLayouts = ['', 'demo-and-data'] as const;
export type AppstoreLayouts = (typeof appstoreLayouts)[number];

const appstore = reactive({
exampleName: useHistoryHash(''),
rtl: false,
formOnly: false,
layout: useLocalStorage('vuetify-example-layout', ''),
formOnly: useHistoryHashQuery('form-only', false as boolean),
activeTab: useHistoryHashQuery('active-tab', 0 as number),
dark: useLocalStorage('vuetify-example-dark', false),
theme: useLocalStorage('vuetify-example-theme', 'light'),
drawer: true,
drawer: useHistoryHashQuery('drawer', true as boolean),
settings: false,
variant: useLocalStorage('vuetify-example-variant', ''),
iconset: useLocalStorage('vuetify-example-iconset', 'mdi'),
blueprint: useLocalStorage('vuetify-example-blueprint', 'md1'),
jsonforms: {
readonly: false,
readonly: useHistoryHashQuery('read-only', false as boolean),
validationMode: 'ValidateAndShow' as ValidationMode,
config: {
restrict: true,
Expand All @@ -26,7 +31,6 @@ const appstore = reactive({
hideAvatar: false,
hideArraySummaryValidation: false,
enableFilterErrorsBeforeTouch: false,
vuetify: {},
},
locale: useLocalStorage('vuetify-example-locale', 'en'),
},
Expand All @@ -36,12 +40,13 @@ export const useAppStore = () => {
return appstore;
};

export function useHistoryHash(initialValue: string) {
function useHistoryHash(initialValue: string) {
const data = ref(initialValue);

// Function to update data based on URL hash
const updateDataFromHash = () => {
const hash = window.location.hash.slice(1);
const hashAndQuery = window.location.hash.slice(1); // Remove the leading '#'
const [hash, _] = hashAndQuery.split('?'); // Split hash and query string
if (hash) {
try {
data.value = decodeURIComponent(hash);
Expand All @@ -51,17 +56,83 @@ export function useHistoryHash(initialValue: string) {
}
};

// Update data from URL hash on component mount
// Initial update from URL hash
updateDataFromHash();

watch(
data,
(newValue) => {
const encodedData = encodeURIComponent(newValue);
window.history.replaceState(null, '', `#${encodedData}`);
},
{ deep: true },
);
watch(data, (newValue) => {
const encodedData = encodeURIComponent(newValue);

const currentHash = window.location.hash.slice(1);
const [, currentQueryString] = currentHash.split('?'); // Extract the query part after ?

window.history.replaceState(
null,
'',
`#${encodedData}${currentQueryString ? '?' + currentQueryString : ''}`, // Keep the query parameters intact
);
});

return data;
}

function useHistoryHashQuery<T extends string | boolean | number>(
queryParam: string,
initialValue: T,
) {
const data: Ref<UnwrapRef<T>> = ref<T>(initialValue);

// Function to update data based on URL hash
const updateDataFromHash = () => {
const hashAndQuery = window.location.hash.slice(1); // Remove the leading '#'
const [_, query] = hashAndQuery.split('?'); // Split hash and query string

const searchParams = new URLSearchParams(query);
if (searchParams) {
try {
const value = searchParams.has(queryParam)
? searchParams.get(queryParam)
: `${initialValue}`;

// Convert the value based on the type of initialValue
if (typeof initialValue === 'boolean') {
// Handle boolean conversion
data.value = (value === 'true') as UnwrapRef<T>;
} else if (typeof initialValue === 'number') {
data.value = (value ? parseFloat(value) : 0) as UnwrapRef<T>;
} else if (typeof initialValue === 'string') {
// Handle string conversion
data.value = value as UnwrapRef<T>;
}
} catch (error) {
console.error('Error parsing hash:', error);
}
}
};

// Initial update from URL hash
updateDataFromHash();

watch(data, (newValue) => {
const encodedData = encodeURIComponent(newValue);

const hashAndQuery = window.location.hash.slice(1); // Remove the leading '#'
const [hash, query] = hashAndQuery.split('?'); // Split hash and query string

const searchParams = new URLSearchParams(query);

if (newValue === initialValue) {
// it is the default value so no need to preserve the query paramter
searchParams.delete(queryParam);
} else {
searchParams.set(queryParam, encodedData);
}

window.history.replaceState(
null,
'',
`#${hash}${searchParams.size > 0 ? '?' + searchParams : ''}`, // Keep the query parameters intact
);
});

return data;
}
Expand Down
Loading
Loading