ConfigHistory.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <script setup lang="ts">
  2. import type { ConfigBackup } from '@/api/config'
  3. import type { GetListResponse } from '@/api/curd'
  4. import type { Key } from 'ant-design-vue/es/_util/type'
  5. import config from '@/api/config'
  6. import StdPagination from '@/components/StdDesign/StdDataDisplay/StdPagination.vue'
  7. import { message } from 'ant-design-vue'
  8. import { datetime } from '../StdDesign/StdDataDisplay/StdTableTransformer'
  9. import DiffViewer from './DiffViewer.vue'
  10. // Define props for the component
  11. const props = defineProps<{
  12. filepath: string
  13. currentContent?: string
  14. }>()
  15. // Define modal props using defineModel with boolean type
  16. const visible = defineModel<boolean>('visible')
  17. const loading = ref(false)
  18. const records = ref<ConfigBackup[]>([])
  19. const showDiffViewer = ref(false)
  20. const pagination = ref({
  21. total: 0,
  22. per_page: 10,
  23. current_page: 1,
  24. total_pages: 0,
  25. })
  26. const selectedRowKeys = ref<Key[]>([])
  27. const selectedRecords = ref<ConfigBackup[]>([])
  28. // Watch for changes in modal visibility and filepath to fetch data
  29. watch(() => [visible.value, props.filepath], ([newVisible, newPath]) => {
  30. if (newVisible && newPath) {
  31. fetchHistoryList()
  32. }
  33. }, { immediate: true })
  34. // Table column definitions
  35. const columns = [
  36. {
  37. title: () => $gettext('Created At'),
  38. dataIndex: 'created_at',
  39. key: 'created_at',
  40. customRender: datetime,
  41. },
  42. ]
  43. // Fetch history records list
  44. async function fetchHistoryList() {
  45. if (!props.filepath)
  46. return
  47. loading.value = true
  48. try {
  49. const response = await config.get_history(props.filepath)
  50. const data = response as GetListResponse<ConfigBackup>
  51. records.value = data.data || []
  52. if (data.pagination) {
  53. pagination.value = data.pagination
  54. }
  55. }
  56. catch (error) {
  57. message.error($gettext('Failed to load history records'))
  58. console.error('Failed to fetch config backup list:', error)
  59. }
  60. finally {
  61. loading.value = false
  62. }
  63. }
  64. // Handle pagination changes
  65. function changePage(page: number, pageSize: number) {
  66. pagination.value.current_page = page
  67. pagination.value.per_page = pageSize
  68. fetchHistoryList()
  69. }
  70. // Row selection handler
  71. const rowSelection = computed(() => ({
  72. selectedRowKeys: selectedRowKeys.value,
  73. onChange: (keys: Key[], selectedRows: ConfigBackup[]) => {
  74. // Limit to maximum of two records
  75. if (keys.length > 2) {
  76. return
  77. }
  78. selectedRowKeys.value = keys
  79. selectedRecords.value = selectedRows
  80. },
  81. getCheckboxProps: (record: ConfigBackup) => ({
  82. disabled: selectedRowKeys.value.length >= 2 && !selectedRowKeys.value.includes(record.id as Key),
  83. }),
  84. }))
  85. // Compare selected records
  86. function compareSelected() {
  87. if (selectedRecords.value.length > 0) {
  88. showDiffViewer.value = true
  89. }
  90. }
  91. // Close modal and reset selection
  92. function handleClose() {
  93. showDiffViewer.value = false
  94. selectedRowKeys.value = []
  95. selectedRecords.value = []
  96. visible.value = false
  97. }
  98. // Dynamic button text based on selection count
  99. const compareButtonText = computed(() => {
  100. if (selectedRowKeys.value.length === 0)
  101. return $gettext('Compare')
  102. if (selectedRowKeys.value.length === 1)
  103. return $gettext('Compare with Current')
  104. return $gettext('Compare Selected')
  105. })
  106. </script>
  107. <template>
  108. <div>
  109. <AModal
  110. v-model:open="visible"
  111. :title="$gettext('Configuration History')"
  112. :footer="null"
  113. @cancel="handleClose"
  114. >
  115. <div class="history-container">
  116. <ATable
  117. :loading="loading"
  118. :columns="columns"
  119. :data-source="records"
  120. :row-selection="rowSelection"
  121. row-key="id"
  122. size="small"
  123. :pagination="false"
  124. />
  125. <div class="history-footer">
  126. <StdPagination
  127. :pagination="pagination"
  128. :loading="loading"
  129. @change="changePage"
  130. />
  131. <div class="actions">
  132. <AButton
  133. type="primary"
  134. :disabled="selectedRowKeys.length === 0"
  135. @click="compareSelected"
  136. >
  137. {{ compareButtonText }}
  138. </AButton>
  139. <AButton @click="handleClose">
  140. {{ $gettext('Close') }}
  141. </AButton>
  142. </div>
  143. </div>
  144. </div>
  145. </AModal>
  146. <DiffViewer
  147. v-model:visible="showDiffViewer"
  148. :records="selectedRecords"
  149. :current-content="currentContent"
  150. />
  151. </div>
  152. </template>
  153. <style lang="less" scoped>
  154. .history-container {
  155. display: flex;
  156. flex-direction: column;
  157. height: 100%;
  158. }
  159. .history-footer {
  160. display: flex;
  161. justify-content: space-between;
  162. align-items: center;
  163. margin-top: 16px;
  164. }
  165. .actions {
  166. display: flex;
  167. gap: 8px;
  168. }
  169. </style>