Skip to content

Commit

Permalink
Dev (#20)
Browse files Browse the repository at this point in the history
* Synchronizing code from bitbucket repository

* Removing TomSelect because it is no longer updated

* Metric template remove restriction

* Multiple environment variables fix

* - Setting dark mode by default in the login window
- Providing better view of current build id and build environment for debugging
- Added environment variables to set_env.sh so that they can be set during build

* Application saving and traversing through the ui fixed #8 #11

* Fixing ts errors on Error handling

* Adding build specific information for better debugging

---------

Co-authored-by: Vasilis Kefalas <[email protected]>
  • Loading branch information
fotisp and vkefalas-exz authored Sep 2, 2024
1 parent 360a7a3 commit 4ea534c
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 129 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ jobs:
with:
context: gui
image-name: gui-builder
build-args: |
BUILD_ID="${{github.sha}}"
BUILD_CONTEXT="${{github.ref_name}}"
secrets: inherit
4 changes: 1 addition & 3 deletions gui/.env.docker
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
VITE_API_URL=VITE_API_URL_PLACEHOLDER
VITE_CFSB_API_URL=VITE_CFSB_API_URL_PLACEHOLDER
VITE_BUILD_ID=VITE_BUILD_ID_PLACEHOLDER
VITE_CONTEXT=VITE_CONTEXT_PLACEHOLDER
VITE_CFSB_API_URL=VITE_CFSB_API_URL_PLACEHOLDER
8 changes: 8 additions & 0 deletions gui/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
# Build the Vue app
FROM node:20 as build-stage

ARG BUILD_ID
ARG BUILD_CONTEXT

WORKDIR /app
COPY package*.json ./
COPY .env.docker ./.env


ENV VITE_BUILD_ID=${BUILD_ID}
ENV VITE_CONTEXT=${BUILD_CONTEXT}

RUN npm install --include-dev
COPY ./ .
RUN npm run build
Expand Down
3 changes: 0 additions & 3 deletions gui/set_env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ do
echo "Setting VITE_CFSB_API_URL_PLACEHOLDER environment variables ${VITE_CFSB_API_URL}"
sed -i 's|VITE_CFSB_API_URL_PLACEHOLDER|'${VITE_CFSB_API_URL}'|g' $file

echo "Setting VITE_BUILD_ID_PLACEHOLDER environment variables ${VITE_BUILD_ID}"
sed -i 's|VITE_BUILD_ID_PLACEHOLDER|'${VITE_BUILD_ID}'|g' $file

echo "Setting VITE_CONTEXT_PLACEHOLDER environment variables ${VITE_CONTEXT}"
sed -i 's|VITE_CONTEXT_PLACEHOLDER|'${VITE_CONTEXT}'|g' $file

Expand Down
74 changes: 41 additions & 33 deletions gui/src/base-components/MultiStepsProvider/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
? 'url(#successGradient)'
: 'none'
"
:icon="isStageConnected(stage + 1) ? 'CheckCircle2' : 'Circle'"
:icon="hasError ? 'XCircle' : isStageConnected(stage + 1) ? 'CheckCircle2' : 'Circle'"
class="w-8 h-8"
:class="[
{ 'text-danger': hasError },
Expand Down Expand Up @@ -196,46 +196,54 @@ const isPrevButtonDisabled = computed(() => {
const prevButtonTooltip = computed(() => (isPrevButtonDisabled.value ? currentStage.value.prevButtonTooltip : ""))
const toPreviousPage = async ({ rawNavigation }: { rawNavigation?: boolean } = {}) => {
const { componentV$, ...data } = currentStageRef.value || {}
const isComponentValid = !componentV$ || (await componentV$.value.$validate())
const isTitleValid = !props.v$ || (await props.v$.$validate())
if (isTitleValid && isComponentValid) {
clientErrorMessages.value = []
if (rawNavigation) {
currentStageName.value = currentStage.value.previous
const { componentV$, ...data } = currentStageRef.value || {};
const isComponentValid = !componentV$ || (await componentV$.value.$validate());
const isTitleValid = !props.v$ || (await props.v$.$validate());
try {
if (!isTitleValid || !isComponentValid) {
clientErrorMessages.value = componentV$.value.$errors.map(
(error: ErrorObject) => error.$propertyPath + ": " + error.$message
);
} else {
const toPrev = () => (currentStageName.value = currentStage.value.previous)
// emits data handler if navigation requires it, here your api call may be implemented
await currentStage.value.onPrevPageClick?.(toPrev, data)
clientErrorMessages.value = [];
}
} else {
// TODO: refactor messages and reinvent way of displaying
clientErrorMessages.value = componentV$.value.$errors.map(
(error: ErrorObject) => error.$propertyPath + ": " + error.$message
)
}
}
} catch (error) {
} finally {
if (rawNavigation) {
currentStageName.value = currentStage.value.previous;
} else {
const toPrev = () => (currentStageName.value = currentStage.value.previous);
await currentStage.value.onPrevPageClick?.(toPrev, data);
}
}
};
// Navigates to next page only if current stage fields are valid
// Navigates to next page regardless if current stage fields are valid
const toNextPage = async ({ rawNavigation }: { rawNavigation?: boolean } = {}) => {
const { componentV$, ...data } = currentStageRef.value || {}
const isComponentValid = !componentV$ || (await componentV$.value.$validate())
const isTitleValid = !props.v$ || (await props.v$.$validate())
if (isTitleValid && isComponentValid) {
clientErrorMessages.value = []
const { componentV$, ...data } = currentStageRef.value || {};
const isComponentValid = !componentV$ || (await componentV$.value.$validate());
const isTitleValid = !props.v$ || (await props.v$.$validate());
try {
if (!isTitleValid || !isComponentValid) {
clientErrorMessages.value = componentV$.value.$errors.map(
(error: ErrorObject) => error.$propertyPath + ": " + error.$message
);
} else {
clientErrorMessages.value = [];
}
} catch (error) {
console.error('Validation error:', error);
} finally {
if (rawNavigation) {
currentStageName.value = currentStage.value.next
currentStageName.value = currentStage.value.next;
} else {
const toNext = () => (currentStageName.value = currentStage.value.next)
// emits data handler if navigation requires it, here your api call may be implemented
await currentStage.value.onNextPageClick?.(toNext, data)
const toNext = () => (currentStageName.value = currentStage.value.next);
await currentStage.value.onNextPageClick?.(toNext, data);
}
} else {
clientErrorMessages.value = componentV$.value.$errors.map(
(error: ErrorObject) => error.$propertyPath + ": " + error.$message
)
}
}
};
const onSaveClick = async () => {
const { componentV$, ...data } = currentStageRef.value || {}
Expand Down
164 changes: 86 additions & 78 deletions gui/src/components/Application/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,29 @@
</template>
<script setup lang="ts">
import { watchEffect, shallowRef, reactive, ref, computed, provide, Ref } from "vue"
import {computed, provide, reactive, ref, Ref, shallowRef, watchEffect} from "vue"
import _ from "lodash"
import { v4 as uuid } from "uuid"
import { IMetricComposite, IMetricRaw } from "@/interfaces/metrics.interface.ts"
import { IVariable } from "@/interfaces/variables.interface.ts"
import { IAppResource } from "@/interfaces/resources.interface.ts"
import { ISLOCompositeExpression } from "@/interfaces/sloviolation.interface.ts"
import { IUtilityFunction } from "@/interfaces/utilityFunctions.interface.ts"
import { IApplication } from "@/interfaces/application.interface.ts"
import {v4 as uuid} from "uuid"
import {IMetricComposite, IMetricRaw} from "@/interfaces/metrics.interface.ts"
import {IVariable} from "@/interfaces/variables.interface.ts"
import {IAppResource} from "@/interfaces/resources.interface.ts"
import {ISLOCompositeExpression} from "@/interfaces/sloviolation.interface.ts"
import {IUtilityFunction} from "@/interfaces/utilityFunctions.interface.ts"
import {IApplication} from "@/interfaces/application.interface.ts"
import MultiStepsProvider from "@/base-components/MultiStepsProvider/index.vue"
import STAGES from "@/components/Application/stages.ts"
import Details from "@/components/Application/Details.vue"
import Resources from "@/components/Application/Resources.vue"
import Metrics from "@/components/Application/Metrics/index.vue"
import ExpressionEditor from "@/components/Application/ExpressionEditor.vue"
import Input from "@/base-components/Form/FormInput.vue"
import { extractValidationError } from "@/utils/helper.ts"
import { useVuelidate } from "@vuelidate/core"
import { required } from "@vuelidate/validators"
import { useApplicationStore } from "@/store/modules/application.ts"
import { ITemplate } from "@/interfaces/template.interface.ts"
import { IParameter } from "@/interfaces/parameter.interface.ts"
import { AxiosError } from "axios"
import {extractValidationError} from "@/utils/helper.ts"
import {useVuelidate} from "@vuelidate/core"
import {required} from "@vuelidate/validators"
import {useApplicationStore} from "@/store/modules/application.ts"
import {ITemplate} from "@/interfaces/template.interface.ts"
import {IParameter} from "@/interfaces/parameter.interface.ts"
import {AxiosError} from "axios"
import {IEnvironment} from "@/interfaces/environment.interface.ts";
interface ApplicationProps {
Expand Down Expand Up @@ -164,13 +164,15 @@ const updateStagesData = () => {
environmentVariables: applicationData.environmentVariables
}
return await Promise.all([getComponentList(), applicationStore.validateApplication(stepPayload)])
.then(() => {
pathsWithError.value = []
responseErrorMessages.value = []
next()
})
.catch(handleError)
try {
await Promise.all([getComponentList(), applicationStore.validateApplication(stepPayload)]);
pathsWithError.value = [];
responseErrorMessages.value = [];
} catch (error: any) {
handleError(error);
} finally {
next();
}
},
payload: {
content: applicationData.content,
Expand All @@ -190,26 +192,28 @@ const updateStagesData = () => {
onNextPageClick: async (next: () => void, { resources }: { resources: Array<IAppResource> }) => {
applicationData.resources = resources
await applicationStore
.validateApplication({ title: applicationData.title, resources: applicationData.resources })
.then(() => {
pathsWithError.value = []
responseErrorMessages.value = []
next()
})
.catch(handleError)
try {
await applicationStore.validateApplication({ title: applicationData.title, resources: applicationData.resources });
pathsWithError.value = [];
responseErrorMessages.value = [];
} catch (error: any) {
handleError(error);
} finally {
next();
}
},
onPrevPageClick: async (prev: () => void, { resources }: { resources: Array<IAppResource> }) => {
applicationData.resources = resources
await applicationStore
.validateApplication({ title: applicationData.title, resources: applicationData.resources })
.then(() => {
pathsWithError.value = []
responseErrorMessages.value = []
prev()
})
.catch(handleError)
try {
await applicationStore.validateApplication({ title: applicationData.title, resources: applicationData.resources });
pathsWithError.value = [];
responseErrorMessages.value = [];
} catch (error: any) {
handleError(error);
} finally {
prev();
}
},
payload: {
appResources: applicationData.resources
Expand Down Expand Up @@ -243,20 +247,21 @@ const updateStagesData = () => {
applicationData.metrics = metrics
applicationData.sloViolations = sloViolations
await applicationStore
.validateApplication({
try {
await applicationStore.validateApplication({
title: applicationData.title,
templates: applicationData.templates,
parameters: applicationData.parameters,
metrics: applicationData.metrics,
sloViolations: applicationData.sloViolations
})
.then(() => {
pathsWithError.value = []
responseErrorMessages.value = []
next()
})
.catch(handleError)
sloViolations: applicationData.sloViolations,
});
pathsWithError.value = [];
responseErrorMessages.value = [];
} catch (error: any) {
handleError(error);
} finally {
next(); // Always navigate to the next step
}
},
onPrevPageClick: async (
prev: () => void,
Expand All @@ -277,20 +282,21 @@ const updateStagesData = () => {
applicationData.metrics = metrics
applicationData.sloViolations = sloViolations
await applicationStore
.validateApplication({
try {
await applicationStore.validateApplication({
title: applicationData.title,
templates: applicationData.templates,
parameters: applicationData.parameters,
metrics: applicationData.metrics,
sloViolations: applicationData.sloViolations
})
.then(() => {
pathsWithError.value = []
responseErrorMessages.value = []
prev()
})
.catch(handleError)
sloViolations: applicationData.sloViolations,
});
pathsWithError.value = [];
responseErrorMessages.value = [];
} catch (error: any) {
handleError(error);
} finally {
prev();
}
},
payload: {
componentList: componentList.value,
Expand All @@ -315,35 +321,37 @@ const updateStagesData = () => {
) => {
applicationData.utilityFunctions = utilityFunctions
await applicationStore
.validateApplication({
try {
await applicationStore.validateApplication({
title: applicationData.title,
utilityFunctions: applicationData.utilityFunctions
})
.then(() => {
pathsWithError.value = []
responseErrorMessages.value = []
next()
})
.catch(handleError)
utilityFunctions: applicationData.utilityFunctions,
});
pathsWithError.value = [];
responseErrorMessages.value = [];
} catch (error: any) {
handleError(error);
} finally {
next();
}
},
onPrevPageClick: async (
prev: () => void,
{ utilityFunctions }: { utilityFunctions: Array<IUtilityFunction> }
) => {
applicationData.utilityFunctions = utilityFunctions
await applicationStore
.validateApplication({
try {
await applicationStore.validateApplication({
title: applicationData.title,
utilityFunctions: applicationData.utilityFunctions
})
.then(() => {
pathsWithError.value = []
responseErrorMessages.value = []
prev()
})
.catch(handleError)
utilityFunctions: applicationData.utilityFunctions,
});
pathsWithError.value = [];
responseErrorMessages.value = [];
} catch (error: any) {
handleError(error);
} finally {
prev();
}
},
payload: {
metrics: applicationData.metrics.map((metric) => metric.name),
Expand Down
Loading

0 comments on commit 4ea534c

Please sign in to comment.