Select Git revision
AdvancedPlacementSwitch.cpp
CreateVirtualView.vue 7.89 KiB
<script setup lang="ts">
import {computed, reactive, Ref, ref, watch} from "vue";
import {TableIdentifier, Transforms, useAPI, VirtualViewCreation} from "@/services/api";
import {useMainStore} from "@/services/mainStore";
import {useSelectionStore} from "@/services/selectionStore";
import SimpleJoin from "@/components/subcomponents/transform/SimpleJoin.vue";
import ExtractJson from "@/components/subcomponents/transform/ExtractJson.vue";
import EditColumns from "@/components/subcomponents/transform/EditColumns.vue";
import TableFilter from "@/components/subcomponents/transform/TableFilter.vue";
import TimeFilter from "@/components/subcomponents/transform/TimeFilter.vue";
import TableSelector from "@/components/helpers/TableSelector.vue";
import {storeToRefs} from "pinia";
import InfoDialog from "@/components/helpers/InfoDialog.vue";
import {rules} from "@/services/utils";
import AdvancedRaw from "@/components/subcomponents/transform/AdvancedRaw.vue";
type WidgetKind = "base" | "transform" | "advanced"
const modes = [
{title: "Join", value: "base"},
{title: "Transform", value: "transform"},
{title: "Advanced", value: "advanced"}]
const widgetComponents: { title: string, value: string, kind: WidgetKind }[] = [
{
title: "Advanced Raw",
value: "advancedRaw",
kind: "advanced"
},
{
title: "Column Editor",
value: "editColumns",
kind: "transform"
}, {
title: "JSON Extractor",
value: "extractJson",
kind: "transform"
}, {
title: "Table Filter",
value: "tableFilter",
kind: "transform"
},
{
title: "Simple Join",
value: "simpleJoin",
kind: "base"
},
]
const widgetInstances: { [key: string]: { ref: any, isValid: Ref<boolean>, kind: WidgetKind, cls: any } } = {
"editColumns": {cls: EditColumns, ref: ref(), isValid: ref<boolean>(false), kind: "transform"},
"extractJson": {cls: ExtractJson, ref: ref(), isValid: ref<boolean>(false), kind: "transform"},
"tableFilter": {cls: TableFilter, ref: ref(), isValid: ref<boolean>(false), kind: "transform"},
"simpleJoin": {cls: SimpleJoin, ref: ref(), isValid: ref<boolean>(false), kind: "base"},
"advancedRaw": {cls: AdvancedRaw, ref: ref(), isValid: ref<boolean>(false), kind: "advanced"},
}
const store = useMainStore()
const selection = useSelectionStore()
const api = useAPI()
const {virtualDBSchema} = storeToRefs(store)
const {selectedTable} = storeToRefs(selection)
const dialog = reactive({content: "", show: false, success: null, title: "Virtual View Creation"})
const loading = ref(false)
const mode = ref("transform")
const removeBaseTable = ref(false)
const permitOverride = ref(true)
const viewIdentifier = reactive<TableIdentifier>({source: "virtual", schema: "virtual", name: ""})
const tab = ref("columnEdit")
const widgetList = computed(() => {
const kind = mode.value
return widgetComponents.filter(item => item.kind === kind)
})
watch(widgetList, (wl) => tab.value = wl[0].value, {flush: "post"})
const widgetInstance = computed(() => widgetInstances[tab.value])
const widgetComponent = computed(() => widgetInstance.value.cls)
const isValid = computed(() => (mode.value !== "transform" || !!selectedTable.value) && !!viewIdentifier.schema && !!viewIdentifier.name && uniqueName())
const disabled = computed(() => {
const selfValid = isValid.value
const widgetValid = widgetInstance.value?.isValid.value
return !selfValid || !widgetValid
})
function createRequest(base: Transforms.Base, transforms: Transforms.Transform[]): VirtualViewCreation {
return {
name: viewIdentifier.name,
schema: viewIdentifier.schema,
table_creation: base,
transforms: transforms
}
}
async function attemptCreation(request: VirtualViewCreation, options?: {
dropBase: boolean,
base: TableIdentifier
}): Promise<boolean> {
loading.value = true
const r = await api.createVirtualView(request, {override_if_exists: permitOverride.value})
const success = !!r?.data
dialog.success = success
if (success) {
dialog.content = `"${r.data.table_meta.name}" has been created`
if (options?.dropBase) {
const t = options.base
const r2 = await api.dropVirtualView({schema: t.schema, view: t.name})
if (r2)
dialog.content += ` and its base ${t.name} has been dropped`
}
} else {
dialog.content = `Virtual view creation has failed`
}
dialog.show = true
loading.value = false
return success
}
async function onSubmit() {
const widget = widgetInstance.value
if (!widget) return
let base = {operation: "existing", base_table: selectedTable.value} as Transforms.ExistingTable
let transforms = []
if (widget.kind === "base" || widget.kind === "advanced")
base = widget.ref.createBase()
if (widget.kind === "transform" || widget.kind === "advanced")
transforms = widget.ref.createTransforms()
const r = createRequest(base, transforms)
attemptCreation(r).then(s => !!s && setTimeout(store.reloadVirtualDB, 500))
}
function uniqueName(v) {
return permitOverride.value || !Object.values(virtualDBSchema.value.tables).some(tm => tm.schema_name === viewIdentifier.schema && tm.name === viewIdentifier.name) || "view already exists"
}
function resetWidget() {
const widget = widgetInstance.value;
if (!!widget) widget.ref.resetAll()
}
</script>
<template>
<v-card title="Create Virtual View" class="fill-height" variant="text">
<v-container fluid>
<v-row justify="start" align="start" class="d-flex">
<v-col cols="2">
<v-select label="Mode" :items="modes" v-model="mode" hide-details variant="solo"></v-select>
</v-col>
<v-col cols="3">
<v-text-field label="Schema Name" :rules="[rules.required, uniqueName]"
prepend-icon="mdi-folder-pound-outline"
v-model="viewIdentifier.schema"
validate-on="invalid-input eager" clearable></v-text-field>
</v-col>
<v-col cols="4">
<v-text-field label="View Name" :rules="[rules.required, uniqueName]" prepend-icon="mdi-table"
v-model="viewIdentifier.name"
validate-on="invalid-input eager" clearable></v-text-field>
</v-col>
</v-row>
<template v-if="mode === 'transform'">
<v-row justify="start" align="center" class="text-center">
<v-col cols="4">
<TableSelector v-model:selected-table="selectedTable" source-d-b="either"
:props="{'hide-details': true}"></TableSelector>
</v-col>
<v-col cols="4">
<v-checkbox label="remove base table afterwards?" density="compact"
v-model="removeBaseTable" hide-details></v-checkbox>
</v-col>
<v-col cols="4">
<v-checkbox label="permit overriding existing table" density="compact"
v-model="permitOverride" hide-details></v-checkbox>
</v-col>
</v-row>
</template>
</v-container>
<v-card class="pa-2" variant="outlined" min-height="200">
<v-card-text>
<v-tabs v-model="tab" align-tabs="start">
<v-tab v-for="widget in widgetList" :text="widget.title" :value="widget.value" :key="widget.value"></v-tab>
</v-tabs>
<v-tabs-window v-model="tab" class="fill-height">
<v-tabs-window-item v-for="(item, key) in widgetInstances" :value="key" :key="key">
<component class="mx-auto" :is="item.cls" v-model="item.isValid.value" :ref="el => item.ref = el"
:table="selectedTable"></component>
</v-tabs-window-item>
</v-tabs-window>
<v-divider></v-divider>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn @click="resetWidget" type="reset">Reset</v-btn>
<v-btn :disabled="disabled" type="submit" @click="onSubmit">Submit</v-btn>
</v-card-actions>
</v-card>
<InfoDialog v-model:dialog="dialog"></InfoDialog>
</v-card>
</template>
<style scoped>
</style>