refactor(change_cert): support select multiple certificates #437

This commit is contained in:
Jacky 2024-07-24 16:05:10 +08:00
parent 2b6e84ab62
commit ada02323d8
No known key found for this signature in database
GPG key ID: 215C21B10DF38B4D
22 changed files with 154 additions and 238 deletions

View file

@ -4,7 +4,6 @@ import 'ace-builds/src-noconflict/mode-nginx'
import ace from 'ace-builds'
import 'ace-builds/src-noconflict/theme-monokai'
import extSearchboxUrl from 'ace-builds/src-noconflict/ext-searchbox?url'
import { computed } from 'vue'
const props = defineProps<{
content?: string

View file

@ -2,7 +2,6 @@
import { CloseOutlined, DashboardOutlined, DatabaseOutlined } from '@ant-design/icons-vue'
import { storeToRefs } from 'pinia'
import { useRouter } from 'vue-router'
import { computed, watch } from 'vue'
import { useSettingsStore } from '@/pinia'
const settingsStore = useSettingsStore()

View file

@ -1,6 +1,5 @@
<script lang="ts" setup>
import type { Ref } from 'vue'
import { computed, inject } from 'vue'
import VPIconMoon from './icons/VPIconMoon.vue'
import VPIconSun from './icons/VPIconSun.vue'
import VPSwitch from '@/components/VPSwitch/VPSwitch.vue'

View file

@ -131,7 +131,7 @@ export const routes: RouteRecordRaw[] = [
{
path: 'list',
name: 'Certificates List',
component: () => import('@/views/certificate/Certificate.vue'),
component: () => import('@/views/certificate/CertificateList/Certificate.vue'),
meta: {
name: () => $gettext('Certificates List'),
},

View file

@ -0,0 +1,54 @@
<script setup lang="tsx">
import { CloudUploadOutlined, SafetyCertificateOutlined } from '@ant-design/icons-vue'
import certColumns from './certColumns'
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
import cert from '@/api/cert'
import WildcardCertificate from '@/views/certificate/WildcardCertificate.vue'
// DO NOT REMOVE THESE LINES
const no_server_name = computed(() => {
return false
})
provide('no_server_name', no_server_name)
const refWildcard = ref()
const refTable = ref()
</script>
<template>
<ACard :title="$gettext('Certificates')">
<template #extra>
<AButton
type="link"
@click="$router.push('/certificates/import')"
>
<CloudUploadOutlined />
{{ $gettext('Import') }}
</AButton>
<AButton
type="link"
@click="() => refWildcard.open()"
>
<SafetyCertificateOutlined />
{{ $gettext('Issue wildcard certificate') }}
</AButton>
</template>
<StdTable
ref="refTable"
:api="cert"
:columns="certColumns"
disable-view
@click-edit="id => $router.push(`/certificates/${id}`)"
/>
<WildcardCertificate
ref="refWildcard"
@issued="() => refTable.get_list()"
/>
</ACard>
</template>
<style lang="less" scoped>
</style>

View file

@ -1,20 +1,10 @@
<script setup lang="tsx">
import { Badge, Tag } from 'ant-design-vue'
import dayjs from 'dayjs'
import { CloudUploadOutlined, SafetyCertificateOutlined } from '@ant-design/icons-vue'
import { input } from '@/components/StdDesign/StdDataEntry'
import { Badge, Tag } from 'ant-design-vue'
import type { Column, JSXElements } from '@/components/StdDesign/types'
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { datetime, mask } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import cert from '@/api/cert'
import type { Column, JSXElements } from '@/components/StdDesign/types'
import type { Cert } from '@/api/cert'
import { AutoCertState, PrivateKeyTypeMask } from '@/constants'
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
import WildcardCertificate from '@/views/certificate/WildcardCertificate.vue'
function notShowInAutoCert(record: Cert) {
return record.auto_cert !== AutoCertState.Enable
}
import { input } from '@/components/StdDesign/StdDataEntry'
import { PrivateKeyTypeMask } from '@/constants'
const columns: Column[] = [{
title: () => $gettext('Name'),
@ -28,11 +18,9 @@ const columns: Column[] = [{
return h('div', text)
},
edit: {
search: {
type: input,
show: notShowInAutoCert,
},
search: true,
}, {
title: () => $gettext('Type'),
dataIndex: 'auto_cert',
@ -45,17 +33,17 @@ const columns: Column[] = [{
if (text === true || text === 1) {
template.push(<Tag bordered={false} color="processing">
{ managed }
</Tag>)
</Tag>)
}
else if (text === 2) {
template.push(<Tag bordered={false} color="success">
{ sync }
</Tag>)
</Tag>)
}
else {
template.push(<Tag bordered={false} color="purple">{
general }
</Tag>)
general }
</Tag>)
}
return h('div', template)
@ -68,29 +56,17 @@ const columns: Column[] = [{
customRender: mask(PrivateKeyTypeMask),
sortable: true,
pithy: true,
}, {
title: () => $gettext('SSL Certificate Path'),
dataIndex: 'ssl_certificate_path',
edit: {
type: input,
show: notShowInAutoCert,
},
hiddenInTable: true,
}, {
title: () => $gettext('SSL Certificate Key Path'),
dataIndex: 'ssl_certificate_key_path',
edit: {
type: input,
show: notShowInAutoCert,
},
hiddenInTable: true,
}, {
title: () => $gettext('Status'),
dataIndex: 'certificate_info',
pithy: true,
customRender: (args: customRender) => {
const template: JSXElements = []
const text = args.text?.not_before && args.text?.not_after && !dayjs().isBefore(args.text?.not_before) && !dayjs().isAfter(args.text?.not_after)
const text = args.text?.not_before
&& args.text?.not_after
&& !dayjs().isBefore(args.text?.not_before)
&& !dayjs().isAfter(args.text?.not_after)
if (text) {
template.push(<Badge status="success"/>)
@ -114,50 +90,4 @@ const columns: Column[] = [{
dataIndex: 'action',
}]
// DO NOT REMOVE THESE LINES
const no_server_name = computed(() => {
return false
})
provide('no_server_name', no_server_name)
const refWildcard = ref()
const refTable = ref()
</script>
<template>
<ACard :title="$gettext('Certificates')">
<template #extra>
<AButton
type="link"
@click="$router.push('/certificates/import')"
>
<CloudUploadOutlined />
{{ $gettext('Import') }}
</AButton>
<AButton
type="link"
@click="() => refWildcard.open()"
>
<SafetyCertificateOutlined />
{{ $gettext('Issue wildcard certificate') }}
</AButton>
</template>
<StdTable
ref="refTable"
:api="cert"
:columns="columns"
disabled-view
@click-edit="id => $router.push(`/certificates/${id}`)"
/>
<WildcardCertificate
ref="refWildcard"
@issued="() => refTable.get_list()"
/>
</ACard>
</template>
<style lang="less" scoped>
</style>
export default columns

View file

@ -1,6 +1,4 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
import config from '@/api/config'
import configColumns from '@/views/config/config'
@ -50,7 +48,7 @@ watch(route, () => {
:columns="configColumns"
disable-delete
disable_search
disabled-view
disable-view
row-key="name"
:get_params="get_params"
@click-edit="(r, row) => {

View file

@ -108,7 +108,7 @@ watch(route, () => {
:columns="columns"
row-key="name"
disable-delete
disabled-view
disable-view
@click-edit="r => $router.push({
path: `/domain/${r}`,
})"

View file

@ -1,8 +1,7 @@
<script setup lang="ts">
import { computed } from 'vue'
import CertInfo from '@/views/domain/cert/CertInfo.vue'
import IssueCert from '@/views/domain/cert/IssueCert.vue'
import ChangeCert from '@/views/domain/cert/ChangeCert.vue'
import ChangeCert from '@/views/domain/cert/components/ChangeCert/ChangeCert.vue'
import type { CertificateInfo } from '@/api/cert'
const props = defineProps<{
@ -12,10 +11,7 @@ const props = defineProps<{
certInfo?: CertificateInfo
}>()
const emit = defineEmits(['callback', 'update:enabled'])
function callback() {
emit('callback')
}
const emit = defineEmits(['update:enabled'])
const enabled = computed({
get() {
@ -42,7 +38,6 @@ const enabled = computed({
<IssueCert
v-model:enabled="enabled"
:config-name="configName"
@callback="callback"
/>
</div>
</template>

View file

@ -1,117 +0,0 @@
<script setup lang="tsx">
import { Badge } from 'ant-design-vue'
import type { ComputedRef, Ref } from 'vue'
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
import type { Cert } from '@/api/cert'
import cert from '@/api/cert'
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { input } from '@/components/StdDesign/StdDataEntry'
import type { NgxDirective } from '@/api/ngx'
import type { Column, JSXElements } from '@/components/StdDesign/types'
const current_server_directives = inject('current_server_directives') as ComputedRef<NgxDirective[]>
const directivesMap = inject('directivesMap') as Ref<Record<string, NgxDirective[]>>
const visible = ref(false)
const columns: Column[] = [{
title: () => $gettext('Name'),
dataIndex: 'name',
sortable: true,
pithy: true,
customRender: (args: customRender) => {
const { text, record: r } = args
if (!text)
return h('div', r.domain)
return h('div', text)
},
edit: {
type: input,
},
search: true,
}, {
title: () => $gettext('Auto Cert'),
dataIndex: 'auto_cert',
customRender: (args: customRender) => {
const template: JSXElements = []
const { text } = args
if (text === true || text > 0) {
template.push(<Badge status="success"/>)
template.push($gettext('Enabled'))
}
else {
template.push(<Badge status="warning"/>)
template.push($gettext('Disabled'))
}
return h('div', template)
},
sortable: true,
pithy: true,
}]
function open() {
visible.value = true
}
const records = ref([]) as Ref<Cert[]>
function ok() {
if (directivesMap.value.ssl_certificate?.[0]) {
directivesMap.value.ssl_certificate[0].params = records.value[0].ssl_certificate_path
}
else {
current_server_directives?.value.push({
directive: 'ssl_certificate',
params: records.value[0].ssl_certificate_path,
})
}
if (directivesMap.value.ssl_certificate_key?.[0]) {
directivesMap.value.ssl_certificate_key[0].params = records.value[0].ssl_certificate_key_path
}
else {
current_server_directives?.value.push({
directive: 'ssl_certificate_key',
params: records.value[0].ssl_certificate_key_path,
})
}
visible.value = false
}
const selectedKeyBuffer = ref({})
const computedSelectedKeys = computed({
get() {
return [selectedKeyBuffer.value]
},
set(v) {
selectedKeyBuffer.value = v
},
})
</script>
<template>
<div>
<AButton @click="open">
{{ $gettext('Change Certificate') }}
</AButton>
<AModal
v-model:open="visible"
:title="$gettext('Change Certificate')"
:mask="false"
@ok="ok"
>
<StdTable
v-model:selected-row-keys="computedSelectedKeys"
v-model:selected-rows="records"
:api="cert"
pithy
:columns="columns"
selection-type="radio"
/>
</AModal>
</div>
</template>
<style lang="less" scoped>
</style>

View file

@ -9,7 +9,7 @@ export interface Props {
const props = defineProps<Props>()
const emit = defineEmits(['callback', 'update:enabled'])
const emit = defineEmits(['update:enabled'])
const issuing_cert = ref(false)
const obtain_cert = ref()

View file

@ -0,0 +1,66 @@
<script setup lang="ts">
import type { Ref, WritableComputedRef } from 'vue'
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
import type { Cert } from '@/api/cert'
import cert from '@/api/cert'
import type { NgxDirective } from '@/api/ngx'
import certColumns from '@/views/certificate/CertificateList/certColumns'
const current_server_directives = inject('current_server_directives') as WritableComputedRef<NgxDirective[]>
const visible = ref(false)
function open() {
visible.value = true
}
const records = ref([]) as Ref<Cert[]>
const selectedKeys = ref([])
async function ok() {
// clear all ssl_certificate and ssl_certificate_key
current_server_directives.value
= current_server_directives.value
.filter(v => v.directive !== 'ssl_certificate' && v.directive !== 'ssl_certificate_key')
records.value.forEach(v => {
current_server_directives?.value.push({
directive: 'ssl_certificate',
params: v.ssl_certificate_path,
})
current_server_directives?.value.push({
directive: 'ssl_certificate_key',
params: v.ssl_certificate_key_path,
})
})
visible.value = false
}
</script>
<template>
<div>
<AButton @click="open">
{{ $gettext('Change Certificate') }}
</AButton>
<AModal
v-model:open="visible"
:title="$gettext('Change Certificate')"
:mask="false"
width="800px"
@ok="ok"
>
<StdTable
v-model:selected-row-keys="selectedKeys"
v-model:selected-rows="records"
:api="cert"
pithy
:columns="certColumns"
selection-type="checkbox"
/>
</AModal>
</div>
</template>
<style lang="less" scoped>
</style>

View file

@ -1,5 +1,4 @@
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { DeleteOutlined, HolderOutlined } from '@ant-design/icons-vue'
import Draggable from 'vuedraggable'
import CodeEditor from '@/components/CodeEditor'

View file

@ -65,24 +65,29 @@ function confirm_change_tls(status: CheckedType) {
})
}
const current_server_directives = computed(() => {
return ngx_config.servers?.[current_server_index.value]?.directives
const current_server_directives = computed({
get() {
return ngx_config.servers?.[current_server_index.value]?.directives
},
set(v) {
ngx_config.servers[current_server_index.value].directives = v
},
})
provide('current_server_directives', current_server_directives)
const directivesMap: ComputedRef<Record<string, NgxDirective[]>> = computed(() => {
const map: Record<string, NgxDirective[]> = {}
const record: Record<string, NgxDirective[]> = {}
current_server_directives.value?.forEach((v, k) => {
v.idx = k
if (map[v.directive])
map[v.directive].push(v)
if (record[v.directive])
record[v.directive].push(v)
else
map[v.directive] = [v]
record[v.directive] = [v]
})
return map
return record
})
// eslint-disable-next-line sonarjs/cognitive-complexity

View file

@ -1,7 +1,5 @@
<script setup lang="ts">
import { MoreOutlined, PlusOutlined } from '@ant-design/icons-vue'
import type { ComputedRef, Ref } from 'vue'
import { Modal } from 'ant-design-vue'
import LogEntry from '@/views/domain/ngx_conf/LogEntry.vue'
import ConfigTemplate from '@/views/domain/ngx_conf/config_template/ConfigTemplate.vue'
@ -21,8 +19,6 @@ withDefaults(defineProps<{
context: 'http',
})
const emit = defineEmits(['callback'])
const [modal, ContextHolder] = Modal.useModal()
const current_server_index = inject('current_server_index') as Ref<number>
@ -131,7 +127,6 @@ provide('ngx_directives', ngx_directives)
:config-name="ngx_config.name"
:cert-info="certInfo?.[k]"
:current-server-index="current_server_index"
@callback="emit('callback')"
/>
</template>

View file

@ -1,6 +1,5 @@
<script setup lang="ts">
import { Form, message } from 'ant-design-vue'
import { reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import { DatabaseOutlined, LockOutlined, MailOutlined, UserOutlined } from '@ant-design/icons-vue'
import SetLanguage from '@/components/SetLanguage/SetLanguage.vue'

View file

@ -1,7 +1,6 @@
<script setup lang="tsx">
import { message } from 'ant-design-vue'
import type { Ref } from 'vue'
import { inject } from 'vue'
import dayjs from 'dayjs'
import type { BannedIP } from '@/api/settings'
import setting from '@/api/settings'

View file

@ -1,5 +1,4 @@
<script setup lang="ts">
import { inject } from 'vue'
import Draggable from 'vuedraggable'
import { DeleteOutlined, HolderOutlined } from '@ant-design/icons-vue'
import type { Settings } from '@/views/preference/typedef'

View file

@ -1,5 +1,4 @@
<script setup lang="ts">
import { inject } from 'vue'
import type { Settings } from '@/views/preference/typedef'
const data: Settings = inject('data')!

View file

@ -1,5 +1,4 @@
<script setup lang="ts">
import { inject } from 'vue'
import type { Settings } from '@/views/preference/typedef'
const data: Settings = inject('data')!

View file

@ -1,5 +1,4 @@
<script setup lang="ts">
import { inject } from 'vue'
import type { Settings } from '@/views/preference/typedef'
const data: Settings = inject('data')!

View file

@ -129,7 +129,7 @@ function handleAddStream() {
:columns="columns"
row-key="name"
disable-delete
disabled-view
disable-view
@click-edit="r => $router.push({
path: `/stream/${r}`,
})"