Skip to content
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
12 changes: 11 additions & 1 deletion frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"@vue-flow/core": "^1.45.0",
"cytoscape": "^3.32.1",
"pinia": "^3.0.3",
"vue": "^3.5.17"
"vue": "^3.5.17",
"vue-toastification": "^2.0.0-rc.5"
},
"devDependencies": {
"@tsconfig/node22": "^22.0.2",
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ import DatabaseStep from "./components/steps/DatabaseStep.vue"
import SchemaStep from "./components/steps/SchemaStep.vue"
import GlobalModal from "@/components/modal/GlobalModal.vue"

const steps: Array<any> = [SchemaStep, ProjectNameStep, DatabaseStep, SchemaStep]
import type { Component } from "vue"

const steps: Component[] = [ProjectNameStep, DatabaseStep, SchemaStep]
</script>

<style>
Expand Down
20 changes: 20 additions & 0 deletions frontend/src/assets/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,25 @@ body {
--color-secondary: #dcebfe;
--color-success: #7fbc8c;
--color-danger: #ff6b6b;
--color-warning: #f5c26b;
--color-background: #f4f4f0;
}

.Vue-Toastification__toast {
border: 2px solid black;
border-radius: 0px !important;
color: black !important;
box-shadow: 2px 2px 0px !important;
}

.Vue-Toastification__toast--success.container-class {
background-color: var(--color-success);
}

.Vue-Toastification__toast--error.container-class {
background-color: var(--color-danger);
}

.Vue-Toastification__toast--warning.container-class {
background-color: var(--color-warning);
}
90 changes: 90 additions & 0 deletions frontend/src/components/ValidatedInput.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<template>
<div class="validated-input">
<label v-if="label" class="field-label">{{ label }}</label>

<input
v-bind="$attrs"
:value="modelValue"
@input="onInput"
:class="{ invalid: error }"
class="field-input"
/>

<p v-if="error" class="error-msg">{{ error }}</p>
</div>
</template>

<script setup lang="ts">
import { ref, watch } from "vue"

interface Props {
modelValue: string
label?: string
validate?: ((value: string) => boolean) | ((value: string) => string | null)
errorMessage?: string // used if validate returns boolean
}

const props = defineProps<Props>()
const emit = defineEmits(["update:modelValue"])

const error = ref<string | null>(null)

const runValidation = (value: string) => {
if (!props.validate) {
error.value = null
return
}

const result = props.validate(value)

if (typeof result === "boolean") {
error.value = result ? null : (props.errorMessage ?? "Invalid value")
} else {
error.value = result // already string|null from custom function
}
}

const onInput = (e: Event) => {
const value = (e.target as HTMLInputElement).value
emit("update:modelValue", value)
runValidation(value)
}

watch(
() => props.modelValue,
(newVal) => runValidation(newVal),
{ immediate: true },
)
</script>

<style scoped>
.field-label {
font-weight: bold;
margin-bottom: 5px;
display: block;
}

.field-input {
border: 2px solid black;
border-radius: 6px;
padding: 0.6rem;
background-color: white;
width: 100%;
}

.field-input.invalid {
border-color: red;
}

.error-msg {
color: red;
font-size: 0.85rem;
margin-top: 2px;
}

.validated-input {
display: flex;
flex-direction: column;
gap: 0.15rem;
}
</style>
10 changes: 8 additions & 2 deletions frontend/src/components/modal/AddEnumValueModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
<div class="input-container">
<div class="input-group">
<label class="field-label">Name</label>
<input class="field-input" v-model="name" type="text" />
<input class="field-input" v-model="name" type="text" maxlength="100" />
</div>

<div class="input-group">
<label class="field-label">Value</label>
<input class="field-input" v-model="value" type="text" />
<input class="field-input" v-model="value" type="text" maxlength="100" />
</div>
</div>

Expand All @@ -22,6 +22,8 @@
import { ref } from "vue"
import { useProjectStore } from "@/stores/useProjectStore"
import { useModalStore } from "@/stores/useModalStore"
import { isValidEnumValueName, warningMessages } from "@/utils/validation"
import { showDangerToast } from "@/utils/toast"

const props = defineProps<{
enumName: string
Expand All @@ -34,6 +36,10 @@ const name = ref("")
const value = ref("auto()")

const saveEnumValue = () => {
if (!isValidEnumValueName(name.value)) {
showDangerToast(warningMessages.enumValueName)
return
}
projectStore.addEnumValue(props.enumName, {
name: name.value,
value: value.value,
Expand Down
11 changes: 9 additions & 2 deletions frontend/src/components/modal/AddFieldModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<div class="input-container">
<div class="input-group">
<label class="field-label">Field name</label>
<input class="field-input" v-model="fieldName" type="text" />
<input class="field-input" v-model="fieldName" type="text" maxlength="100" />
</div>

<div class="input-group">
Expand Down Expand Up @@ -44,10 +44,11 @@
</option>
</select>
<input
v-else
class="field-input"
v-model="defaultValue"
type="text"
v-else
maxlength="100"
:disabled="isPrimaryKey || createdAtTimestamp || updatedAtTimestamp"
/>
</div>
Expand Down Expand Up @@ -77,6 +78,8 @@ import { ref, watch } from "vue"
import { useProjectStore } from "@/stores/useProjectStore"
import { useModalStore } from "@/stores/useModalStore"
import type { EnumT, FieldType } from "@/types/types"
import { isValidFieldName, warningMessages } from "@/utils/validation"
import { showDangerToast } from "@/utils/toast"

const props = defineProps<{
id: string
Expand Down Expand Up @@ -143,6 +146,10 @@ watch(type, (newVal) => {

const saveField = () => {
if (!fieldName.value || !type.value) return
if (!isValidFieldName(fieldName.value)) {
showDangerToast(warningMessages.fieldName)
return
}
projectStore.addField(props.id, {
name: fieldName.value,
type: type.value as FieldType,
Expand Down
13 changes: 10 additions & 3 deletions frontend/src/components/modal/AddRelationModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<div class="input-container">
<div class="input-group">
<label class="relation-label">Field name</label>
<input class="relation-input" v-model="fieldName" type="text" />
<input class="relation-input" v-model="fieldName" type="text" maxlength="100" />
</div>

<div class="input-group">
Expand All @@ -27,7 +27,7 @@

<div class="input-group">
<label class="relation-label">Back populates</label>
<input class="relation-input" v-model="backPopulates" type="text" />
<input class="relation-input" v-model="backPopulates" type="text" maxlength="100" />
</div>
</div>

Expand All @@ -47,6 +47,9 @@
import { ref, computed } from "vue"
import { useProjectStore } from "@/stores/useProjectStore"
import { useModalStore } from "@/stores/useModalStore"
import type { OnDeleteType } from "@/types/types"
import { isValidFieldName, warningMessages } from "@/utils/validation"
import { showDangerToast } from "@/utils/toast"

const props = defineProps<{
id: string
Expand All @@ -67,11 +70,15 @@ const filteredNodes = computed(() => projectStore.nodes.filter((node) => node.id

const saveSelect = () => {
if (!selectedNodeId.value || !fieldName.value) return
if (!isValidFieldName(fieldName.value)) {
showDangerToast(warningMessages.fieldName)
return
}
projectStore.addRelation(props.id, selectedNodeId.value, {
fieldName: fieldName.value,
targetModel: selectedNodeId.value,
backPopulates: backPopulates.value,
onDelete: onDelete.value,
onDelete: onDelete.value as OnDeleteType,
isNullable: nullable.value,
isUnique: unique.value,
isIndex: indexed.value,
Expand Down
12 changes: 10 additions & 2 deletions frontend/src/components/modal/EditEnumValueModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
<div class="input-container">
<div class="input-group">
<label class="field-label">Name</label>
<input class="field-input" v-model="name" type="text" />
<input class="field-input" v-model="name" type="text" maxlength="100" />
</div>

<div class="input-group">
<label class="field-label">Value</label>
<input class="field-input" v-model="value" type="text" />
<input class="field-input" v-model="value" type="text" maxlength="100" />
</div>
</div>

Expand All @@ -23,6 +23,8 @@ import { ref } from "vue"
import { useProjectStore } from "@/stores/useProjectStore"
import { useModalStore } from "@/stores/useModalStore"
import type { EnumValue } from "@/types/types"
import { isValidEnumValueName, warningMessages } from "@/utils/validation"
import { showDangerToast } from "@/utils/toast"

const props = defineProps<{
enumName: string
Expand All @@ -36,6 +38,10 @@ const name = ref(props.enumValue.name)
const value = ref(props.enumValue.value)

const saveEnumValue = () => {
if (!isValidEnumValueName(name.value)) {
showDangerToast(warningMessages.enumValueName)
return
}
projectStore.updateEnumValue(props.enumName, props.enumValue.name, {
name: name.value,
value: value.value,
Expand Down Expand Up @@ -101,3 +107,5 @@ const saveEnumValue = () => {
box-shadow: none;
}
</style>

function showDangerToast(modelName: any) { throw new Error("Function not implemented."); }
11 changes: 9 additions & 2 deletions frontend/src/components/modal/EditFieldModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<div class="input-container">
<div class="input-group">
<label class="field-label">Field name</label>
<input class="field-input" v-model="fieldName" type="text" />
<input class="field-input" v-model="fieldName" type="text" maxlength="100" />
</div>

<div class="input-group">
Expand Down Expand Up @@ -44,10 +44,11 @@
</option>
</select>
<input
v-else
class="field-input"
v-model="defaultValue"
type="text"
v-else
maxlength="100"
:disabled="isPrimaryKey || createdAtTimestamp || updatedAtTimestamp"
/>
</div>
Expand Down Expand Up @@ -78,6 +79,8 @@ import { ref, onMounted, watch } from "vue"
import { useProjectStore } from "@/stores/useProjectStore"
import { useModalStore } from "@/stores/useModalStore"
import type { EnumT, RelationalField } from "@/types/types"
import { isValidFieldName, warningMessages } from "@/utils/validation"
import { showDangerToast } from "@/utils/toast"

const props = defineProps<{
id: string
Expand Down Expand Up @@ -153,6 +156,10 @@ watch(type, (newVal) => {
})

const saveField = () => {
if (!isValidFieldName(fieldName.value)) {
showDangerToast(warningMessages.fieldName)
return
}
projectStore.updateField(props.id, props.field.name, {
name: fieldName.value,
type: type.value,
Expand Down
Loading