Skip to content

Commit

Permalink
Merge pull request #803 from molgenis/feat/form-validation-link-file
Browse files Browse the repository at this point in the history
feat: form validation link file
  • Loading branch information
marikaris authored Oct 21, 2024
2 parents b2f47e0 + ae90552 commit 44194cb
Show file tree
Hide file tree
Showing 8 changed files with 405 additions and 91 deletions.
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

0 comments on commit 44194cb

Please sign in to comment.