|
@@ -3,13 +3,13 @@ import type { Ref } from 'vue'
|
|
|
import type { Cert } from '@/api/cert'
|
|
|
import { message } from 'ant-design-vue'
|
|
|
import cert from '@/api/cert'
|
|
|
-import AutoCertForm from '@/components/AutoCertForm'
|
|
|
-import CertInfo from '@/components/CertInfo'
|
|
|
-import CodeEditor from '@/components/CodeEditor'
|
|
|
-import FooterToolBar from '@/components/FooterToolbar'
|
|
|
-import NodeSelector from '@/components/NodeSelector'
|
|
|
import { AutoCertState } from '@/constants'
|
|
|
-import RenewCert from './components/RenewCert.vue'
|
|
|
+
|
|
|
+import AutoCertManagement from './components/AutoCertManagement.vue'
|
|
|
+import CertificateActions from './components/CertificateActions.vue'
|
|
|
+import CertificateBasicInfo from './components/CertificateBasicInfo.vue'
|
|
|
+import CertificateContentEditor from './components/CertificateContentEditor.vue'
|
|
|
+import CertificateDownload from './components/CertificateDownload.vue'
|
|
|
import { useCertStore } from './store'
|
|
|
|
|
|
const route = useRoute()
|
|
@@ -27,6 +27,10 @@ const notShowInAutoCert = computed(() => {
|
|
|
return data.value.auto_cert !== AutoCertState.Enable
|
|
|
})
|
|
|
|
|
|
+const isManaged = computed(() => {
|
|
|
+ return data.value.auto_cert === AutoCertState.Enable
|
|
|
+})
|
|
|
+
|
|
|
function init() {
|
|
|
if (id.value > 0) {
|
|
|
cert.getItem(id.value).then(r => {
|
|
@@ -55,6 +59,10 @@ async function save() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+function handleBack() {
|
|
|
+ router.push('/certificates/list')
|
|
|
+}
|
|
|
+
|
|
|
const log = computed(() => {
|
|
|
if (!data.value.log)
|
|
|
return ''
|
|
@@ -72,177 +80,50 @@ const log = computed(() => {
|
|
|
}
|
|
|
}).join('\n')
|
|
|
})
|
|
|
-
|
|
|
-const isManaged = computed(() => {
|
|
|
- return data.value.auto_cert === AutoCertState.Enable
|
|
|
-})
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
<ACard :title="id > 0 ? $gettext('Modify Certificate') : $gettext('Import Certificate')">
|
|
|
- <div
|
|
|
- v-if="isManaged"
|
|
|
- class="mb-4"
|
|
|
- >
|
|
|
- <div class="mb-2">
|
|
|
- <AAlert
|
|
|
- :message="$gettext('This certificate is managed by Nginx UI')"
|
|
|
- type="success"
|
|
|
- show-icon
|
|
|
- />
|
|
|
- </div>
|
|
|
- <div
|
|
|
- v-if="!data.filename"
|
|
|
- class="mt-4 mb-4"
|
|
|
- >
|
|
|
- <AAlert
|
|
|
- :message="$gettext('This Auto Cert item is invalid, please remove it.')"
|
|
|
- type="error"
|
|
|
- show-icon
|
|
|
- />
|
|
|
- </div>
|
|
|
- <div
|
|
|
- v-else-if="!data.domains"
|
|
|
- class="mt-4 mb-4"
|
|
|
- >
|
|
|
- <AAlert
|
|
|
- :message="$gettext('Domains list is empty, try to reopen Auto Cert for %{config}', { config: data.filename })"
|
|
|
- type="error"
|
|
|
- show-icon
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <ARow>
|
|
|
+ <ARow :gutter="[16, 16]">
|
|
|
<ACol
|
|
|
:sm="24"
|
|
|
- :md="12"
|
|
|
+ :lg="12"
|
|
|
>
|
|
|
- <AForm
|
|
|
- v-if="data.certificate_info"
|
|
|
- layout="vertical"
|
|
|
- >
|
|
|
- <AFormItem :label="$gettext('Certificate Status')">
|
|
|
- <CertInfo
|
|
|
- :cert="data.certificate_info"
|
|
|
- class="max-w-96"
|
|
|
- />
|
|
|
- </AFormItem>
|
|
|
- </AForm>
|
|
|
+ <!-- Auto Certificate Management -->
|
|
|
+ <AutoCertManagement
|
|
|
+ v-model:data="data"
|
|
|
+ :is-managed="isManaged"
|
|
|
+ @renewed="init"
|
|
|
+ />
|
|
|
|
|
|
- <template v-if="isManaged">
|
|
|
- <RenewCert
|
|
|
- :options="{
|
|
|
- name: data.name,
|
|
|
- domains: data.domains,
|
|
|
- key_type: data.key_type,
|
|
|
- challenge_method: data.challenge_method,
|
|
|
- dns_credential_id: data.dns_credential_id,
|
|
|
- acme_user_id: data.acme_user_id,
|
|
|
- revoke_old: data.revoke_old,
|
|
|
- }"
|
|
|
- @renewed="init"
|
|
|
+ <AForm layout="vertical">
|
|
|
+ <!-- Certificate Basic Information -->
|
|
|
+ <CertificateBasicInfo
|
|
|
+ v-model:data="data"
|
|
|
+ :errors="errors"
|
|
|
+ :is-managed="isManaged"
|
|
|
/>
|
|
|
|
|
|
- <AutoCertForm
|
|
|
- v-model:options="data"
|
|
|
- key-type-read-only
|
|
|
- style="max-width: 600px"
|
|
|
- hide-note
|
|
|
- />
|
|
|
- </template>
|
|
|
+ <!-- Download Certificate Files -->
|
|
|
+ <CertificateDownload :data="data" />
|
|
|
|
|
|
- <AForm
|
|
|
- layout="vertical"
|
|
|
- style="max-width: 600px"
|
|
|
- >
|
|
|
- <AFormItem
|
|
|
- :label="$gettext('Name')"
|
|
|
- :validate-status="errors.name ? 'error' : ''"
|
|
|
- :help="errors.name === 'required'
|
|
|
- ? $gettext('This field is required')
|
|
|
- : ''"
|
|
|
- >
|
|
|
- <p v-if="isManaged">
|
|
|
- {{ data.name }}
|
|
|
- </p>
|
|
|
- <AInput
|
|
|
- v-else
|
|
|
- v-model:value="data.name"
|
|
|
- />
|
|
|
- </AFormItem>
|
|
|
- <AFormItem
|
|
|
- :label="$gettext('SSL Certificate Path')"
|
|
|
- :validate-status="errors.ssl_certificate_path ? 'error' : ''"
|
|
|
- :help="errors.ssl_certificate_path === 'required' ? $gettext('This field is required')
|
|
|
- : errors.ssl_certificate_path === 'certificate_path'
|
|
|
- ? $gettext('The path exists, but the file is not a certificate') : ''"
|
|
|
- >
|
|
|
- <p v-if="isManaged">
|
|
|
- {{ data.ssl_certificate_path }}
|
|
|
- </p>
|
|
|
- <AInput
|
|
|
- v-else
|
|
|
- v-model:value="data.ssl_certificate_path"
|
|
|
- />
|
|
|
- </AFormItem>
|
|
|
- <AFormItem
|
|
|
- :label="$gettext('SSL Certificate Key Path')"
|
|
|
- :validate-status="errors.ssl_certificate_key_path ? 'error' : ''"
|
|
|
- :help="errors.ssl_certificate_key_path === 'required' ? $gettext('This field is required')
|
|
|
- : errors.ssl_certificate_key_path === 'privatekey_path'
|
|
|
- ? $gettext('The path exists, but the file is not a private key') : ''"
|
|
|
- >
|
|
|
- <p v-if="isManaged">
|
|
|
- {{ data.ssl_certificate_key_path }}
|
|
|
- </p>
|
|
|
- <AInput
|
|
|
- v-else
|
|
|
- v-model:value="data.ssl_certificate_key_path"
|
|
|
- />
|
|
|
- </AFormItem>
|
|
|
- <AFormItem :label="$gettext('Sync to')">
|
|
|
- <NodeSelector
|
|
|
- v-model:target="data.sync_node_ids"
|
|
|
- hidden-local
|
|
|
- />
|
|
|
- </AFormItem>
|
|
|
- <AFormItem
|
|
|
- :label="$gettext('SSL Certificate Content')"
|
|
|
- :validate-status="errors.ssl_certificate ? 'error' : ''"
|
|
|
- :help="errors.ssl_certificate === 'certificate'
|
|
|
- ? $gettext('The input is not a SSL Certificate') : ''"
|
|
|
- >
|
|
|
- <CodeEditor
|
|
|
- v-model:content="data.ssl_certificate"
|
|
|
- default-height="300px"
|
|
|
- :readonly="!notShowInAutoCert"
|
|
|
- disable-code-completion
|
|
|
- :placeholder="$gettext('Leave blank will not change anything')"
|
|
|
- />
|
|
|
- </AFormItem>
|
|
|
- <AFormItem
|
|
|
- :label="$gettext('SSL Certificate Key Content')"
|
|
|
- :validate-status="errors.ssl_certificate_key ? 'error' : ''"
|
|
|
- :help="errors.ssl_certificate_key === 'privatekey'
|
|
|
- ? $gettext('The input is not a SSL Certificate Key') : ''"
|
|
|
- >
|
|
|
- <CodeEditor
|
|
|
- v-model:content="data.ssl_certificate_key"
|
|
|
- default-height="300px"
|
|
|
- :readonly="!notShowInAutoCert"
|
|
|
- disable-code-completion
|
|
|
- :placeholder="$gettext('Leave blank will not change anything')"
|
|
|
- />
|
|
|
- </AFormItem>
|
|
|
+ <!-- Certificate Content Editor -->
|
|
|
+ <CertificateContentEditor
|
|
|
+ v-model:data="data"
|
|
|
+ :errors="errors"
|
|
|
+ :readonly="!notShowInAutoCert"
|
|
|
+ class="max-w-600px"
|
|
|
+ />
|
|
|
</AForm>
|
|
|
</ACol>
|
|
|
+
|
|
|
+ <!-- Log Column for Auto Cert -->
|
|
|
<ACol
|
|
|
v-if="data.auto_cert === AutoCertState.Enable"
|
|
|
:sm="24"
|
|
|
- :md="12"
|
|
|
+ :lg="12"
|
|
|
>
|
|
|
- <ACard :title="$gettext('Log')">
|
|
|
+ <ACard size="small" :title="$gettext('Log')">
|
|
|
<pre
|
|
|
v-dompurify-html="log"
|
|
|
class="log-container"
|
|
@@ -251,20 +132,11 @@ const isManaged = computed(() => {
|
|
|
</ACol>
|
|
|
</ARow>
|
|
|
|
|
|
- <FooterToolBar>
|
|
|
- <ASpace>
|
|
|
- <AButton @click="$router.push('/certificates/list')">
|
|
|
- {{ $gettext('Back') }}
|
|
|
- </AButton>
|
|
|
-
|
|
|
- <AButton
|
|
|
- type="primary"
|
|
|
- @click="save"
|
|
|
- >
|
|
|
- {{ $gettext('Save') }}
|
|
|
- </AButton>
|
|
|
- </ASpace>
|
|
|
- </FooterToolBar>
|
|
|
+ <!-- Certificate Actions -->
|
|
|
+ <CertificateActions
|
|
|
+ @save="save"
|
|
|
+ @back="handleBack"
|
|
|
+ />
|
|
|
</ACard>
|
|
|
</template>
|
|
|
|
|
@@ -277,4 +149,40 @@ const isManaged = computed(() => {
|
|
|
font-size: 12px;
|
|
|
line-height: 2;
|
|
|
}
|
|
|
+
|
|
|
+.code-editor-container {
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ .drag-overlay {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ background-color: rgba(24, 144, 255, 0.1);
|
|
|
+ border: 2px dashed #1890ff;
|
|
|
+ border-radius: 6px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ z-index: 10;
|
|
|
+
|
|
|
+ .drag-content {
|
|
|
+ text-align: center;
|
|
|
+ color: #1890ff;
|
|
|
+
|
|
|
+ .drag-icon {
|
|
|
+ font-size: 48px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+
|
|
|
+ p {
|
|
|
+ font-size: 16px;
|
|
|
+ margin: 0;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|