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>
172 changes: 105 additions & 67 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="isEmpty(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="isEmpty(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="isEmpty(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="isEmpty(getSelectedVariables())">
<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="isEmpty(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="isEmpty(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="isEmpty(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(allFileInformationProvided, getSelectedVariables())"
>
<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 @@ -151,18 +159,21 @@ import { getProjects, getTableVariables, getProject } from "@/api/api";
import {
getRestructuredProject,
getTablesFromListOfFiles,
isEmpty,
} from "@/helpers/utils";
import { Project } from "@/types/api";
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 @@ -203,12 +214,9 @@ export default defineComponent({

const isSrcTableSet = () => {
return (
props.sourceTable !== "" &&
props.sourceFolder !== "" &&
props.sourceProject !== "" &&
props.sourceTable !== undefined &&
props.sourceFolder !== undefined &&
props.sourceProject !== undefined
!isEmpty(props.sourceTable) &&
!isEmpty(props.sourceFolder) &&
!isEmpty(props.sourceProject)
);
};
const fetchVariables = async () => {
Expand All @@ -235,6 +243,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 @@ -245,6 +254,7 @@ export default defineComponent({
},
methods: {
getTablesFromListOfFiles,
isEmpty,
async getProjectContent(project: string) {
await getProject(project)
.then((data) => {
Expand All @@ -257,7 +267,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 +278,36 @@ 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();
},
getSelectedVariables() {
return this.$refs.variableSelector && (this.$refs.variableSelector as any).selectedVariables ? (this.$refs.variableSelector as any).selectedVariables : [];
},
saveIfValid(fileInfoSet: boolean, selectedVariables: StringArray) {
if(fileInfoSet && !isEmpty(selectedVariables)){
this.onSave(
this.srcProject,
this.sourceObject,
this.vwProject,
this.linkedObject,
selectedVariables
)
} else {
this.formValidated = true;
}
}
},
watch: {
srcProject() {
Expand All @@ -294,6 +322,16 @@ export default defineComponent({
},
},
computed: {
allFileInformationProvided(): boolean {
return (
!isEmpty(this.vwTable) &&
!isEmpty(this.vwFolder) &&
!isEmpty(this.vwProject) &&
!isEmpty(this.srcProject) &&
!isEmpty(this.srcFolder) &&
!isEmpty(this.srcTable));

},
linkedObject(): string {
return `${this.vwFolder}/${this.vwTable}`;
},
Expand All @@ -303,15 +341,15 @@ export default defineComponent({
isEditMode(): boolean {
// when all items are preselected, we are in edit mode
return (
this.sourceFolder !== undefined &&
this.sourceProject !== undefined &&
this.sourceTable !== undefined &&
this.viewFolder !== undefined &&
this.viewProject !== undefined &&
this.viewTable !== undefined &&
this.preselectedVariables.length > 0
!isEmpty(this.sourceFolder) &&
!isEmpty(this.sourceProject) &&
!isEmpty(this.sourceTable) &&
!isEmpty(this.viewFolder) &&
!isEmpty(this.viewProject) &&
!isEmpty(this.viewTable) &&
!isEmpty(this.preselectedVariables)
);
},
},
});
</script>
</script>
15 changes: 15 additions & 0 deletions ui/src/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,21 @@ export function diskSpaceBelowThreshold(diskSpace: number): boolean {
return diskSpace < 2147483648;
}

export function isEmpty(variable: any): boolean {
// function will return true if empty string, empty object or empty array, else false
if (variable === undefined || variable === null || variable === '') {
return true;
} else if(typeof(variable) === 'object') {
if (Array.isArray(variable)) {
return variable.length === 0;
} else {
return isEmptyObject(variable);
}
} else {
return false;
}
}

/**
* Convert given bytes to 2 digits precision round exponent version string.
* @param bytes number
Expand Down
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;
};
Loading
Loading