This commit is contained in:
andbi 2025-11-19 20:22:22 -06:00
parent aa7c30950c
commit 72716e1c28
41 changed files with 15461 additions and 0 deletions

View 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>

View 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">&nbsp;</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>

View file

@ -0,0 +1,52 @@
<template>
<div class="my-3">
<h1>Welcome!</h1>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- left -->
<div class="col-span-2">
<p>
This is a sample <strong>Nuxt</strong> web application that uses
<strong>Spring Boot</strong> as a RESTful backend. Launch the backend
from your IDE or use the following commands:
</p>
<pre>
cd backend
mvn clean spring-boot:run
</pre
>
<p>
I've left comments in the most important parts of the code. For more
details, use the links section.
</p>
</div>
<!-- right -->
<div class="bg-neutral-100 py-2 px-4 rounded-lg">
<h3 style="margin-top: 0 !important">Links</h3>
<ol>
<li>
<a href="https://nuxt.com" target="_blank">Nuxt</a> - the core
framework based on Vue.js.
</li>
<li>
<a href="https://ui.nuxt.com" target="_blank">Nuxt UI</a> - utility
components and styling.
</li>
<li>
<a href="https://spring.io/projects/spring-boot" target="_blank">
Spring Boot
</a>
- the most popular Java framework.
</li>
<li>
<a href="https://github.com/nvm-sh/nvm" target="_blank">
Node Version Manager
</a>
- an absolute must for any npm project.
</li>
</ol>
</div>
</div>
</div>
</template>
<script setup lang="ts"></script>