main
vue 237 lines 6.34 KB
Raw
1 <template>
2 <n-spin :show="loading" content-class="flex grow flex-col" class="flex flex-col overflow-hidden">
3 <div v-if="license" class="flex flex-col gap-4">
4 <CardKV v-if="!hideKey">
5 <template #key>
6 <span class="flex items-center gap-3">
7 <Icon :name="KeyIcon" :size="14" />
8 <span>Key</span>
9 </span>
10 </template>
11 <template #value>
12 {{ license.key }}
13 </template>
14 </CardKV>
15 <CardKV v-if="!hideFeatures">
16 <template #key>
17 <span class="flex items-center gap-3">
18 <Icon :name="FeaturesIcon" :size="14" />
19 <span>Features</span>
20 </span>
21 </template>
22 <template #value>
23 <div v-if="features.length" class="grid-auto-fit-200 grid gap-2">
24 <CardKV v-for="feature of features" :key="feature">
25 <template #value>
26 <span class="flex items-center gap-3">
27 <Icon :name="CheckIcon" :size="14" class="text-primary" />
28 <span>{{ feature }}</span>
29 </span>
30 </template>
31 </CardKV>
32 </div>
33 <template v-else>No feature enabled</template>
34 </template>
35 </CardKV>
36 <CardKV>
37 <template #key>
38 <span class="flex items-center gap-3">
39 <Icon :name="ExpiresIcon" :size="14" />
40 <span>Expires</span>
41 </span>
42 </template>
43 <template #value>
44 {{ expiresText }}
45 <span class="text-secondary">({{ periodText }})</span>
46 </template>
47 </CardKV>
48 <CardKV>
49 <template #key>
50 <span class="flex items-center gap-3">
51 <Icon :name="CustomerIcon" :size="14" />
52 <span>Customer</span>
53 </span>
54 </template>
55 <template #value>
56 <div class="flex flex-wrap gap-2">
57 <Badge v-for="(value, key) of license.customer" :key type="splitted" color="primary" fluid>
58 <template #label>
59 {{ sanitizeKey(key) }}
60 </template>
61 <template #value>
62 <template v-if="key === 'created'">
63 {{ formatDate(value, dFormats.datetime) }}
64 </template>
65 <template v-else>
66 {{ value ?? "-" }}
67 </template>
68 </template>
69 </Badge>
70 </div>
71 </template>
72 </CardKV>
73 <CardKV v-if="dockerCompose">
74 <template #key>
75 <span class="flex items-center gap-3">
76 <Icon :name="ConfigIcon" :size="14" />
77 <span>Docker Configuration</span>
78 </span>
79 </template>
80 <template #value>
81 <Markdown :source="dockerCompose" code-bg-transparent />
82 </template>
83 </CardKV>
84 </div>
85 </n-spin>
86 </template>
87
88 <script setup lang="ts">
89 import type { License, LicenseFeatures } from "@/types/license.d"
90 import _startCase from "lodash/startCase"
91 import { NSpin, useMessage } from "naive-ui"
92 import { computed, defineAsyncComponent, onBeforeMount, onMounted, ref, toRefs } from "vue"
93 import Api from "@/api"
94 import Badge from "@/components/common/Badge.vue"
95 import CardKV from "@/components/common/cards/CardKV.vue"
96 import Icon from "@/components/common/Icon.vue"
97 import { useSettingsStore } from "@/stores/settings"
98 import { formatDate } from "@/utils/format"
99
100 const props = defineProps<{
101 licenseData?: License
102 featuresData?: LicenseFeatures[]
103 hideKey?: boolean
104 hideFeatures?: boolean
105 }>()
106
107 const emit = defineEmits<{
108 (e: "licenseLoaded", value: License): void
109 (
110 e: "mounted",
111 value: {
112 reload: () => void
113 }
114 ): void
115 }>()
116
117 const Markdown = defineAsyncComponent(() => import("@/components/common/Markdown.vue"))
118
119 const { licenseData, featuresData, hideKey, hideFeatures } = toRefs(props)
120
121 const KeyIcon = "ph:key"
122 const ExpiresIcon = "ph:calendar-blank"
123 const CustomerIcon = "carbon:user"
124 const CheckIcon = "carbon:checkmark-outline"
125 const FeaturesIcon = "material-symbols:checklist"
126 const ConfigIcon = "carbon:settings"
127
128 const message = useMessage()
129 const loadingLicense = ref(false)
130 const loadingFeatures = ref(false)
131 const loadingDockerCompose = ref(false)
132 const dFormats = useSettingsStore().dateFormat
133
134 const licenseLoaded = ref<License | null>(null)
135 const featuresLoaded = ref<LicenseFeatures[]>([])
136 const dockerCompose = ref<string | null>(null)
137 const license = computed(() => licenseLoaded.value || licenseData?.value || null)
138 const features = computed(() => featuresLoaded.value || featuresData?.value || [])
139 const expiresText = computed(() => (license.value ? formatDate(license.value.expires, dFormats.datetime) : ""))
140 const periodText = computed(() =>
141 license.value ? `${license.value.period} Day${license.value.period === 1 ? "" : "s"}` : ""
142 )
143
144 const loading = computed(() => loadingLicense.value || loadingFeatures.value || loadingDockerCompose.value)
145
146 function getLicense() {
147 loadingLicense.value = true
148
149 Api.license
150 .verifyLicense()
151 .then(res => {
152 if (res.data.success) {
153 licenseLoaded.value = res.data?.license
154 emit("licenseLoaded", licenseLoaded.value)
155 } else {
156 message.warning(res.data?.message || "An error occurred. Please try again later.")
157 }
158 })
159 .catch(err => {
160 if (err.response.status !== 404) {
161 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
162 }
163 })
164 .finally(() => {
165 loadingLicense.value = false
166 })
167 }
168
169 function getLicenseFeatures() {
170 loadingFeatures.value = true
171
172 Api.license
173 .getLicenseFeatures()
174 .then(res => {
175 if (res.data.success) {
176 featuresLoaded.value = res.data?.features
177 } else {
178 message.warning(res.data?.message || "An error occurred. Please try again later.")
179 }
180 })
181 .catch(err => {
182 if (err.response.status !== 404) {
183 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
184 }
185 })
186 .finally(() => {
187 loadingFeatures.value = false
188 })
189 }
190
191 function retrieveDockerCompose() {
192 loadingDockerCompose.value = true
193
194 Api.license
195 .retrieveDockerCompose()
196 .then(res => {
197 if (res.data.success) {
198 dockerCompose.value = res.data?.docker_compose
199 } else {
200 message.warning(res.data?.message || "An error occurred. Please try again later.")
201 }
202 })
203 .catch(err => {
204 if (err.response.status !== 404) {
205 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
206 }
207 })
208 .finally(() => {
209 loadingDockerCompose.value = false
210 })
211 }
212
213 function load() {
214 if (!license.value) {
215 getLicense()
216 }
217 if (!hideFeatures.value && !features.value.length) {
218 getLicenseFeatures()
219 }
220
221 retrieveDockerCompose()
222 }
223
224 function sanitizeKey(text: string) {
225 return _startCase(text).toLowerCase()
226 }
227
228 onBeforeMount(() => {
229 load()
230 })
231
232 onMounted(() => {
233 emit("mounted", {
234 reload: load
235 })
236 })
237 </script>