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

feat: form validation link file #803

Merged
merged 11 commits into from
Oct 21, 2024
Merged
46 changes: 46 additions & 0 deletions ui/src/components/FormValidation.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<template>
<div :class="isValidated && validationCondition ? 'invalid-field' : ''" class="p-1">
<slot></slot>
<div v-if="isValidated && validationCondition" class="feedback">
{{ invalidMessage }}
</div>
</div>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
name: "FormValidation",
props: {
isValidated: {
type: Boolean,
default: false
},
validationCondition: {
type: Boolean,
required: true
},
invalidMessage: {
type: String,
required: true
}
}
});
</script>

<style scoped>
.invalid-field {
border: 1px;
border-color: rgb(220, 53, 69);
border-style: solid;
border-radius: 10px;
}

.feedback {
color: rgb(220, 53, 69);
font-style: italic;
font-size: 0.9rem;
}

</style>
134 changes: 80 additions & 54 deletions ui/src/components/ViewEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
disabled
v-model="srcProject"
/>
<Dropdown
v-else
<FormValidation v-else :isValidated="formValidated" invalidMessage="Please select a source project to link from " :validationCondition="srcProject === ''">
<Dropdown
:options="projects.map((project) => project.name)"
@update="updateSrcProject"
></Dropdown>
></Dropdown>
</FormValidation>
</div>
</div>
<div class="row mb-3">
Expand All @@ -35,11 +36,12 @@
disabled
v-model="srcFolder"
/>
<Dropdown
v-else
:options="Object.keys(projectData)"
@update="updateSrcFolder"
></Dropdown>
<FormValidation v-else :isValidated="formValidated" invalidMessage="Please select a source folder to link from " :validationCondition="srcFolder === ''">
<Dropdown
:options="Object.keys(projectData)"
@update="updateSrcFolder"
></Dropdown>
</FormValidation>
</div>
</div>
<div class="row mb-3">
Expand All @@ -54,22 +56,29 @@
disabled
v-model="srcTable"
/>
<Dropdown
v-else
:options="getTablesFromListOfFiles(projectData[srcFolder])"
@update="updateSrcTable"
></Dropdown>
<FormValidation v-else :isValidated="formValidated" invalidMessage="Please select a source table to link from" :validationCondition="srcTable === ''">
<Dropdown
:options="getTablesFromListOfFiles(projectData[srcFolder])"
@update="updateSrcTable"
></Dropdown>
</FormValidation>
</div>
</div>
</form>
</div>
<div class="row">
<div class="col-12" v-if="variables.length > 0">
<VariableSelector
:variables="variables"
:preselectedVariables="preselectedVariables"
ref="variableSelector"
/>
<FormValidation
class="p-3"
:isValidated="formValidated"
invalidMessage="Please select at least one variable"
:validationCondition="($refs.variableSelector as any).selectedVariables.length === 0">
<VariableSelector
:variables="variables"
:preselectedVariables="preselectedVariables"
ref="variableSelector"
/>
</FormValidation>
</div>
</div>
<div class="row mt-3">
Expand All @@ -90,59 +99,58 @@
disabled
v-model="vwProject"
/>
<Dropdown
v-else
:options="projects.map((project) => project.name)"
@update="updateVwProject"
></Dropdown>
<FormValidation v-else :isValidated="formValidated" invalidMessage="Please select a project name" :validationCondition="vwProject === ''">
<Dropdown
:options="projects.map((project) => project.name)"
@update="updateVwProject"
required
></Dropdown>
</FormValidation>
</div>
</div>
<div class="row mb-3">
<label for="inputViewFolder" class="col-sm-3 col-form-label">
Folder:
</label>
<div class="col-sm-9">
<input
type="string"
class="form-control"
:disabled="viewFolder !== undefined"
v-model="vwFolder"
/>
<FormValidation :isValidated="formValidated" invalidMessage="Please enter a folder name" :validationCondition="vwFolder === ''">
<input
type="string"
class="form-control"
:disabled="viewFolder !== undefined"
v-model="vwFolder"
required
/>
</FormValidation>
</div>
</div>
<div class="row mb-3">
<label for="inputViewTable" class="col-sm-3 col-form-label">
Table:
</label>
<div class="col-sm-9">
<input
type="string"
class="form-control"
:disabled="isEditMode"
v-model="vwTable"
/>
<FormValidation :isValidated="formValidated" invalidMessage="Please enter a table name" :validationCondition="vwTable === ''">
<input
type="string"
class="form-control"
:disabled="isEditMode"
v-model="vwTable"
/>
</FormValidation>
</div>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button
class="btn btn-primary"
type="submit"
@click.prevent="saveIfValid"
>
<i class="bi bi-floppy-fill"></i> Save
</button>
</div>
</form>
</div>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button
class="btn btn-primary"
type="button"
@click="
onSave(
srcProject,
sourceObject,
vwProject,
linkedObject,
($refs.variableSelector as any).selectedVariables
)
"
>
<i class="bi bi-floppy-fill"></i> Save
</button>
</div>
</div>
</div>
</template>
Expand All @@ -157,12 +165,14 @@ import { StringArray, ViewEditorData } from "@/types/types";
import { PropType, Ref, defineComponent, onMounted, ref } from "vue";
import VariableSelector from "@/components/VariableSelector.vue";
import Dropdown from "@/components/Dropdown.vue";
import FormValidation from "@/components/FormValidation.vue";

