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

Implemented: 'Learn More' functionality that generates job info from GitBook Lens APIs (#726) #730

Merged
merged 11 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ VUE_APP_ALIAS=
VUE_APP_DEFAULT_LOG_LEVEL="error"
VUE_APP_LOGIN_URL="http://launchpad.hotwax.io/login"
VUE_APP_BROKER_JOB_ENUMS = {"REJ_ORDR":"JOB_BKR_REJ_ORD"}
VUE_APP_GITBOOK_API_KEY=""
VUE_APP_SPACE_ID=""
VUE_APP_GITBOOK_BASE_URL="https://api.gitbook.com/v1"
VUE_APP_GITBOOK_JOBS_DOCS_URL="https://docs.hotwax.co/documents/retail-operations/workflow/job-workflows"
7 changes: 4 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"@hotwax/app-version-info": "^1.0.0",
"@hotwax/apps-theme": "^1.2.6",
"@hotwax/dxp-components": "1.15.4",
"@hotwax/oms-api": "1.14.0",
"@hotwax/oms-api": "^1.14.0",
"@ionic/core": "^7.6.0",
"@ionic/vue": "^7.6.0",
"@ionic/vue-router": "^7.6.0",
Expand Down
4 changes: 3 additions & 1 deletion src/adapter/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { api, client, getConfig, initialise, logout, resetConfig, updateInstanceUrl, updateToken, setUserTimeZone, getAvailableTimeZones} from '@hotwax/oms-api'
import { api, askQuery, client, getConfig, initialise, logout, resetConfig, searchQuery, updateInstanceUrl, updateToken, setUserTimeZone, getAvailableTimeZones} from '@hotwax/oms-api'

export {
api,
askQuery,
client,
getConfig,
initialise,
logout,
resetConfig,
updateInstanceUrl,
updateToken,
searchQuery,
setUserTimeZone,
getAvailableTimeZones
}
20 changes: 18 additions & 2 deletions src/components/JobConfiguration.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

<ion-item v-if="currentJob.description" lines="none">
<ion-label class="ion-text-wrap">
<p>{{ currentJob.description }}</p>
<p>{{ currentJob.description }}
<ion-text class="learn-more-text" color="primary" @click="openLearnMoreModal()">{{ translate("Learn more") }}</ion-text>
</p>
</ion-label>
</ion-item>

Expand Down Expand Up @@ -170,6 +172,7 @@ import {
IonRow,
IonSelect,
IonSelectOption,
IonText,
alertController,
modalController,
} from "@ionic/vue";
Expand Down Expand Up @@ -200,6 +203,7 @@ import emitter from '@/event-bus';
import { Actions, hasPermission } from '@/authorization'
import CustomFrequencyModal from '@/components/CustomFrequencyModal.vue';
import JobParameterModal from '@/components/JobParameterModal.vue'
import LearnMoreModal from "@/components/LearnMoreModal.vue";

export default defineComponent({
name: "JobConfiguration",
Expand All @@ -218,7 +222,8 @@ export default defineComponent({
IonRow,
IonSelect,
IonSelectOption,
IonCheckbox
IonCheckbox,
IonText
},
data() {
return {
Expand Down Expand Up @@ -279,6 +284,13 @@ export default defineComponent({
const jobId = this.currentJob.jobId
this.router.push({ name: 'DataManagerLogDetails', params: { jobId } })
},
async openLearnMoreModal() {
const learnMoreModal = await modalController.create({
component: LearnMoreModal,
componentProps: {currentJob: this.currentJob}
})
return learnMoreModal.present()
},
getDateTime(time: any) {
return DateTime.fromMillis(time).toISO()
},
Expand Down Expand Up @@ -604,6 +616,10 @@ export default defineComponent({
</script>

<style scoped>
.learn-more-text {
font-size: 14px;
cursor: pointer;
}
section {
margin-top: var(--spacer-sm);
margin-bottom: var(--spacer-sm);
Expand Down
170 changes: 170 additions & 0 deletions src/components/LearnMoreModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
<template>
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-button @click="closeModal()">
<ion-icon slot="icon-only" :icon="closeOutline" />
</ion-button>
</ion-buttons>
<ion-title>{{ translate("Learn more") }}</ion-title>
<ion-buttons slot="end">
<ion-button fill="clear" color="medium" @click="redirectToJobsDoc()">
<ion-icon slot="icon-only" :icon="openOutline" />
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>

<ion-content>
<div class="empty-state" v-if="isGeneratingAnswer">
<ion-item lines="none">
<ion-spinner name="crescent" slot="start" />
{{ translate("Generating answer...") }}
</ion-item>
</div>

<div class="empty-state" v-else-if="!Object.keys(askResponse).length">
<ion-item lines="none">
<p>{{ translate("The job details is not generating, please try again later.") }}</p>
</ion-item>
</div>

<div v-else>
<ion-item lines="full" class="ion-margin-top">
<ion-label>
{{ queryString }}
<p>{{ currentJob?.systemJobEnumId }}</p>
</ion-label>
</ion-item>

<ion-list>
<ion-item lines="none">
<ion-label>{{ translate("Sources") }}</ion-label>
</ion-item>
<ion-item v-for="section in jobSection" :key="section.id" lines="none">
<ion-chip outline @click="redirectToDoc(section)">
<ion-label>{{ section.title }}</ion-label>
<ion-icon :icon="openOutline" />
</ion-chip>
</ion-item>
</ion-list>

<ion-item>
<ion-label>
<p class="overline">{{ translate("Summary") }}</p>
{{ askResponse?.text }}
</ion-label>
</ion-item>
</div>
</ion-content>
</template>

<script lang="ts">
import { IonButton, IonButtons, IonChip, IonContent, IonHeader, IonIcon, IonItem, IonLabel, IonList, IonSpinner, IonTitle, IonToolbar, modalController } from "@ionic/vue";
import { closeOutline, openOutline } from 'ionicons/icons'
import { translate } from '@hotwax/dxp-components';
import { defineComponent } from "vue";
import { hasError } from '@/utils'
import { askQuery, searchQuery } from "@/adapter";
import logger from "@/logger";

export default defineComponent({
name: "LearnMoreModal",
components: {
IonButton,
IonButtons,
IonChip,
IonContent,
IonHeader,
IonIcon,
IonItem,
IonLabel,
IonList,
IonSpinner,
IonTitle,
IonToolbar
},
data() {
return {
queryString: '',
askResponse: {} as any,
jobSection: {} as any,
isGeneratingAnswer: true
}
},
props: ["currentJob"],
mounted() {
this.askQuery();
},
methods: {
async searchQuery(pageIds: any) {
let items = [] as any;
this.jobSection = [];
try {
const resp = await searchQuery({
queryString: this.currentJob?.enumName,
spaceId: process.env.VUE_APP_SPACE_ID,
baseURL: process.env.VUE_APP_GITBOOK_BASE_URL,
token: process.env.VUE_APP_GITBOOK_API_KEY
});
if(!hasError(resp)) {
items = resp.data.items;
pageIds.forEach((pageId: any) => {
const filteredPage = items.find((item: any) => item.id === pageId);
if (filteredPage) {
this.jobSection.push(...filteredPage.sections);
}
});
this.isGeneratingAnswer = false;
} else {
throw resp.data;
}
} catch(error: any) {
logger.error(error);
this.isGeneratingAnswer = false;
}
},
async askQuery() {
this.queryString = `What does ${this.currentJob?.enumName} job do?`;
try {
const resp = await askQuery({
queryString: this.queryString,
spaceId: process.env.VUE_APP_SPACE_ID,
baseURL: process.env.VUE_APP_GITBOOK_BASE_URL,
token: process.env.VUE_APP_GITBOOK_API_KEY
});
if(!hasError(resp)) {
this.askResponse = resp.data.answer;
if(this.askResponse) {
const pageIds = this.askResponse?.sources.map((source: any) => source.page);
this.searchQuery(pageIds);
} else {
this.isGeneratingAnswer = false;
}
} else {
throw resp.data;
}
} catch(error: any) {
logger.error(error);
this.isGeneratingAnswer = false;
}
},
async redirectToDoc(section: any) {
window.open(`https://docs.hotwax.co/documents/retail-operations/${section.path}`, "_blank", "noopener, noreferrer")
},
async redirectToJobsDoc() {
ymaheshwari1 marked this conversation as resolved.
Show resolved Hide resolved
window.open(`${process.env.VUE_APP_GITBOOK_JOBS_DOCS_URL}`, "_blank", "noopener, noreferrer")
},
async closeModal() {
modalController.dismiss({ dismissed: true });
}
},
setup() {
return {
closeOutline,
openOutline,
translate
};
}
})
</script>
5 changes: 5 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
"Fulfilled": "Fulfilled",
"Fulfillment": "Fulfillment",
"Fulfillment status": "Fulfillment status",
"Generating answer...": "Generating answer...",
"Get Paid Transactions": "Get Paid Transactions",
"Go to OMS": "Go to OMS",
"Go to Launchpad": "Go to Launchpad",
Expand Down Expand Up @@ -135,6 +136,7 @@
"Landed inventory cost": "Landed inventory cost",
"Last run": "Last run",
"Last Shopify Order ID": "Last Shopify Order ID",
"Learn more": "Learn more",
"Loading": "Loading",
"Login": "Login",
"Log Id": "Log Id",
Expand Down Expand Up @@ -268,6 +270,7 @@
"Skip job": "Skip job",
"Skip once": "Skip once",
"Skipping will run this job at the next occurrence based on the temporal expression.": "Skipping will run this job at the next occurrence based on the temporal expression.",
"Sources": "Sources",
"Some jobs have slow frequency type, hence, feasible frequency will be set automatically": "Some jobs have slow frequency type, hence, feasible frequency will be set automatically",
"Something went wrong": "Something went wrong",
"Something went wrong while getting complete user permissions.": "Something went wrong while getting complete user permissions.",
Expand All @@ -281,6 +284,7 @@
"store name": "store name",
"Stores": "Stores",
"stores selected": "stores selected",
"Summary": "Summary",
"Sync": "Sync",
"Sync pre-selling related information to Shopify as tags and meta fields.": "Sync pre-selling related information to Shopify as tags and meta fields.",
"Sync products": "Sync products",
Expand All @@ -301,6 +305,7 @@
"This job may take several minutes to run. Wait till the job has moved to the pipeline history before checking results.": "This job may take several minutes to run.{ space } Wait till the job has moved to the pipeline history before checking results.",
"This job schedule cannot be skipped": "This job schedule cannot be skipped",
"This job does not have any custom parameters.": "This job does not have any custom parameters.",
"The job details is not generating, please try again later.": "The job details is not generating, please try again later.",
"Time zone updated successfully": "Time zone updated successfully",
"Timezone": "Timezone",
"Tomorrow": "Tomorrow",
Expand Down
19 changes: 17 additions & 2 deletions src/views/Pipeline.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,17 @@
<ion-label class="ion-text-wrap">{{ job.tempExprId ? temporalExpr(job.tempExprId)?.description : "🙃" }}</ion-label>
</ion-item>

<ion-item lines="full">
<ion-item>
<ion-icon slot="start" :icon="refreshOutline" />
<ion-label class="ion-text-wrap">{{ job.currentRetryCount }}</ion-label>
</ion-item>

<ion-item lines="full">
<ion-icon slot="start" :icon="codeWorkingOutline" />
<ion-label class="ion-text-wrap">{{ job.systemJobEnumId }}</ion-label>
<ion-icon :icon="helpCircleOutline" @click.stop.prevent="openLearnMoreModal(job)"/>
</ion-item>

<div class="actions">
<div>
<ion-button :disabled="!hasPermission(Actions.APP_JOB_UPDATE)" fill="clear" @click.stop="skipJob(job)">{{ translate("Skip") }}</ion-button>
Expand Down Expand Up @@ -300,7 +306,7 @@ import {
IonButtons
} from "@ionic/vue";
import JobConfiguration from '@/components/JobConfiguration.vue'
import { closeCircleOutline, codeWorkingOutline, copyOutline, ellipsisVerticalOutline, filterOutline, pinOutline, refreshOutline, timeOutline, timerOutline } from "ionicons/icons";
import { closeCircleOutline, codeWorkingOutline, copyOutline, ellipsisVerticalOutline, filterOutline, helpCircleOutline, pinOutline, refreshOutline, timeOutline, timerOutline } from "ionicons/icons";
import emitter from '@/event-bus';
import JobHistoryModal from '@/components/JobHistoryModal.vue';
import { Plugins } from '@capacitor/core';
Expand All @@ -310,6 +316,7 @@ import { Actions, hasPermission } from '@/authorization'
import Filters from '@/components/Filters.vue';
import FailedJobReasonModal from '@/views/FailedJobReasonModal.vue'
import { translate } from '@hotwax/dxp-components';
import LearnMoreModal from '@/components/LearnMoreModal.vue';

export default defineComponent({
name: "Pipeline",
Expand Down Expand Up @@ -391,6 +398,13 @@ export default defineComponent({
this.isScrollingEnabled = false;
},
methods : {
async openLearnMoreModal(job: any) {
const learnMoreModal = await modalController.create({
component: LearnMoreModal,
componentProps: {currentJob: job}
})
return learnMoreModal.present()
},
isPinnedJobSelected(jobEnumId: any) {
return (this as any).pipelineFilters.enum.some((jobId: any) => jobId === jobEnumId );
},
Expand Down Expand Up @@ -672,6 +686,7 @@ export default defineComponent({
store,
codeWorkingOutline,
ellipsisVerticalOutline,
helpCircleOutline,
pinOutline,
refreshOutline,
timeOutline,
Expand Down
Loading