initial
This commit is contained in:
parent
aa7c30950c
commit
72716e1c28
41 changed files with 15461 additions and 0 deletions
84
frontend/app/pages/data/[id].vue
Normal file
84
frontend/app/pages/data/[id].vue
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
<template>
|
||||
<div>
|
||||
<div v-if="loadedType">
|
||||
<!-- Show our basic breadcrumb view -->
|
||||
<simple-breadcrumb
|
||||
:last="loadedType.name"
|
||||
:previous="[{ path: '/data', title: 'Data Structures' }]"
|
||||
/>
|
||||
|
||||
<!-- Show our editor -->
|
||||
<data-type-editor v-model="loadedType" />
|
||||
|
||||
<u-button
|
||||
color="primary"
|
||||
size="xl"
|
||||
class="my-3"
|
||||
@click="onSave(loadedType)"
|
||||
>
|
||||
<span class="px-3">Save</span>
|
||||
</u-button>
|
||||
|
||||
<div
|
||||
class="px-3 py-2 border-l-4 border-l-red-700 bg-red-100 mt-5 prose-sm"
|
||||
>
|
||||
<h2 style="margin: 0" class="text-red-700">Important</h2>
|
||||
<ol class="list-decimal">
|
||||
<li>
|
||||
All dynamic changes are performed on a
|
||||
<strong>local copy</strong> of the data that we received from the
|
||||
backend during the page load event.
|
||||
</li>
|
||||
<li>
|
||||
If a view requires additional data to be rendered, that data should
|
||||
also be loaded, or a more complex data structure must be sent by the
|
||||
backend.
|
||||
</li>
|
||||
<li>
|
||||
Additional data can also be loaded dynamically in response to
|
||||
various UI events.
|
||||
</li>
|
||||
<li>
|
||||
<strong>But!</strong> The save operation is performed atomically in
|
||||
a single <strong>ACID</strong> transaction on the server side. This
|
||||
is the only way we can avoid partial saves or discrepancies in
|
||||
business-critical data. See the architecture proposal for more
|
||||
details.
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>Loading ....</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { API } from "~/API";
|
||||
import type { DataType } from "~/types";
|
||||
|
||||
// Current page's route (path)
|
||||
const route = useRoute();
|
||||
const api = API.instance();
|
||||
|
||||
// The loading state, initially undefined
|
||||
const loadedType = ref<DataType | undefined>(undefined);
|
||||
|
||||
function onSave(type: DataType) {
|
||||
api.saveDataType(type).then(() => {
|
||||
// Get the fresh copy of the data
|
||||
loadTypeFromUrlParameter();
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadTypeFromUrlParameter();
|
||||
});
|
||||
|
||||
function loadTypeFromUrlParameter() {
|
||||
// Load the type by the page's [id] parameter
|
||||
const dataId = route.params.id as string;
|
||||
api.readDataType(dataId).then((response) => {
|
||||
// Update the loaded type var
|
||||
loadedType.value = response;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
139
frontend/app/pages/data/index.vue
Normal file
139
frontend/app/pages/data/index.vue
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<template>
|
||||
<div>
|
||||
<h1>Data Structures</h1>
|
||||
<table class="w-full lg:w-1/2">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-0">ID</th>
|
||||
<th>Name</th>
|
||||
<th class="w-0"> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="type in types.dataTypes" :key="type.id">
|
||||
<td class="w-0 text-nowrap">
|
||||
{{ type.id }}
|
||||
</td>
|
||||
<td class="w-full">
|
||||
<router-link :to="'/data/' + type.id">{{ type.name }}</router-link>
|
||||
</td>
|
||||
<td class="w-0">
|
||||
<u-button
|
||||
icon="i-bi-trash"
|
||||
size="xs"
|
||||
color="error"
|
||||
@click="deleteType(type)"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<u-button color="primary" @click="showNewTypeModal">Create New</u-button>
|
||||
|
||||
<u-modal
|
||||
v-model:open="newTypeDialogShow"
|
||||
:dismissible="false"
|
||||
title="New Type"
|
||||
description="Create and save a new type"
|
||||
>
|
||||
<template #body>
|
||||
<div class="grid grid-cols-1 gap-3">
|
||||
<u-form-field label="ID">
|
||||
<u-input v-model="newType.id" />
|
||||
</u-form-field>
|
||||
<u-form-field label="Name">
|
||||
<u-input v-model="newType.name" />
|
||||
</u-form-field>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<u-button
|
||||
:disabled="newType.id.length === 0 || newType.name.length === 0"
|
||||
@click="saveNewType"
|
||||
>
|
||||
Save
|
||||
</u-button>
|
||||
</template>
|
||||
</u-modal>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { API } from "~/API";
|
||||
import { DataType, DataTypeConfiguration } from "~/types";
|
||||
import { confirmationDialog } from "~/ui";
|
||||
|
||||
const types = ref<DataTypeConfiguration>(new DataTypeConfiguration([]));
|
||||
|
||||
// Var that holds our new type instance
|
||||
const newType = ref<DataType>(DataType.empty());
|
||||
const newTypeDialogShow = ref(false);
|
||||
|
||||
const api = API.instance();
|
||||
|
||||
// INIT !! This hook will be called when the layout has beed initialized
|
||||
onMounted(readAllTypes);
|
||||
|
||||
function showNewTypeModal() {
|
||||
newType.value = DataType.empty();
|
||||
newTypeDialogShow.value = true;
|
||||
}
|
||||
|
||||
function deleteType(type: DataType) {
|
||||
confirmationDialog().show("delete", () => {
|
||||
// This will be executed on confirmation
|
||||
|
||||
api.deleteDataType(type).finally(() => {
|
||||
// The delete call doesn't return anything, updating the list...
|
||||
readAllTypes();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function saveNewType() {
|
||||
api
|
||||
.saveDataType(newType.value)
|
||||
.then((configuration) => {
|
||||
// Update the types list
|
||||
types.value = configuration;
|
||||
toaster.add({
|
||||
title: "Success !!!",
|
||||
color: "success",
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
// Just log the error
|
||||
console.error("API response error", e);
|
||||
toaster.add({
|
||||
title: "Backend Error",
|
||||
color: "error",
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
// Reset the new type states
|
||||
newType.value = DataType.empty();
|
||||
newTypeDialogShow.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
const toaster = useToast();
|
||||
|
||||
function readAllTypes() {
|
||||
// Call the backend to initialize the available data types
|
||||
api
|
||||
.readConfiguration()
|
||||
.then((configuration) => {
|
||||
// Save the configuration in the global state var
|
||||
// (see the description in the state's declaration (app/composables/application.ts)
|
||||
types.value = configuration;
|
||||
})
|
||||
.catch((e) => {
|
||||
// Log & show the error
|
||||
console.error("API response error", e);
|
||||
toaster.add({
|
||||
title: "Backend Error",
|
||||
color: "error",
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
Loading…
Add table
Add a link
Reference in a new issue