export default defineComponent({
name: "ViewEditor",
components: {
VariableSelector,
Dropdown,
FormValidation
},
props: {
sourceFolder: String,
Expand Down Expand Up @@ -235,6 +245,7 @@ export default defineComponent({
data(): ViewEditorData {
return {
projectData: {},
formValidated: false,
vwTable: this.viewTable ? this.viewTable : "",
vwProject: this.viewProject ? this.viewProject : "",
vwFolder: this.viewFolder ? this.viewFolder : "",
Expand All @@ -257,7 +268,6 @@ export default defineComponent({
});
},
async getVariables(project: string, folder: string, file: string) {
console.log(project, folder, file);
await getTableVariables(project, folder + "%2F" + file)
.then((response) => {
this.variables = response;
Expand All @@ -269,17 +279,33 @@ export default defineComponent({
});
},
updateSrcProject(event: Event) {
this.formValidated = false;
this.srcProject = event.toString();
},
updateVwProject(event: Event) {
this.vwProject = event.toString();
},
updateSrcFolder(event: Event) {
this.formValidated = false;
this.srcFolder = event.toString();
},
updateSrcTable(event: Event) {
this.formValidated = false;
this.srcTable = event.toString();
},
saveIfValid(){
if(this.vwTable && this.vwFolder && this.vwProject){
this.onSave(
this.srcProject,
this.sourceObject,
this.vwProject,
this.linkedObject,
(this.$refs.variableSelector as any).selectedVariables
)
} else {
this.formValidated = true;
}
}
},
watch: {
srcProject() {
Expand Down Expand Up @@ -314,4 +340,4 @@ export default defineComponent({
},
},
});
</script>
</script>
2 changes: 2 additions & 0 deletions ui/src/types/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

import { Project, User } from "./api";

export type StringObject = Record<string, string | Array<string>>;
Expand Down Expand Up @@ -128,4 +129,5 @@ export type ViewEditorData = {
srcTable: string;
srcProject: string;
srcFolder: string;
formValidated: boolean;
};
31 changes: 31 additions & 0 deletions ui/tests/unit/components/FormValidation.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { mount, VueWrapper } from "@vue/test-utils";
import FormValidation from "@/components/FormValidation.vue";

describe("ButtonGroup", () => {
const msg = "Invalid form! Please fix.";
const mockFunction = jest.fn();
let wrapper: VueWrapper<any>;
beforeEach(function () {
wrapper = mount(FormValidation, {
props: {
validationCondition: false,
invalidMessage: msg
},
});
});

test("validation message not shown when isValidated not defined", () => {
expect(wrapper.html()).not.toContain(msg)
});

test("validation message not shown when isValidated true and condition false", async () => {
await wrapper.setProps({ isValidated: true});
expect(wrapper.html()).not.toContain(msg)
});

test("validation message shown when isValidated true and condition false", async () => {
await wrapper.setProps({ validationCondition: true, isValidated: true});
expect(wrapper.html()).toContain(msg)
});

});