SiteDuplicate.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. <script setup lang="ts">
  2. import domain from '@/api/domain'
  3. import NodeSelector from '@/components/NodeSelector/NodeSelector.vue'
  4. import gettext from '@/gettext'
  5. import { useSettingsStore } from '@/pinia'
  6. import { Form, message, notification } from 'ant-design-vue'
  7. const props = defineProps<{
  8. visible: boolean
  9. name: string
  10. }>()
  11. const emit = defineEmits(['update:visible', 'duplicated'])
  12. const settings = useSettingsStore()
  13. const show = computed({
  14. get() {
  15. return props.visible
  16. },
  17. set(v) {
  18. emit('update:visible', v)
  19. },
  20. })
  21. interface Model {
  22. name: string // site name
  23. target: number[] // ids of deploy targets
  24. }
  25. const modelRef: Model = reactive({ name: '', target: [] })
  26. const rulesRef = reactive({
  27. name: [
  28. {
  29. required: true,
  30. message: () => $gettext('Please input name, '
  31. + 'this will be used as the filename of the new configuration!'),
  32. },
  33. ],
  34. target: [
  35. {
  36. required: true,
  37. message: () => $gettext('Please select at least one node!'),
  38. },
  39. ],
  40. })
  41. const { validate, validateInfos, clearValidate } = Form.useForm(modelRef, rulesRef)
  42. const loading = ref(false)
  43. const node_map: Record<number, string> = reactive({})
  44. function onSubmit() {
  45. validate().then(async () => {
  46. loading.value = true
  47. modelRef.target.forEach(id => {
  48. if (id === 0) {
  49. domain.duplicate(props.name, { name: modelRef.name }).then(() => {
  50. message.success($gettext('Duplicate to local successfully'))
  51. show.value = false
  52. emit('duplicated')
  53. }).catch(e => {
  54. message.error($gettext(e?.message ?? 'Server error'))
  55. })
  56. }
  57. else {
  58. // get source content
  59. domain.get(props.name).then(r => {
  60. domain.save(modelRef.name, {
  61. name: modelRef.name,
  62. content: r.config,
  63. }, { headers: { 'X-Node-ID': id } }).then(() => {
  64. notification.success({
  65. message: $gettext('Duplicate successfully'),
  66. description:
  67. $gettext('Duplicate %{conf_name} to %{node_name} successfully', { conf_name: props.name, node_name: node_map[id] }),
  68. })
  69. }).catch(e => {
  70. notification.error({
  71. message: $gettext('Duplicate failed'),
  72. description: $gettext(e?.message ?? 'Server error'),
  73. })
  74. })
  75. if (r.enabled) {
  76. domain.enable(modelRef.name, { headers: { 'X-Node-ID': id } }).then(() => {
  77. notification.success({
  78. message: $gettext('Enabled successfully'),
  79. })
  80. })
  81. }
  82. })
  83. }
  84. })
  85. loading.value = false
  86. })
  87. }
  88. watch(() => props.visible, v => {
  89. if (v) {
  90. modelRef.name = props.name // default with source name
  91. modelRef.target = [0]
  92. nextTick(() => clearValidate())
  93. }
  94. })
  95. watch(() => gettext.current, () => {
  96. clearValidate()
  97. })
  98. </script>
  99. <template>
  100. <AModal
  101. v-model:open="show"
  102. :title="$gettext('Duplicate')"
  103. :confirm-loading="loading"
  104. :mask="false"
  105. @ok="onSubmit"
  106. >
  107. <AForm layout="vertical">
  108. <AFormItem
  109. :label="$gettext('Name')"
  110. v-bind="validateInfos.name"
  111. >
  112. <AInput v-model:value="modelRef.name" />
  113. </AFormItem>
  114. <AFormItem
  115. v-if="!settings.is_remote"
  116. :label="$gettext('Target')"
  117. v-bind="validateInfos.target"
  118. >
  119. <NodeSelector
  120. v-model:target="modelRef.target"
  121. v-model:map="node_map"
  122. />
  123. </AFormItem>
  124. </AForm>
  125. </AModal>
  126. </template>
  127. <style lang="less" scoped>
  128. </style>