Skip to content

Commit

Permalink
Merge pull request #621 from amansinghbais/job-manager/#620
Browse files Browse the repository at this point in the history
Implemented: new UI for brokering page (#620)
  • Loading branch information
ravilodhi authored Nov 2, 2023
2 parents 04ce081 + 82050e8 commit 32db074
Show file tree
Hide file tree
Showing 5 changed files with 314 additions and 182 deletions.
265 changes: 197 additions & 68 deletions src/components/BatchModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,51 +6,107 @@
<ion-icon slot="icon-only" :icon="closeOutline" />
</ion-button>
</ion-buttons>
<ion-title>{{ currentBatch?.jobName ? currentBatch?.jobName : $t('New broker run') }}</ion-title>
<ion-title>{{ $t('New broker run') }}</ion-title>
</ion-toolbar>
</ion-header>

<ion-content>
<ion-item>
<ion-label position="fixed">{{ $t('Batch name') }}</ion-label>
<ion-label position="fixed">{{ $t('Name') }}</ion-label>
<ion-input :placeholder="currentDateTime = getCurrentDateTime()" v-model="jobName" />
</ion-item>
<ion-item :disabled="currentBatch?.jobId">
<ion-label>{{ $t('Order queue') }}</ion-label>
<ion-select slot="end" interface="popover" :value="this.currentScheduledBatch?.facilityId || batchFacilityId" @ionChange="batchFacilityId = $event['detail'].value">
<ion-item>
<ion-icon slot="start" :icon="ticketOutline" />
<ion-label>{{ $t('Order parking') }}</ion-label>
<ion-select slot="end" interface="popover" :value="batchFacilityId" @ionChange="batchFacilityId = $event['detail'].value; updateCustomParameters()">
<ion-select-option value="_NA_">{{ $t("Brokering queue") }}</ion-select-option>
<ion-select-option value="PRE_ORDER_PARKING">{{ $t("Pre-order parking") }}</ion-select-option>
<ion-select-option value="BACKORDER_PARKING">{{ $t("Back-order parking") }}</ion-select-option>
</ion-select>
</ion-item>
<ion-radio-group>
<ion-item :disabled="currentBatch?.jobId">
<ion-label>{{ $t('New orders') }}</ion-label>
<!-- "this.currentScheduledBatch?.unfillable === false" - Did this because ion-radio is not considering boolean -->
<ion-radio :checked="this.currentScheduledBatch?.unfillable === false" slot="start" @click="unfillableOrder = false" color="secondary"/>
<ion-item>
<ion-icon slot="start" :icon="warningOutline" />
<ion-label>{{ $t('Unfillable orders') }}</ion-label>
<ion-toggle slot="end" :checked="unfillableOrder" @ionChange="unfillableOrder = !unfillableOrder; updateCustomParameters()" />
</ion-item>

<ion-list v-if="customOptionalParameters.length || customRequiredParameters.length">
<ion-item lines="none">
<ion-label>{{ $t('More parameters') }}</ion-label>
</ion-item>

<ion-item-divider v-if="customRequiredParameters.length" color="light">
<ion-label>{{ $t('Required Parameters') }}</ion-label>
</ion-item-divider>

<ion-item :key="index" v-for="(parameter, index) in customRequiredParameters">
<ion-label>{{ parameter.name }}</ion-label>
<ion-input :placeholder="parameter.value ? parameter.value : parameter.name" v-model="parameter.value" />
<ion-note slot="helper">{{ parameter.type }}</ion-note>
</ion-item>
<ion-item :disabled="currentBatch?.jobId">
<ion-label>{{ $t('Unfillable orders') }}</ion-label>
<!-- "this.currentScheduledBatch?.unfillable === false" - Did this because ion-radio is not considering boolean -->
<ion-radio :checked="this.currentScheduledBatch?.unfillable === true" slot="start" @click="unfillableOrder = true" color="secondary"/>

<ion-item-divider v-if="customOptionalParameters.length" color="light">
<ion-label>{{ $t('Optional Parameters') }}</ion-label>
</ion-item-divider>

<ion-item :key="index" v-for="(parameter, index) in customOptionalParameters">
<ion-label>{{ parameter.name }}</ion-label>
<ion-input :placeholder="parameter.value ? parameter.value : parameter.name" v-model="parameter.value"/>
<ion-note slot="helper">{{ parameter.type }}</ion-note>
</ion-item>
</ion-radio-group>
<ion-item>
<ion-label position="fixed">{{ $t("Schedule") }}</ion-label>
<ion-datetime hour-cycle="h12" :value="currentBatch?.runTime ? getDateTime(currentBatch.runTime) : getNowTimestamp()" @ionChange="updateRunTime($event)" presentation="time" size="cover" />
</ion-item>
<ion-fab @click="updateJob()" vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button>
<ion-icon :icon="checkmarkDoneOutline" />
</ion-fab-button>
</ion-fab>
</ion-list>
<ion-list v-else>
<ion-item>
<ion-label>{{ $t('No parameters available') }}</ion-label>
</ion-item>
</ion-list>

<ion-card>
<ion-card-header>
<ion-card-title>{{ $t('Schedule') }}</ion-card-title>
</ion-card-header>

<ion-item>
<ion-icon slot="start" :icon="timeOutline" />
<ion-label>{{ $t('Run time') }}</ion-label>
<ion-select interface="popover" :placeholder="$t('Select')" :value="runTime" @ionChange="updateRunTime($event)">
<ion-select-option v-for="runTime in runTimes" :key="runTime.value" :value="runTime.value">{{ $t(runTime.label) }}</ion-select-option>
</ion-select>

<ion-modal class="date-time-modal" :is-open="isDateTimeModalOpen" @didDismiss="() => isDateTimeModalOpen = false">
<ion-content force-overscroll="false">
<ion-datetime
show-default-buttons
hour-cycle="h23"
:value="runTime ? (isCustomRunTime(runTime) ? getDateTime(runTime) : getDateTime(DateTime.now().toMillis() + runTime)) : getNowTimestamp()"
@ionChange="updateCustomTime($event)"
/>
</ion-content>
</ion-modal>
</ion-item>
<ion-item lines="none">
<ion-icon slot="start" :icon="timerOutline" />
<ion-label>{{ $t('Frequency') }}</ion-label>
<ion-select :value="jobStatus" :interface-options="{ header: $t('Frequency') }" interface="popover" :placeholder="$t('Disabled')" @ionChange="jobStatus = $event.detail.value" @ionDismiss="jobStatus == 'CUSTOM' && setCustomFrequency()">
<ion-select-option v-for="freq in frequencyOptions" :key="freq.id" :value="freq.id">{{ freq.description }}</ion-select-option>
</ion-select>
</ion-item>
</ion-card>
</ion-content>
<ion-fab :disabled="!hasPermission(Actions.APP_JOB_UPDATE) || isRequiredParametersMissing" @click="updateJob()" vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button>
<ion-icon :icon="checkmarkDoneOutline" />
</ion-fab-button>
</ion-fab>
</template>

<script lang="ts">
import {
IonButton,
IonButtons,
IonCard,
IonCardHeader,
IonCardTitle,
IonContent,
IonDatetime,
IonFab,
Expand All @@ -59,27 +115,35 @@ import {
IonIcon,
IonInput,
IonItem,
IonItemDivider,
IonLabel,
IonRadio,
IonRadioGroup,
IonList,
IonModal,
IonNote,
IonSelect,
IonSelectOption,
IonTitle,
IonToggle,
IonToolbar,
modalController
} from '@ionic/vue';
import { defineComponent } from 'vue';
import { closeOutline, checkmarkDoneOutline } from 'ionicons/icons';
import { closeOutline, checkmarkDoneOutline, ticketOutline, timeOutline, timerOutline, warningOutline } from 'ionicons/icons';
import { mapGetters, useStore } from 'vuex';
import { DateTime } from 'luxon';
import { handleDateTimeInput, generateJobCustomParameters, getNowTimestamp, isFutureDate, showToast, hasJobDataError } from '@/utils';
import { handleDateTimeInput, generateAllowedFrequencies, generateAllowedRunTimes, generateJobCustomParameters, generateJobCustomOptions, getNowTimestamp, hasJobDataError, isCustomRunTime, isFutureDate, showToast } from '@/utils';
import { translate } from '@/i18n'
import CustomFrequencyModal from '@/components/CustomFrequencyModal.vue';
import { Actions, hasPermission } from '@/authorization'
export default defineComponent({
name: 'BatchModal',
components: {
IonButton,
IonButtons,
IonCard,
IonCardHeader,
IonCardTitle,
IonContent,
IonDatetime,
IonFab,
Expand All @@ -88,15 +152,17 @@ export default defineComponent({
IonIcon,
IonInput,
IonItem,
IonItemDivider,
IonLabel,
IonRadio,
IonRadioGroup,
IonList,
IonModal,
IonNote,
IonSelect,
IonSelectOption,
IonTitle,
IonToggle,
IonToolbar,
},
props: ["id", "enumId"],
data() {
return {
jobEnums: JSON.parse(process.env?.VUE_APP_BATCH_JOB_ENUMS as string) as any,
Expand All @@ -105,9 +171,13 @@ export default defineComponent({
unfillableOrder: false as boolean,
batchFacilityId: '_NA_' as string,
currentDateTime: '' as string,
jobRunTime: '' as any,
currentScheduledBatch: {} as any,
orders: ""
runTime: '' as any,
runTimes: [] as any,
isDateTimeModalOpen: false,
jobStatus: null,
frequencyOptions: [] as any,
customOptionalParameters: [] as any,
customRequiredParameters: [] as any
}
},
computed: {
Expand All @@ -119,74 +189,133 @@ export default defineComponent({
}),
},
mounted() {
this.getCurrentBatch();
this.generateRunTimes(this.runTime)
this.generateFrequencyOptions(this.jobStatus)
this.updateCustomParameters()
},
methods: {
getCurrentBatch() {
this.currentBatch = this.getJob(this.enumId)?.find((job: any) => job.id === this.id)
this.jobName = this.currentBatch?.jobName;
this.currentScheduledBatch = (this as any).jobEnums[this.currentBatch?.enumId];
},
getDateTime(time: any) {
return DateTime.fromMillis(time).toISO()
},
closeModal() {
modalController.dismiss({ dismissed: true });
},
async updateJob() {
let batchJobEnum = this.enumId;
if (!batchJobEnum) {
const jobEnum: any = Object.values(this.jobEnums)?.find((job: any) => {
return job.unfillable === this.unfillableOrder && job.facilityId === this.batchFacilityId
});
batchJobEnum = jobEnum.id
async generateRunTimes(currentRunTime?: any) {
const runTimes = JSON.parse(JSON.stringify(generateAllowedRunTimes()))
let selectedRunTime
// 0 check for the 'Now' value and '' check for initial render
if(currentRunTime || currentRunTime === 0 ) {
selectedRunTime = runTimes.some((runTime: any) => runTime.value === currentRunTime)
if(!selectedRunTime) runTimes.push({ label: this.getTime(currentRunTime), value: currentRunTime })
}
this.runTime = currentRunTime
this.runTimes = runTimes
},
async generateFrequencyOptions(currentFrequency?: any) {
const frequencyOptions = JSON.parse(JSON.stringify(generateAllowedFrequencies()));
if(hasPermission(Actions.APP_CUSTOM_FREQ_VIEW)) frequencyOptions.push({ "id": "CUSTOM", "description": "Custom" })
if(currentFrequency) {
const selectedFrequency = frequencyOptions.find((frequency: any) => frequency.id === currentFrequency);
if(!selectedFrequency ) {
const frequencies = await this.store.dispatch("job/fetchTemporalExpression", [ currentFrequency ]);
const frequency = frequencies[currentFrequency];
frequency && (frequencyOptions.push({ "id": frequency.tempExprId, "description": frequency.description }))
}
}
this.frequencyOptions = frequencyOptions;
this.jobStatus = currentFrequency;
},
async updateJob() {
const jobEnum: any = Object.values(this.jobEnums)?.find((job: any) => job.unfillable === this.unfillableOrder && job.facilityId === this.batchFacilityId);
const job = this.currentBatch ? this.currentBatch : this.getJob(batchJobEnum)?.find((job: any) => job.status === 'SERVICE_DRAFT');
if (!job) {
const job = this.getJob(jobEnum.id)?.find((job: any) => job.status === 'SERVICE_DRAFT');
if(!job) {
showToast(translate('Configuration missing'))
return;
}
// return if job has missing data or error
if (hasJobDataError(job)) return;
if (this.jobRunTime) {
job['runTime'] = this.jobRunTime
}
if(hasJobDataError(job)) return;
job['jobStatus'] = 'EVERYDAY';
job['jobName'] = this.jobName || this.currentDateTime;
job.runTime = this.runTime != 0 ? (!isCustomRunTime(this.runTime) ? DateTime.now().toMillis() + this.runTime : this.runTime) : ''
// if job runTime is not a valid date then making runTime as empty
if (job?.runTime && !isFutureDate(job?.runTime)) {
if(job?.runTime && !isFutureDate(job?.runTime)) {
job.runTime = ''
}
if (job?.status === 'SERVICE_DRAFT') {
const jobCustomParameters = generateJobCustomParameters([], [], job.runtimeData)
await this.store.dispatch('job/scheduleService', { job, jobCustomParameters })
} else if (job?.status === 'SERVICE_PENDING') {
await this.store.dispatch('job/updateJob', job)
}
job['jobStatus'] = this.jobStatus ? this.jobStatus : 'HOURLY';
job['jobName'] = this.jobName || this.currentDateTime;
const jobCustomParameters = generateJobCustomParameters(this.customRequiredParameters, this.customOptionalParameters, job.runtimeData)
await this.store.dispatch('job/scheduleService', { job, jobCustomParameters })
this.closeModal()
},
updateRunTime(ev: CustomEvent) {
this.jobRunTime = handleDateTimeInput(ev['detail'].value)
async setCustomFrequency() {
const customFrequencyModal = await modalController.create({
component: CustomFrequencyModal,
});
customFrequencyModal.onDidDismiss()
.then((result) => {
let jobStatus = result.data.frequencyId;
this.generateFrequencyOptions(jobStatus);
});
return customFrequencyModal.present();
},
updateCustomTime(event: CustomEvent) {
const currTime = DateTime.now().toMillis();
const setTime = handleDateTimeInput(event.detail.value);
if(setTime > currTime) this.generateRunTimes(setTime)
else showToast(translate("Provide a future date and time"))
},
updateCustomParameters() {
const jobEnum: any = Object.values(this.jobEnums)?.find((job: any) => job.unfillable === this.unfillableOrder && job.facilityId === this.batchFacilityId);
const job = this.getJob(jobEnum.id)?.find((job: any) => job.status === 'SERVICE_DRAFT');
this.customOptionalParameters = generateJobCustomOptions(job).optionalParameters;
this.customRequiredParameters = generateJobCustomOptions(job).requiredParameters;
},
updateRunTime(event: CustomEvent) {
const value = event.detail.value
if(value != 'CUSTOM') this.generateRunTimes(value)
else this.isDateTimeModalOpen = true
},
getCurrentDateTime() {
return DateTime.now().setZone(this.userProfile.userTimeZone).toLocaleString(DateTime.DATETIME_MED);
},
getTime(time: any) {
return DateTime.fromMillis(time).toLocaleString(DateTime.DATETIME_MED);
},
isRequiredParametersMissing() {
return this.customRequiredParameters.some((parameter: any) => !parameter.value?.trim())
}
},
setup() {
const store = useStore();
return {
checkmarkDoneOutline,
closeOutline,
getNowTimestamp,
hasPermission,
isCustomRunTime,
store,
getNowTimestamp
ticketOutline,
timeOutline,
timerOutline,
warningOutline,
Actions,
DateTime
};
},
});
</script>
</script>

<style>
ion-modal.date-time-modal {
--width: 290px;
--height: 440px;
--border-radius: 8px;
}
</style>
4 changes: 2 additions & 2 deletions src/components/JobConfiguration.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<section>
<ion-item lines="none">
<!-- Adding conditional check for currentJob.jobName as currentJob is undefined when i18n runs $t -->
<h1>{{ currentJob.enumName ? currentJob.enumName : currentJob.jobName ? currentJob.jobName : '' }}</h1>
<h1>{{ isBrokerJob ? currentJob.jobName : currentJob.enumName ? currentJob.enumName : currentJob.jobName ? currentJob.jobName : '' }}</h1>
<ion-badge slot="end" color="dark" v-if="currentJob?.runTime && currentJob.statusId !== 'SERVICE_DRAFT'">{{ $t("running") }} {{ timeTillJob(currentJob.runTime) }}</ion-badge>
</ion-item>

Expand Down Expand Up @@ -199,7 +199,7 @@ export default defineComponent({
this.generateRunTimes(this.runTime)
this.generateFrequencyOptions(this.jobStatus)
},
props: ["status", "type"],
props: ["isBrokerJob", "status", "type"],
computed: {
...mapGetters({
pinnedJobs: 'user/getPinnedJobs',
Expand Down
Loading

0 comments on commit 32db074

Please sign in to comment.