CertificateEditor.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. <script setup lang="ts">
  2. import { useGettext } from 'vue3-gettext'
  3. import type { Ref } from 'vue'
  4. import { message } from 'ant-design-vue'
  5. import { AutoCertState } from '@/constants'
  6. import CertInfo from '@/views/domain/cert/CertInfo.vue'
  7. import AutoCertStepOne from '@/views/domain/cert/components/AutoCertStepOne.vue'
  8. import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
  9. import type { Cert } from '@/api/cert'
  10. import cert from '@/api/cert'
  11. import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
  12. import RenewCert from '@/views/certificate/RenewCert.vue'
  13. const { $gettext } = useGettext()
  14. const route = useRoute()
  15. const id = computed(() => {
  16. return Number.parseInt(route.params.id as string)
  17. })
  18. const data = ref({}) as Ref<Cert>
  19. const notShowInAutoCert = computed(() => {
  20. return data.value.auto_cert !== AutoCertState.Enable
  21. })
  22. function init() {
  23. if (id.value > 0) {
  24. cert.get(id.value).then(r => {
  25. data.value = r
  26. })
  27. }
  28. else {
  29. data.value = {} as Cert
  30. }
  31. }
  32. onMounted(() => {
  33. init()
  34. })
  35. const router = useRouter()
  36. const errors = ref({}) as Ref<Record<string, string>>
  37. function save() {
  38. cert.save(data.value.id, data.value).then(r => {
  39. data.value = r
  40. message.success($gettext('Save successfully'))
  41. router.push(`/certificates/${r.id}`)
  42. errors.value = {}
  43. }).catch(e => {
  44. errors.value = e.errors
  45. message.error($gettext(e?.message ?? 'Server error'))
  46. })
  47. }
  48. provide('data', data)
  49. provide('no_server_name', computed(() => {
  50. return false
  51. }))
  52. const log = computed(() => {
  53. const logs = data.value.log?.split('\n')
  54. logs.forEach((line, idx, lines) => {
  55. const regex = /\[Nginx UI\] (.*)/
  56. const matches = line.match(regex)
  57. if (matches && matches.length > 1) {
  58. const extractedText = matches[1]
  59. lines[idx] = line.replaceAll(extractedText, $gettext(extractedText))
  60. }
  61. })
  62. return logs.join('\n')
  63. })
  64. const isManaged = computed(() => {
  65. return data.value.auto_cert === AutoCertState.Enable
  66. })
  67. </script>
  68. <template>
  69. <ACard :title="id > 0 ? $gettext('Modify Certificate') : $gettext('Import Certificate')">
  70. <div
  71. v-if="isManaged"
  72. class="mb-4"
  73. >
  74. <div class="mb-2">
  75. <AAlert
  76. :message="$gettext('This certificate is managed by Nginx UI')"
  77. type="success"
  78. show-icon
  79. />
  80. </div>
  81. <div
  82. v-if="!data.filename"
  83. class="mt-4 mb-4"
  84. >
  85. <AAlert
  86. :message="$gettext('This Auto Cert item is invalid, please remove it.')"
  87. type="error"
  88. show-icon
  89. />
  90. </div>
  91. <div
  92. v-else-if="!data.domains"
  93. class="mt-4 mb-4"
  94. >
  95. <AAlert
  96. :message="$gettext('Domains list is empty, try to reopen Auto Cert for %{config}', { config: data.filename })"
  97. type="error"
  98. show-icon
  99. />
  100. </div>
  101. </div>
  102. <ARow>
  103. <ACol
  104. :sm="24"
  105. :md="12"
  106. >
  107. <AForm
  108. v-if="data.certificate_info"
  109. layout="vertical"
  110. >
  111. <AFormItem :label="$gettext('Certificate Status')">
  112. <CertInfo :cert="data.certificate_info" />
  113. </AFormItem>
  114. </AForm>
  115. <template v-if="isManaged">
  116. <RenewCert @renewed="init" />
  117. <AutoCertStepOne
  118. style="max-width: 600px"
  119. hide-note
  120. />
  121. </template>
  122. <AForm
  123. layout="vertical"
  124. style="max-width: 600px"
  125. >
  126. <AFormItem
  127. :label="$gettext('Name')"
  128. :validate-status="errors.name ? 'error' : ''"
  129. :help="errors.name === 'required'
  130. ? $gettext('This field is required')
  131. : ''"
  132. >
  133. <p v-if="isManaged">
  134. {{ data.name }}
  135. </p>
  136. <AInput
  137. v-else
  138. v-model:value="data.name"
  139. />
  140. </AFormItem>
  141. <AFormItem
  142. :label="$gettext('SSL Certificate Path')"
  143. :validate-status="errors.ssl_certificate_path ? 'error' : ''"
  144. :help="errors.ssl_certificate_path === 'required' ? $gettext('This field is required')
  145. : errors.ssl_certificate_path === 'publickey_path'
  146. ? $gettext('The path exists, but the file is not a public key') : ''"
  147. >
  148. <p v-if="isManaged">
  149. {{ data.ssl_certificate_path }}
  150. </p>
  151. <AInput
  152. v-else
  153. v-model:value="data.ssl_certificate_path"
  154. />
  155. </AFormItem>
  156. <AFormItem
  157. :label="$gettext('SSL Certificate Key Path')"
  158. :validate-status="errors.ssl_certificate_key_path ? 'error' : ''"
  159. :help="errors.ssl_certificate_key_path === 'required' ? $gettext('This field is required')
  160. : errors.ssl_certificate_key_path === 'privatekey_path'
  161. ? $gettext('The path exists, but the file is not a private key') : ''"
  162. >
  163. <p v-if="isManaged">
  164. {{ data.ssl_certificate_key_path }}
  165. </p>
  166. <AInput
  167. v-else
  168. v-model:value="data.ssl_certificate_key_path"
  169. />
  170. </AFormItem>
  171. <AFormItem
  172. :label="$gettext('SSL Certificate Content')"
  173. :validate-status="errors.ssl_certificate ? 'error' : ''"
  174. :help="errors.ssl_certificate === 'publickey'
  175. ? $gettext('The input is not a SSL Certificate') : ''"
  176. >
  177. <CodeEditor
  178. v-model:content="data.ssl_certificate"
  179. default-height="300px"
  180. :readonly="!notShowInAutoCert"
  181. :placeholder="$gettext('Leave blank will not change anything')"
  182. />
  183. </AFormItem>
  184. <AFormItem
  185. :label="$gettext('SSL Certificate Key Content')"
  186. :validate-status="errors.ssl_certificate_key ? 'error' : ''"
  187. :help="errors.ssl_certificate_key === 'privatekey'
  188. ? $gettext('The input is not a SSL Certificate Key') : ''"
  189. >
  190. <CodeEditor
  191. v-model:content="data.ssl_certificate_key"
  192. default-height="300px"
  193. :readonly="!notShowInAutoCert"
  194. :placeholder="$gettext('Leave blank will not change anything')"
  195. />
  196. </AFormItem>
  197. </AForm>
  198. </ACol>
  199. <ACol
  200. v-if="data.auto_cert === AutoCertState.Enable"
  201. :sm="24"
  202. :md="12"
  203. >
  204. <ACard :title="$gettext('Log')">
  205. <pre
  206. class="log-container"
  207. v-html="log"
  208. />
  209. </ACard>
  210. </ACol>
  211. </ARow>
  212. <FooterToolBar>
  213. <ASpace>
  214. <AButton @click="$router.push('/certificates/list')">
  215. {{ $gettext('Back') }}
  216. </AButton>
  217. <AButton
  218. type="primary"
  219. @click="save"
  220. >
  221. {{ $gettext('Save') }}
  222. </AButton>
  223. </ASpace>
  224. </FooterToolBar>
  225. </ACard>
  226. </template>
  227. <style scoped lang="less">
  228. .log-container {
  229. overflow: scroll;
  230. padding: 5px;
  231. margin-bottom: 0;
  232. font-size: 12px;
  233. line-height: 2;
  234. }
  235. </style>