@cryptotaxi247 / CoPilot / commits / 04e1626b

added delete integration feature

Davide Di Modica committed Jan 24, 2024 at 19:11 UTC 04e1626b6e5b25f5e9af79eba31c5d863d482c31
8 files changed +185 -63
.eslintrc.cjs
+2 -1
@@ -22,6 +22,7 @@ module.exports = {
22 ecmaVersion: "latest"
23 },
24 rules: {
25 - "vue/multi-word-component-names": "off"
25 + "vue/multi-word-component-names": "off",
26 + "vue/no-setup-props-destructure": "off"
27 }
28 }
package-lock.json
+4 -4
@@ -52,7 +52,7 @@
52 "@types/inquirer": "^9.0.7",
53 "@types/jsdom": "^21.1.6",
54 "@types/lodash": "^4.14.202",
55 - "@types/node": "^20.11.5",
55 + "@types/node": "^20.11.6",
56 "@types/validator": "^13.11.8",
57 "@vitejs/plugin-vue": "^5.0.3",
58 "@vitejs/plugin-vue-jsx": "^3.1.0",
@@ -2300,9 +2300,9 @@
2300 }
2301 },
2302 "node_modules/@types/node": {
2303 - "version": "20.11.5",
2304 - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz",
2305 - "integrity": "sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==",
2303 + "version": "20.11.6",
2304 + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.6.tgz",
2305 + "integrity": "sha512-+EOokTnksGVgip2PbYbr3xnR7kZigh4LbybAfBAw5BpnQ+FqBYUsvCEjYd70IXKlbohQ64mzEYmMtlWUY8q//Q==",
2306 "dev": true,
2307 "dependencies": {
2308 "undici-types": "~5.26.4"
package.json
+1 -1
@@ -75,7 +75,7 @@
75 "@types/inquirer": "^9.0.7",
76 "@types/jsdom": "^21.1.6",
77 "@types/lodash": "^4.14.202",
78 - "@types/node": "^20.11.5",
78 + "@types/node": "^20.11.6",
79 "@types/validator": "^13.11.8",
80 "@vitejs/plugin-vue": "^5.0.3",
81 "@vitejs/plugin-vue-jsx": "^3.1.0",
src/api/integrations.ts
+5
@@ -49,6 +49,11 @@ export default {
49 }
50 return HttpClient.post<FlaskBaseResponse>(`/integrations/create_integration`, payload)
51 },
52 + deleteIntegration(customerCode: string, integrationName: string) {
53 + return HttpClient.delete<FlaskBaseResponse>(`/integrations/delete_integration`, {
54 + data: { customer_code: customerCode, integration_name: integrationName }
55 + })
56 + },
57
58 office365Provision(customerCode: string, integrationName: string) {
59 return HttpClient.post<FlaskBaseResponse>(`/office365/provision`, {
src/components/customers/integrations/CustomerIntegrationActions.vue new
+128
@@ -0,0 +1,128 @@
1 +<template>
2 + <div class="alert-actions flex gap-4 justify-end">
3 + <n-button
4 + v-if="isOffice365 && !integration.deployed"
5 + :loading="loadingOffice365Provision"
6 + @click="office365Provision()"
7 + type="success"
8 + :size="size"
9 + secondary
10 + >
11 + <template #icon><Icon :name="DeployIcon"></Icon></template>
12 + Deploy
13 + </n-button>
14 +
15 + <n-button
16 + :size="size"
17 + type="error"
18 + ghost
19 + @click="handleDelete"
20 + :loading="loadingDelete"
21 + v-if="!hideDeleteButton"
22 + >
23 + <template #icon>
24 + <Icon :name="DeleteIcon" :size="15"></Icon>
25 + </template>
26 + Delete
27 + </n-button>
28 + </div>
29 +</template>
30 +
31 +<script setup lang="ts">
32 +import { NButton, useDialog, useMessage } from "naive-ui"
33 +import Icon from "@/components/common/Icon.vue"
34 +import Api from "@/api"
35 +import { computed, h, ref } from "vue"
36 +import { watch } from "vue"
37 +import type { CustomerIntegration } from "@/types/integrations"
38 +
39 +const emit = defineEmits<{
40 + (e: "startLoading"): void
41 + (e: "stopLoading"): void
42 + (e: "deployed"): void
43 + (e: "deleted"): void
44 +}>()
45 +
46 +const { integration, size } = defineProps<{
47 + integration: CustomerIntegration
48 + hideDeleteButton?: boolean
49 + size?: "tiny" | "small" | "medium" | "large"
50 +}>()
51 +
52 +const DeployIcon = "carbon:deploy"
53 +const DeleteIcon = "ph:trash"
54 +
55 +const dialog = useDialog()
56 +const message = useMessage()
57 +const loadingOffice365Provision = ref(false)
58 +const loadingDelete = ref(false)
59 +const loading = computed(() => loadingOffice365Provision.value || loadingDelete.value)
60 +
61 +const isOffice365 = computed(() => serviceName.value === "Office365")
62 +const serviceName = computed(() => integration.integration_service_name)
63 +const customerCode = computed(() => integration.customer_code)
64 +
65 +watch(loading, val => {
66 + emit(val ? "startLoading" : "startLoading")
67 +})
68 +
69 +function office365Provision() {
70 + loadingOffice365Provision.value = true
71 +
72 + Api.integrations
73 + .office365Provision(customerCode.value, serviceName.value)
74 + .then(res => {
75 + if (res.data.success) {
76 + emit("deployed")
77 + message.success(res.data?.message || "Customer integration successfully deployed.")
78 + } else {
79 + message.warning(res.data?.message || "An error occurred. Please try again later.")
80 + }
81 + })
82 + .catch(err => {
83 + message.error(err.response?.data?.message || "An error occurred. Please try again later.")
84 + })
85 + .finally(() => {
86 + loadingOffice365Provision.value = false
87 + })
88 +}
89 +
90 +function handleDelete() {
91 + dialog.warning({
92 + title: "Confirm",
93 + content: () =>
94 + h("div", {
95 + innerHTML: `Are you sure you want to delete the integration: <strong>${serviceName.value}</strong> ?`
96 + }),
97 + positiveText: "Yes I'm sure",
98 + negativeText: "Cancel",
99 + onPositiveClick: () => {
100 + deleteIntegration()
101 + },
102 + onNegativeClick: () => {
103 + message.info("Delete canceled")
104 + }
105 + })
106 +}
107 +
108 +function deleteIntegration() {
109 + loadingDelete.value = true
110 +
111 + Api.integrations
112 + .deleteIntegration(customerCode.value, serviceName.value)
113 + .then(res => {
114 + if (res.data.success) {
115 + emit("deleted")
116 + message.success(res.data?.message || "Customer integration successfully deleted.")
117 + } else {
118 + message.warning(res.data?.message || "An error occurred. Please try again later.")
119 + }
120 + })
121 + .catch(err => {
122 + message.error(err.response?.data?.message || "An error occurred. Please try again later.")
123 + })
124 + .finally(() => {
125 + loadingDelete.value = false
126 + })
127 +}
128 +</script>
src/components/customers/integrations/CustomerIntegrationItem.vue
+44 -56
@@ -3,7 +3,13 @@
3 <div class="px-4 py-3 flex flex-col gap-3">
4 <div class="header-box flex justify-between items-center">
5 <div class="id">#{{ integration.id }}</div>
6 - <div class="actions">
6 + <div class="actions flex gap-3">
7 + <Badge v-if="integration.deployed" type="active">
8 + <template #iconLeft>
9 + <Icon :name="DeployIcon" :size="13"></Icon>
10 + </template>
11 + <template #value>Deployed</template>
12 + </Badge>
13 <Badge type="cursor" @click.stop="showDetails = true">
14 <template #iconLeft>
15 <Icon :name="DetailsIcon" :size="14"></Icon>
@@ -16,28 +22,23 @@
22 <div class="content flex flex-col gap-1 grow">
23 <div class="title">{{ serviceName }}</div>
24 </div>
19 - <div class="actions-box">
20 - <template v-if="isOffice365">
21 - <n-button
22 - v-if="!integration.deployed"
23 - :loading="loadingOffice365Provision"
24 - @click="office365Provision()"
25 - type="success"
26 - size="small"
27 - secondary
28 - >
29 - <template #icon><Icon :name="DeployIcon"></Icon></template>
30 - Deploy Integration
31 - </n-button>
32 -
33 - <Badge type="active" v-else>
34 - <template #iconLeft>
35 - <Icon :name="DeployIcon" :size="13"></Icon>
36 - </template>
37 - <template #value>Deployed</template>
38 - </Badge>
39 - </template>
40 - </div>
25 + <CustomerIntegrationActions
26 + class="actions-box"
27 + :integration="integration"
28 + hideDeleteButton
29 + @deployed="emit('deployed')"
30 + @deleted="emit('deleted')"
31 + />
32 + </div>
33 + <div class="footer-box flex justify-between items-center gap-4">
34 + <CustomerIntegrationActions
35 + class="actions-box"
36 + :integration="integration"
37 + hideDeleteButton
38 + @deployed="emit('deployed')"
39 + @deleted="emit('deleted')"
40 + :size="'small'"
41 + />
42 </div>
43 </div>
44
@@ -63,11 +64,11 @@
64 import Icon from "@/components/common/Icon.vue"
65 import Badge from "@/components/common/Badge.vue"
66 import { computed, ref, toRefs } from "vue"
66 -import { NModal, NButton, useMessage } from "naive-ui"
67 +import { NModal } from "naive-ui"
68 import type { CustomerIntegration } from "@/types/integrations"
69 +import CustomerIntegrationActions from "./CustomerIntegrationActions.vue"
70 import KVCard from "@/components/common/KVCard.vue"
71 import _uniqBy from "lodash/uniqBy"
70 -import Api from "@/api"
72
73 const props = defineProps<{
74 integration: CustomerIntegration
@@ -77,17 +78,14 @@ const { integration, embedded } = toRefs(props)
78
79 const emit = defineEmits<{
80 (e: "deployed"): void
81 + (e: "deleted"): void
82 }>()
83
82 -const DetailsIcon = "carbon:settings-adjust"
84 const DeployIcon = "carbon:deploy"
85 +const DetailsIcon = "carbon:settings-adjust"
86
85 -const loadingOffice365Provision = ref(false)
86 -const message = useMessage()
87 const showDetails = ref(false)
88 const serviceName = computed(() => integration.value.integration_service_name)
89 -const customerCode = computed(() => integration.value.customer_code)
90 -
89 const authKeys = computed(() => {
90 const keys: { key: string; value: string }[] = []
91
@@ -102,29 +100,6 @@ const authKeys = computed(() => {
100
101 return _uniqBy(keys, "key")
102 })
105 -
106 -const isOffice365 = computed(() => serviceName.value === "Office365")
107 -
108 -function office365Provision() {
109 - loadingOffice365Provision.value = true
110 -
111 - Api.integrations
112 - .office365Provision(customerCode.value, serviceName.value)
113 - .then(res => {
114 - if (res.data.success) {
115 - emit("deployed")
116 - message.success(res.data?.message || "Customer integration successfully deployed.")
117 - } else {
118 - message.warning(res.data?.message || "An error occurred. Please try again later.")
119 - }
120 - })
121 - .catch(err => {
122 - message.error(err.response?.data?.message || "An error occurred. Please try again later.")
123 - })
124 - .finally(() => {
125 - loadingOffice365Provision.value = false
126 - })
127 -}
103 </script>
104
105 <style lang="scss" scoped>
@@ -148,10 +123,12 @@ function office365Provision() {
123 .content {
124 word-break: break-word;
125 }
126 + }
127
152 - .actions-box {
153 - min-height: 30px;
154 - }
128 + .footer-box {
129 + display: none;
130 + font-size: 13px;
131 + margin-top: 10px;
132 }
133
134 &.embedded {
@@ -161,5 +138,16 @@ function office365Provision() {
138 &:hover {
139 box-shadow: 0px 0px 0px 1px inset var(--primary-color);
140 }
141 +
142 + @container (max-width: 450px) {
143 + .main-box {
144 + .actions-box {
145 + display: none;
146 + }
147 + }
148 + .footer-box {
149 + display: flex;
150 + }
151 + }
152 }
153 </style>
src/components/customers/integrations/CustomerIntegrations.vue
+1
@@ -28,6 +28,7 @@
28 :key="integration.id"
29 :integration="integration"
30 @deployed="refreshList()"
31 + @deleted="refreshList()"
32 embedded
33 class="item-appear item-appear-bottom item-appear-005 mb-2"
34 />
vite.config.mts renamed
-1
@@ -1,5 +1,4 @@
1 import { fileURLToPath, URL } from "node:url"
2 -
2 import { defineConfig } from "vite"
3 import vue from "@vitejs/plugin-vue"
4 import vueJsx from "@vitejs/plugin-vue-jsx"