diff --git a/package-lock.json b/package-lock.json index a6ba0c70..db6b24ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@casl/vue": "^2.2.0", "@hotwax/app-version-info": "^1.0.0", "@hotwax/apps-theme": "^1.2.6", - "@hotwax/dxp-components": "^1.13.0", + "@hotwax/dxp-components": "1.14.1", "@hotwax/oms-api": "^1.14.0", "@ionic/core": "7.6.0", "@ionic/vue": "7.6.0", @@ -2830,9 +2830,9 @@ "integrity": "sha512-zpUjGoY7LBlKeiP0V7tonrmoey8HQ5THQmyixQ+IDtrjmEJNBjynW/Ef3gC0FUNNPuVqxWPZdT5CVgaETLGTwg==" }, "node_modules/@hotwax/dxp-components": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@hotwax/dxp-components/-/dxp-components-1.13.0.tgz", - "integrity": "sha512-AkzHpGIWYFURIAKaqioNZdkaeJBaJHs+ep+5ibLyEj+Ex+GsyMsI9L1NVO+tl91ECkCNx02QjHPhMfpo0osQ3w==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@hotwax/dxp-components/-/dxp-components-1.14.1.tgz", + "integrity": "sha512-JmaD1z/wHtmHl7kE94lDJPl/DDD95kaEJcp81ShHW8U8J0CBnI3JaBC5+ThKCeUmJq8+9L/in6C0/t5EslVOIg==", "dependencies": { "@hotwax/oms-api": "^1.8.1", "@ionic/core": "^7.6.0", diff --git a/package.json b/package.json index 399facbe..95632d2a 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "@casl/vue": "^2.2.0", "@hotwax/app-version-info": "^1.0.0", "@hotwax/apps-theme": "^1.2.6", - "@hotwax/dxp-components": "^1.13.0", + "@hotwax/dxp-components": "1.14.1", "@hotwax/oms-api": "^1.14.0", "@ionic/core": "7.6.0", "@ionic/vue": "7.6.0", diff --git a/src/api/index.ts b/src/api/index.ts index 84939cfe..e0972972 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -5,6 +5,8 @@ import emitter from "@/event-bus" import store from "@/store"; import { StatusCodes } from "http-status-codes"; +let apiConfig = {} as any + axios.interceptors.request.use((config: any) => { // TODO: pass csrf token const token = store.getters["user/getUserToken"]; @@ -77,6 +79,8 @@ const axiosCache = setupCache({ * @return {Promise} Response from API as returned by Axios */ const api = async (customConfig: any) => { + apiConfig = customConfig + // Prepare configuration const config: any = { url: customConfig.url, @@ -87,7 +91,14 @@ const api = async (customConfig: any) => { } const baseURL = store.getters["user/getInstanceUrl"]; - if (baseURL) config.baseURL = baseURL.startsWith('http') ? baseURL.includes('/rest/s1/available-to-promise') ? baseURL : `${baseURL}/rest/s1/available-to-promise/` : `https://${baseURL}.hotwax.io/rest/s1/available-to-promise/`; + const omsRedirectionInfo = store.getters["user/getOmsRedirectionInfo"] + + if(customConfig.useOmsRedirection) { + config.baseURL = omsRedirectionInfo.url.startsWith('http') ? omsRedirectionInfo.url.includes('/api') ? omsRedirectionInfo.url : `${omsRedirectionInfo.url}/api/` : `https://${omsRedirectionInfo.url}.hotwax.io/api/`; + } else if (baseURL) { + config.baseURL = baseURL.startsWith('http') ? baseURL.includes('/rest/s1/available-to-promise') ? baseURL : `${baseURL}/rest/s1/available-to-promise/` : `https://${baseURL}.hotwax.io/rest/s1/available-to-promise/`; + } + if(customConfig.cache) config.adapter = axiosCache.adapter; const networkStatus = await OfflineHelper.getNetworkStatus(); if (customConfig.queue && !networkStatus.connected) { @@ -108,7 +119,7 @@ const api = async (customConfig: any) => { * @return {Promise} Response from API as returned by Axios */ const client = (config: any) => { - return axios.request(config); + return axios.create().request(config); } export { api as default, client, axios }; \ No newline at end of file diff --git a/src/components/CustomFrequencyModal.vue b/src/components/CustomFrequencyModal.vue new file mode 100644 index 00000000..bf5744b0 --- /dev/null +++ b/src/components/CustomFrequencyModal.vue @@ -0,0 +1,62 @@ + + + + + + + + + {{ translate("Custom frequency") }} + + + + + + + + + {{ customFrequency.description }} + + + + + + {{ translate("No frequency found.")}} + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/JobHistoryModal.vue b/src/components/JobHistoryModal.vue new file mode 100644 index 00000000..341b0bf7 --- /dev/null +++ b/src/components/JobHistoryModal.vue @@ -0,0 +1,84 @@ + + + + + + + + + {{ currentJob?.enumName }} + + + + + + + + + {{ job.runTime ? getTime(job.runTime) : "-" }} + {{ getDate(job.runTime) }} + + {{ getStatusDesc(job.statusId) }} + + + + + + {{ translate("No available history for this job.")}} + + + + + \ No newline at end of file diff --git a/src/components/ScheduleActionsPopover.vue b/src/components/ScheduleActionsPopover.vue index 95288991..9db91948 100644 --- a/src/components/ScheduleActionsPopover.vue +++ b/src/components/ScheduleActionsPopover.vue @@ -108,14 +108,14 @@ async function runNow() { try { const resp = await RuleService.runNow(ruleGroup.value.ruleGroupId) if(!hasError(resp) && resp.data.jobRunId) { - showToast(translate("Service has been scheduled")) + showToast(translate("Service has been scheduled.")) await store.dispatch('rule/fetchRules', { groupTypeEnumId: ruleGroup.value.groupTypeEnumId, pageSize: 50 }) popoverController.dismiss(); } else { throw resp.data } } catch(err) { - showToast(translate("Failed to schedule service")) + showToast(translate("Failed to schedule service.")) logger.error(err) } emitter.emit("dismissLoader"); diff --git a/src/components/ScheduleRuleItem.vue b/src/components/ScheduleRuleItem.vue index 09608abc..e56e226d 100644 --- a/src/components/ScheduleRuleItem.vue +++ b/src/components/ScheduleRuleItem.vue @@ -76,13 +76,13 @@ async function saveSchedule() { try { const resp = await RuleService.scheduleRuleGroup(payload) if(!hasError(resp)) { - showToast(translate("Service has been scheduled")) + showToast(translate("Service has been scheduled.")) await store.dispatch('rule/fetchRules', { groupTypeEnumId: ruleGroup.value.groupTypeEnumId, pageSize: 50 }) } else { throw resp.data } } catch(err) { - showToast(translate("Failed to schedule service")) + showToast(translate("Failed to schedule service.")) logger.error(err) } emitter.emit("dismissLoader"); diff --git a/src/components/ShopActionsPopover.vue b/src/components/ShopActionsPopover.vue index a4f26bf5..f47f719b 100644 --- a/src/components/ShopActionsPopover.vue +++ b/src/components/ShopActionsPopover.vue @@ -2,19 +2,19 @@ {{ translate("More options") }} - + {{ translate("History") }} - + {{ translate("Copy details") }} - + {{ translate("Run now") }} - + {{ translate("Disable") }} @@ -23,7 +23,176 @@ \ No newline at end of file diff --git a/src/locales/en.json b/src/locales/en.json index 16d09dd5..ef51488c 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -10,6 +10,7 @@ "App": "App", "Apply": "Apply", "Are you sure you want to change the time zone to?": "Are you sure you want to change the time zone to?", + "Are you sure you want to save these changes?": "Are you sure you want to save these changes?", "Authenticating": "Authenticating", "Available to Promise": "Available to Promise", "Blank": "Blank", @@ -27,12 +28,14 @@ "Color": "Color", "Configuration missing": "Configuration missing", "Confirm": "Confirm", + "Copied to clipboard": "Copied to clipboard", "Copy details": "Copy details", "Create channel group": "Create channel group", "Create new": "Create new", "Create rule": "Create rule", "Create Rule": "Create Rule", "Custom": "Custom", + "Custom frequency": "Custom frequency", "Custom fulfillment capacity": "Custom fulfillment capacity", "Delete": "Delete", "Description": "Description", @@ -69,6 +72,7 @@ "Facility association updated successfully with pickup group.": "Facility association updated successfully with pickup group.", "Failed": "Failed", "Failed to associate some facilites to group.": "Failed to associate some facilites to group.", + "Failed to cancel this job.": "Failed to cancel this job.", "Failed to create rule.": "Failed to create rule.", "Failed to create channel group.": "Failed to create channel group.", "Failed to disable rule group.": "Failed to disable rule group.", @@ -80,7 +84,7 @@ "Failed to update facility": "Failed to update facility", "Failed to update some jobs": "Failed to update some jobs", "Failed to update threshold.": "Failed to update threshold.", - "Failed to schedule service": "Failed to schedule service", + "Failed to schedule service.": "Failed to schedule service.", "Failed to schedule service, hence other jobs are not updated": "Failed to schedule service, hence other jobs are not updated", "Failed to update facility association with pickup group.": "Failed to update facility association with pickup group.", "features": "{type} features", @@ -109,6 +113,7 @@ "Include": "Include {label}", "Info": "Info", "Inventory group": "Inventory group", + "Job runtime has passed. Please refresh to get the latest job data in order to perform any action.": "Job runtime has passed. Please refresh to get the latest job data in order to perform any action.", "Jobs sequence updated successfully": "Jobs sequence updated successfully", "Keep editing": "Keep editing", "Last run": "Last run", @@ -130,11 +135,13 @@ "New safety stock rule": "New safety stock rule", "No": "No", "No available history for rule.": "No available history for {name} rule.", + "No available history for this job.": "No available history for this job.", "No Capacity": "No Capacity", "No capacity sets the fulfillment capacity to 0, preventing any new orders from being allocated to this facility. To add a fulfillment capacity to this facility, use the custom option.": "No capacity sets the fulfillment capacity to 0, preventing any new orders from being allocated to this facility.{space} To add a fulfillment capacity to this facility, use the custom option.", "No channel found for selected product store. Either change the product store or associate channels with the product store.": "No channel found for selected product store. Either change the product store or associate channels with the product store.", "No facility found.": "No facility found.", "No facility group found for selected product store. Either change the product store or associate facility groups with the product store.": "No facility group found for selected product store. Either change the product store or associate facility groups with the product store.", + "No frequency found.": "No frequency found.", "No fulfillment capacity": "No fulfillment capacity", "No inventory channel found.": "No inventory channel found.", "No job found.": "No job found.", @@ -198,6 +205,7 @@ "Run now": "Run now", "running": "running", "Running": "Running", + "Running this job now will not replace this job. A copy of this job will be created and run immediately. You may not be able to reverse this action.": "Running this job now will not replace this job. A copy of this job will be created and run immediately.{ space } You may not be able to reverse this action.", "Running this schedule now will not replace this schedule. A copy of this schedule will be created and run immediately. You may not be able to reverse this action.": "Running this schedule now will not replace this schedule. A copy of this schedule will be created and run immediately. You may not be able to reverse this action.", "Run time": "Run time", "Save changes": "Save changes", @@ -227,7 +235,7 @@ "Select run time": "Select run time", "Select store": "Select store", "Sequence for rules updated successfully.": "Sequence for rules updated successfully.", - "Service has been scheduled": "Service has been scheduled", + "Service has been scheduled.": "Service has been scheduled.", "Set safety stock": "Set safety stock", "Settings": "Settings", "eCom Store": "eCom Store", @@ -252,6 +260,7 @@ "Stores": "Stores", "stores selected": "stores selected", "Success": "Success", + "Successfully cancelled this job.": "Successfully cancelled this job.", "Sorry, your username or password is incorrect. Please try again.": "Sorry, your username or password is incorrect. Please try again.", "The timezone you select is used to ensure automations you schedule are always accurate to the time you select.": "The timezone you select is used to ensure automations you schedule are always accurate to the time you select.", "There are no jobs pending right now": "There are no jobs pending right now", diff --git a/src/services/ChannelService.ts b/src/services/ChannelService.ts index da4b9500..933d7961 100644 --- a/src/services/ChannelService.ts +++ b/src/services/ChannelService.ts @@ -1,4 +1,7 @@ -import api from '@/api'; +import api, {client} from '@/api'; +import logger from '@/logger'; +import { hasError } from '@/utils'; +import store from '@/store'; const fetchInventoryChannels = async (payload: any): Promise => { return api({ @@ -64,13 +67,139 @@ const createFacility = async (payload: any): Promise => { }); } +const fetchShopifyConfigs = async (payload: any): Promise => { + return api({ + url: "shopifyShops", + method: "get", + params: payload + }); +} + +const fetchJobInformation = async (payload: any): Promise => { + const omsRedirectionInfo = store.getters["user/getOmsRedirectionInfo"] + const baseURL = omsRedirectionInfo.url.startsWith('http') ? omsRedirectionInfo.url.includes('/api') ? omsRedirectionInfo.url : `${omsRedirectionInfo.url}/api/` : `https://${omsRedirectionInfo.url}.hotwax.io/api/`; + + let jobs = []; + + try { + const resp = await client({ + url: "findJobs", + method: "post", + baseURL, + data: payload, + headers: { + "Authorization": 'Bearer ' + omsRedirectionInfo.token, + 'Content-Type': 'application/json' + } + }) as any; + + if(!hasError(resp)) { + jobs = resp.data.docs + } else { + throw resp.data; + } + } catch(error: any) { + logger.error(error); + } + + return jobs; +} + +const getServiceStatusDesc = async (payload: any): Promise => { + const omsRedirectionInfo = store.getters["user/getOmsRedirectionInfo"] + const baseURL = omsRedirectionInfo.url.startsWith('http') ? omsRedirectionInfo.url.includes('/api') ? omsRedirectionInfo.url : `${omsRedirectionInfo.url}/api/` : `https://${omsRedirectionInfo.url}.hotwax.io/api/`; + + return client({ + url: "performFind", + method: "post", + data: payload, + baseURL, + headers: { + "Authorization": 'Bearer ' + omsRedirectionInfo.token, + 'Content-Type': 'application/json' + }, + cache: true + }); +} + +const fetchTemporalExpression = async (payload: any): Promise => { + const omsRedirectionInfo = store.getters["user/getOmsRedirectionInfo"] + const baseURL = omsRedirectionInfo.url.startsWith('http') ? omsRedirectionInfo.url.includes('/api') ? omsRedirectionInfo.url : `${omsRedirectionInfo.url}/api/` : `https://${omsRedirectionInfo.url}.hotwax.io/api/`; + + return client({ + url: "performFind", + method: "post", + baseURL, + data: payload, + headers: { + "Authorization": 'Bearer ' + omsRedirectionInfo.token, + 'Content-Type': 'application/json' + } + }); +} + +const disableJob = async (payload: any): Promise => { + const omsRedirectionInfo = store.getters["user/getOmsRedirectionInfo"] + const baseURL = omsRedirectionInfo.url.startsWith('http') ? omsRedirectionInfo.url.includes('/api') ? omsRedirectionInfo.url : `${omsRedirectionInfo.url}/api/` : `https://${omsRedirectionInfo.url}.hotwax.io/api/`; + + return client({ + url: "service/cancelScheduledJob", + method: "post", + baseURL, + data: payload, + headers: { + "Authorization": 'Bearer ' + omsRedirectionInfo.token, + 'Content-Type': 'application/json' + } + }); +} + +const scheduleJob = async (payload: any): Promise => { + const omsRedirectionInfo = store.getters["user/getOmsRedirectionInfo"] + const baseURL = omsRedirectionInfo.url.startsWith('http') ? omsRedirectionInfo.url.includes('/api') ? omsRedirectionInfo.url : `${omsRedirectionInfo.url}/api/` : `https://${omsRedirectionInfo.url}.hotwax.io/api/`; + + return client({ + url: "scheduleService", + method: "post", + baseURL, + data: payload, + headers: { + "Authorization": 'Bearer ' + omsRedirectionInfo.token, + 'Content-Type': 'application/json' + } + }); +} + +const updateJob = async (payload: any): Promise => { + const omsRedirectionInfo = store.getters["user/getOmsRedirectionInfo"] + const baseURL = omsRedirectionInfo.url.startsWith('http') ? omsRedirectionInfo.url.includes('/api') ? omsRedirectionInfo.url : `${omsRedirectionInfo.url}/api/` : `https://${omsRedirectionInfo.url}.hotwax.io/api/`; + + return client({ + url: "service/updateJobSandbox", + method: "post", + baseURL, + data: payload, + headers: { + "Authorization": 'Bearer ' + omsRedirectionInfo.token, + 'Content-Type': 'application/json' + } + }); +} + export const ChannelService = { createFacility, createFacilityGroup, + disableJob, fetchGroupFacilities, fetchInventoryChannels, + fetchJobInformation, + fetchShopifyConfigs, + fetchTemporalExpression, + getServiceStatusDesc, + scheduleJob, updateFacilityAssociationWithGroup, updateFacilityAssociationWithProductStore, updateGroupAssociationWithProductStore, - updateGroup + updateGroup, + updateJob } \ No newline at end of file diff --git a/src/store/modules/channel/ChannelState.ts b/src/store/modules/channel/ChannelState.ts index ad076b61..305b6908 100644 --- a/src/store/modules/channel/ChannelState.ts +++ b/src/store/modules/channel/ChannelState.ts @@ -1,3 +1,6 @@ export default interface ChannelState { inventoryChannels: any; + jobs: any; + statusDesc: any; + temporalExp: any; } \ No newline at end of file diff --git a/src/store/modules/channel/actions.ts b/src/store/modules/channel/actions.ts index e6843965..9dd226d8 100644 --- a/src/store/modules/channel/actions.ts +++ b/src/store/modules/channel/actions.ts @@ -6,6 +6,7 @@ import { ChannelService } from '@/services/ChannelService' import { hasError } from '@/utils' import logger from '@/logger' import store from "@/store" +import { DateTime } from 'luxon' const actions: ActionTree = { @@ -70,6 +71,131 @@ const actions: ActionTree = { commit(types.CHANNEL_INVENTORY_CHANNELS_UPDATED, groups); }, + async fetchShopifyConfigs () { + let shopifyConfigs = []; + + try { + const resp = await ChannelService.fetchShopifyConfigs({ productStoreId: store.state.user.currentEComStore.productStoreId }); + if (!hasError(resp)) { + shopifyConfigs = resp.data; + } else { + throw resp.data + } + } catch(error: any) { + logger.error(error) + } + return shopifyConfigs; + }, + + async fetchJobs ({ commit, dispatch }) { + const shopifyConfigs = await dispatch("fetchShopifyConfigs"); + + if(!shopifyConfigs.length) { + return; + } + + let params = {}, draftJob = {} as any; + + // Fetch draft job + params = { + inputFields: { + statusId: "SERVICE_DRAFT", + systemJobEnumId: "JOB_UL_INV" + } as any, + fieldList: ["systemJobEnumId", "runTime", "tempExprId", "parentJobId", "serviceName", "jobId", "jobName", "currentRetryCount", "statusId", "productStoreId", "runtimeDataId", "shopId", "description", "enumTypeId", "enumName"], + noConditionFind: "Y", + viewSize: 1 + } + + const draftJobs = await ChannelService.fetchJobInformation(params); + if(draftJobs.length) draftJob = draftJobs[0]; + + // Fetching pending jobs + params = { + inputFields: { + statusId: "SERVICE_PENDING", + systemJobEnumId: "JOB_UL_INV", + "productStoreId": store.state.user.currentEComStore.productStoreId, + } as any, + fieldList: ["systemJobEnumId", "runTime", "tempExprId", "parentJobId", "serviceName", "jobId", "jobName", "currentRetryCount", "statusId", "productStoreId", "runtimeDataId", "shopId", "description", "enumTypeId", "enumName"], + noConditionFind: "Y" + } + + const pendingJobs = await ChannelService.fetchJobInformation(params); + + const jobs = shopifyConfigs.map((shop: any) => { + const pendingJob = pendingJobs.find((job: any) => job.shopId === shop.shopId) + + if(pendingJob?.jobId) { + return { + ...shop, + ...pendingJob, + runTimeValue: pendingJob.runTime + } + } else { + return { + ...draftJob, + ...shop, + runTimeValue: (draftJob?.runTime && (DateTime.fromMillis(draftJob.runTime).diff(DateTime.local()).milliseconds > 0)) ? draftJob.runTime : "", + tempExprId: "SERVICE_DRAFT" + } + } + }) + + commit(types.CHANNEL_JOBS_UPDATED, jobs) + }, + + async getServiceStatusDesc ({ commit }) { + let statusDescs = []; + + try{ + const resp = await ChannelService.getServiceStatusDesc({ + "inputFields": { + "statusTypeId": "SERVICE_STATUS", + "statusTypeId_op": "equals" + }, + "entityName": "StatusItem", + "fieldList": ["statusId", "description"], + "noConditionFind": "Y", + "viewSize": 20 + }) + + if(!hasError(resp)) { + statusDescs = resp.data.docs; + } else { + throw resp.data; + } + } catch(err) { + logger.error(err) + } + commit(types.CHANNEL_SERVICE_STATUS_DESC_UPDATED, statusDescs); + }, + + async findTemporalExpression({ commit, state }){ + let temporalExpressions = []; + + const resp = await ChannelService.fetchTemporalExpression({ + "inputFields": { + "tempExprTypeId": "FREQUENCY", + }, + "viewSize": 100, + "fieldList": [ "tempExprId", "description","integer1", "integer2" ], + "entityName": "TemporalExpression", + "noConditionFind": "Y", + }) + + if(!hasError(resp)) { + temporalExpressions = resp.data.docs; + temporalExpressions.forEach((temporalExpression: any) => { + state.temporalExp[temporalExpression.tempExprId] = temporalExpression; + }) + // Caching it for other uses + commit(types.CHANNEL_TEMPORAL_EXPRESSION_UPDATED, state.temporalExp); + } + + return temporalExpressions; + }, + async clearChannelState({ commit }) { commit(types.CHANNEL_INVENTORY_CHANNELS_UPDATED, []) }, diff --git a/src/store/modules/channel/getters.ts b/src/store/modules/channel/getters.ts index ad2fb11b..eaa25ab9 100644 --- a/src/store/modules/channel/getters.ts +++ b/src/store/modules/channel/getters.ts @@ -5,6 +5,15 @@ import ChannelState from './ChannelState'; const getters: GetterTree = { getInventoryChannels (state) { return state.inventoryChannels - } + }, + getJobs (state) { + return state.jobs + }, + getStatusDesc: (state) => (statusId: any) => { + return state.statusDesc[statusId] ? state.statusDesc[statusId] : "-"; + }, + getTemporalExpr: (state) => (id: string): any => { + return state.temporalExp[id]; + }, } export default getters; \ No newline at end of file diff --git a/src/store/modules/channel/index.ts b/src/store/modules/channel/index.ts index b1a9e8fe..ad2dad31 100644 --- a/src/store/modules/channel/index.ts +++ b/src/store/modules/channel/index.ts @@ -8,7 +8,10 @@ import ChannelState from './ChannelState' const channelModule: Module = { namespaced: true, state: { - inventoryChannels: [] + inventoryChannels: [], + jobs: [], + statusDesc: {}, + temporalExp: [] }, getters, actions, diff --git a/src/store/modules/channel/mutation-types.ts b/src/store/modules/channel/mutation-types.ts index cfe05e1e..06fec7de 100644 --- a/src/store/modules/channel/mutation-types.ts +++ b/src/store/modules/channel/mutation-types.ts @@ -1,2 +1,5 @@ export const SN_CHANNEL = 'channel' -export const CHANNEL_INVENTORY_CHANNELS_UPDATED = SN_CHANNEL + '/INVENTORY_CHANNELS_UPDATED' \ No newline at end of file +export const CHANNEL_INVENTORY_CHANNELS_UPDATED = SN_CHANNEL + '/INVENTORY_CHANNELS_UPDATED' +export const CHANNEL_JOBS_UPDATED = SN_CHANNEL + '/JOBS_UPDATED' +export const CHANNEL_SERVICE_STATUS_DESC_UPDATED = SN_CHANNEL + '/SERVICE_STATUS_DESC_UPDATED' +export const CHANNEL_TEMPORAL_EXPRESSION_UPDATED = SN_CHANNEL + '/TEMPORAL_EXPRESSION_UPDATED' \ No newline at end of file diff --git a/src/store/modules/channel/mutations.ts b/src/store/modules/channel/mutations.ts index 9a376d5e..3cf530df 100644 --- a/src/store/modules/channel/mutations.ts +++ b/src/store/modules/channel/mutations.ts @@ -6,5 +6,16 @@ const mutations: MutationTree = { [types.CHANNEL_INVENTORY_CHANNELS_UPDATED] (state, payload) { state.inventoryChannels = payload; }, + [types.CHANNEL_JOBS_UPDATED] (state, payload) { + state.jobs = payload; + }, + [types.CHANNEL_SERVICE_STATUS_DESC_UPDATED] (state, payload) { + payload.map((status: any) => { + state.statusDesc[status.statusId] = status.description; + }) + }, + [types.CHANNEL_TEMPORAL_EXPRESSION_UPDATED] (state, temporalExp) { + state.temporalExp = temporalExp; + }, } export default mutations; \ No newline at end of file diff --git a/src/utils/index.ts b/src/utils/index.ts index ae787391..de1654a9 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,5 +1,7 @@ import { toastController } from '@ionic/vue'; import { DateTime } from 'luxon'; +import logger from '@/logger'; +import { translate } from '@hotwax/dxp-components'; // TODO Use separate files for specific utilities @@ -159,5 +161,24 @@ const generateRuleConditions = (ruleId: string, conditionTypeEnumId: string, app return conditions; } +const hasJobDataError = (job: any) => { + let warning = ''; + let message = ''; -export { doReorder, generateInternalId, generateRuleActions, generateRuleConditions, getDate, getDateAndTime, getTime, hasError, showToast, timeTillRun } \ No newline at end of file + if (job?.serviceName === '_NA_') { + warning = `${job.systemJobEnumId} :: This job does not have any service data configuration.`; + message = 'This job does not have any service data configuration.'; + } else if (job?.runtimeData?._ERROR_MESSAGE_) { + warning = `${job.systemJobEnumId}(${job.serviceName}) has runtimeData error :: ${job.runtimeData._ERROR_MESSAGE_}`; + message = 'This job does not have any runtime data configuration.'; + } + + if(message) { + logger.warn(warning); + showToast(translate(message)); + return true; + } + return false; +} + +export { doReorder, generateInternalId, generateRuleActions, generateRuleConditions, getDate, getDateAndTime, getTime, hasJobDataError, hasError, showToast, timeTillRun } \ No newline at end of file diff --git a/src/views/InventoryChannels.vue b/src/views/InventoryChannels.vue index 004311df..ad958578 100644 --- a/src/views/InventoryChannels.vue +++ b/src/views/InventoryChannels.vue @@ -10,7 +10,7 @@ {{ translate("Channels") }} - + {{ translate("Publish") }} @@ -76,43 +76,54 @@ - + - {{ "SHOP CONFIG ID" }} - {{ "Shop name" }} + {{ job.shopifyConfigId }} + {{ job.name ? job.name : job.shopifyConfigId }} - {{ "in 2 minutes" }} + {{ translate("running") }} {{ timeFromNow(job.runTime) }} - - A + + {{ runTime.label }} + + isDateTimeModalOpen = false"> + + + + - - {{ "Every 5 minute" }} + + {{ freq.description }} - - {{ "Group name" }} + + {{ channel.facilityGroupName ? channel.facilityGroupName : channel.facilityGroupId }} - - - {{ translate("Save changes") }} - + + + {{ translate("Save changes") }} + - + @@ -128,8 +139,8 @@ \ No newline at end of file
{{ translate("No frequency found.")}}
{{ getDate(job.runTime) }}
{{ translate("No available history for this job.")}}