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"