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

Add support toggling json view of schemas in CreateSchemaForm #939

Merged
merged 9 commits into from
Dec 12, 2023
60 changes: 60 additions & 0 deletions services/tenant-ui/frontend/src/components/common/ToggleJson.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<template>
<div class="mt-2">
<div class="flex justify-content-end">
{{ $t('common.json') }}
<InputSwitch v-model="showRawJson" class="ml-1" @input="toggleJson" />
</div>
<div v-show="!showRawJson">
<slot></slot>
</div>
<div v-show="showRawJson">
<Textarea
id="credentialValuesEdit"
v-model="valuesJson"
:auto-resize="true"
rows="20"
cols="60"
class="w-full mt-1"
/>
</div>
</div>
</template>

<script setup lang="ts" generic="T">
// Libraries
import { ref, defineExpose } from 'vue';
// Source
import InputSwitch from 'primevue/inputswitch';
import Textarea from 'primevue/textarea';

const showRawJson = ref<boolean>(false);
const valuesJson = ref<string>('');

// Undefined indicates that the conversion was a failure
// note that indication of the error should be handled in the
// toJson and fromJson using libraries like vue-toastification
const props = defineProps<{
toJson: () => string | undefined;
fromJson: (jsonRepresentation: string) => T | undefined;
}>();

defineExpose({
showRawJson,
valuesJson,
});

const toggleJson = () => {
if (showRawJson.value) {
const res = props.toJson();
if (res) {
valuesJson.value = res;
} else {
showRawJson.value = !showRawJson.value;
}
} else {
if (!props.fromJson(valuesJson.value)) {
showRawJson.value = !showRawJson.value;
}
}
jamshale marked this conversation as resolved.
Show resolved Hide resolved
};
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -11,43 +11,13 @@
</div>

<div class="field mt-5">
<!-- Label/toggle -->
<div class="flex justify-content-between">
<div class="flex justify-content-start">
<label for="credentialValuesEdit">
<strong>{{ $t('issue.credentialFieldValues') }}</strong>
</label>
</div>
<div class="flex justify-content-end">
{{ $t('common.json') }}
<InputSwitch v-model="showRawJson" class="ml-1" @input="toggleJson" />
</div>
</div>

<!-- Raw JSON input mode -->
<div v-show="showRawJson">
<Textarea
id="credentialValuesEdit"
v-model="credentialValuesJson"
:auto-resize="true"
rows="20"
cols="60"
class="w-full mt-1"
/>

<div class="flex justify-content-end">
<small>
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
{{ $t('issue.schema') }}: {{ schemaForSelectedCred.schema.name }}
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
{{ $t('issue.version') }}:
{{ schemaForSelectedCred.schema.version }}
</small>
</div>
</div>

<!-- Dynamic Attribute field list -->
<div v-show="!showRawJson">
<ToggleJson
ref="jsonVal"
:to-json="credentialValueToJson"
:from-json="jsonToCredentialValue"
generic="CredentialValue[]"
>
<!-- Dynamic Attribute field list -->
<div
v-for="(item, index) in credentialValuesRaw"
:key="item.name"
Expand All @@ -62,8 +32,16 @@
class="w-full"
/>
</div>
</ToggleJson>
<div class="flex justify-content-end">
<small>
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
{{ $t('issue.schema') }}: {{ schemaForSelectedCred.schema.name }}
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
{{ $t('issue.version') }}:
{{ schemaForSelectedCred.schema.version }}
</small>
</div>

<Button label="Save" class="mt-5 w-full" @click="saveCredValues" />
</div>
</template>
Expand All @@ -73,16 +51,20 @@
import { onMounted, ref } from 'vue';
// PrimeVue / Validation
import Button from 'primevue/button';
import InputSwitch from 'primevue/inputswitch';
import InputText from 'primevue/inputtext';
import Textarea from 'primevue/textarea';
import { useToast } from 'vue-toastification';
import { tryParseJson } from '@/helpers/jsonParsing';
import ToggleJson from '@/components/common/ToggleJson.vue';

const toast = useToast();

// Props
interface CredentialValue {
name: string;
value: string;
}
interface Props {
existingCredentialValues?: { name: string; value: string }[];
existingCredentialValues?: CredentialValue[];
header: String;
schemaForSelectedCred: any;
}
Expand All @@ -91,58 +73,43 @@ const props = defineProps<Props>();
const emit = defineEmits(['back', 'save']);

// Fields
const credentialValuesJson = ref('');
const credentialValuesRaw = ref([] as { name: string; value: string }[]);

const showRawJson = ref(false);
const credentialValuesRaw = ref<CredentialValue[]>([]);

// TODO: util function file
function _tryParseJson(jsonString: string) {
try {
const o = JSON.parse(jsonString);
if (o && typeof o === 'object') {
return o;
}
return false;
} catch (e) {
return false;
}
}
const jsonVal = ref<{ showRawJson: boolean; valuesJson: string }>({
showRawJson: false,
valuesJson: '',
});

function _jsonToCredRaw() {
const parsed = _tryParseJson(credentialValuesJson.value);
function jsonToCredentialValue(
jsonString: string
): CredentialValue[] | undefined {
const parsed = tryParseJson<CredentialValue[]>(jsonString);
if (parsed) {
credentialValuesRaw.value = JSON.parse(credentialValuesJson.value);
credentialValuesRaw.value = parsed;
return parsed;
} else {
toast.warning('The JSON you inputted has invalid syntax');
return undefined;
}
}

const toggleJson = () => {
if (showRawJson.value) {
// Convert over to the json from what was entered on the fields
credentialValuesJson.value = JSON.stringify(
credentialValuesRaw.value,
undefined,
2
);
} else {
// Parse the entered JSON into fields, or ignore and warn if invalid syntax
_jsonToCredRaw();
}
};
function credentialValueToJson(): string | undefined {
// Convert over to the json from what was entered on the fields
const j = JSON.stringify(credentialValuesRaw.value, undefined, 2);
return j;
}

const saveCredValues = () => {
if (showRawJson.value) {
_jsonToCredRaw();
if (jsonVal.value.showRawJson) {
jsonToCredentialValue(jsonVal.value.valuesJson);
}
emit('save', credentialValuesRaw.value);
};

// Whnen the component is intialized set up the fields and raw JSON based
// When the component is initialized set up the fields and raw JSON based
// on the supplied schema and if there is existing values already
onMounted(() => {
// Popuplate cred editor if it's not already been edited
// Populate cred editor if it's not already been edited
if (!props.existingCredentialValues?.length) {
const schemaFillIn = props.schemaForSelectedCred.schema.attrNames.map(
(a: string) => {
Expand All @@ -158,10 +125,5 @@ onMounted(() => {
} else {
credentialValuesRaw.value = props.existingCredentialValues;
}
credentialValuesJson.value = JSON.stringify(
credentialValuesRaw.value,
undefined,
2
);
});
</script>
Loading
Loading