Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f320088
upgrade vulnerable dependencies to fix known security issues
FU-design Jun 16, 2025
1ce02fe
upgrade vulnerable dependencies to fix known security issues
FU-design Jun 16, 2025
6635ae8
Replace vite-plugin-icons with unplugin-icons
FU-design Jun 18, 2025
56cfbe9
refactor svg-icon component
FU-design Jun 18, 2025
f4e2752
eslint bugfix
FU-design Jun 18, 2025
bc364a0
eslint bugfix
FU-design Jun 18, 2025
204a3ed
bugfix
FU-design Jun 18, 2025
4e92ba8
format bugfix
FU-design Jun 18, 2025
9a4f276
fix ci
FU-design Jun 19, 2025
3d31dfb
fix ci
FU-design Jun 19, 2025
b016e98
fix ci
FU-design Jun 19, 2025
8cc2e3f
add unit tests for filter-form
FU-design Jun 19, 2025
691c351
add lost license
FU-design Jun 19, 2025
30c598d
fix header menu not updating when navigating from AI Assistant to Sys…
FU-design Jun 19, 2025
f7d5b4a
bugfix
FU-design Jun 19, 2025
47135c5
disable Complete button until checkWorkflow is done
FU-design Jun 19, 2025
ec3a794
bugfix
FU-design Jun 19, 2025
d1fe4fb
merge code
FU-design Jun 24, 2025
b319f1e
add use-chart composable
FU-design Jun 24, 2025
5267180
change menu storage structure
FU-design Jun 26, 2025
c862169
merge code
FU-design Jun 26, 2025
df078f2
bugfix
FU-design Jun 26, 2025
aba8e8b
fix broken layout on login page
FU-design Jun 26, 2025
4a237dc
bugfix
FU-design Jun 26, 2025
55379b5
add hostname duplication check on host addition
FU-design Jul 2, 2025
92c6125
merge code
FU-design Jul 2, 2025
c39d552
fix router skip
FU-design Jul 10, 2025
88ef0cf
merge code
FU-design Jul 10, 2025
68ea724
Merge remote-tracking branch 'origin/main' into bigtop-4454
FU-design Jul 10, 2025
c36c5a2
code review
FU-design Jul 10, 2025
3abee26
bug fix
FU-design Jul 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions bigtop-manager-ui/src/assets/images/svg/warn.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion bigtop-manager-ui/src/components/common/svg-icon/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@
stop: IconSvgStop,
success: IconSvgSuccess,
unknown: IconSvgUnknown,
'carbon-language': IconSvgCarbonLanguage
'carbon-language': IconSvgCarbonLanguage,
warn: IconSvgWarn
}

const props = defineProps<{ name: string | undefined }>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,34 @@
-->

<script setup lang="ts">
import { TableColumnType } from 'ant-design-vue'
import { PaginationProps, TableColumnType } from 'ant-design-vue'
import { computed, reactive, ref, watch } from 'vue'
import { generateRandomId } from '@/utils/tools'
import { useI18n } from 'vue-i18n'

import useBaseTable from '@/composables/use-base-table'
import HostCreate from '@/pages/cluster-manage/hosts/create.vue'
import HostCreate from '@/components/create-host/create.vue'

import type { FilterConfirmProps, FilterResetProps } from 'ant-design-vue/es/table/interface'
import type { GroupItem } from '@/components/common/button-group/types'
import type { HostReq } from '@/api/command/types'

type Key = string | number
type conflictItem = HostReq & { strategy: 'override' | 'keep' }

interface TableState {
selectedRowKeys: Key[]
searchText: string
searchedColumn: string
}

const { t } = useI18n()
const props = defineProps<{ stepData: HostReq[] }>()
const emits = defineEmits(['updateData'])
const data = ref<HostReq[]>([])

const searchInputRef = ref()
const hostCreateRef = ref<InstanceType<typeof HostCreate> | null>(null)

const state = reactive<TableState>({
searchText: '',
searchedColumn: '',
Expand Down Expand Up @@ -86,43 +92,19 @@
}
])

const { loading, dataSource, paginationProps, onChange } = useBaseTable({
columns: columns.value,
rows: data.value
})
const { loading, dataSource, paginationProps, onChange } = useBaseTable<HostReq>({ columns: columns.value, rows: [] })

const operations = computed((): GroupItem[] => [
{
text: 'edit',
clickEvent: (_item, args) => editHost(args)
},
{
text: 'remove',
danger: true,
clickEvent: (_item, args) => deleteHost(args)
}
{ text: 'edit', clickEvent: (_item, args) => updateHost('EDIT', args) },
{ text: 'remove', danger: true, clickEvent: (_item, args) => deleteHost(args) }
])

watch(
() => props.stepData,
(val) => {
dataSource.value = val
},
{
immediate: true
}
)

const isContain = (source: string, target: string): boolean => {
return source.toString().toLowerCase().includes(target.toLowerCase())
}

const onFilterDropdownOpenChange = (visible: boolean) => {
if (visible) {
setTimeout(() => {
searchInputRef.value.focus()
}, 100)
}
visible && setTimeout(searchInputRef.value.focus(), 100)
}

const onSelectChange = (selectedRowKeys: Key[]) => {
Expand All @@ -140,60 +122,108 @@
state.searchText = ''
}

const addHost = () => {
hostCreateRef.value?.handleOpen('ADD')
const updateHost = (type: 'ADD' | 'EDIT', row?: HostReq) => {
hostCreateRef.value?.handleOpen(type, row)
}

const editHost = (row: HostReq) => {
hostCreateRef.value?.handleOpen('EDIT', row)
const deleteHost = (row?: HostReq) => {
if (row?.hostnames) {
dataSource.value = dataSource.value?.filter((v) => row!.key !== v.key)
} else {
dataSource.value = dataSource.value?.filter((v) => !state.selectedRowKeys.includes(v.key)) || []
}
updateStepData()
}

const updateStepData = () => {
const res = dataSource.value.map((v) => {
return {
...v,
hostnames: [v.hostname]
}
})
Object.assign(paginationProps.value as PaginationProps, { total: dataSource.value.length })
const res = dataSource.value.map((v) => ({ ...v, hostnames: [v.hostname] }))
emits('updateData', res)
}

const addHostSuccess = (type: 'ADD' | 'EDIT', item: HostReq) => {
/**
* Merges duplicate hostnames based on strategy.
* @param list
* @param duplicateHosts
* @param config host config
*/
const mergeByStrategy = (list: HostReq[], duplicateHosts: conflictItem[], config: HostReq): HostReq[] => {
const strategyMap = new Map<string, conflictItem>()
duplicateHosts.forEach((s) => strategyMap.set(s.hostname, s))

const existingHostnames = new Set<string>()
const mainPart: HostReq[] = []
const prependPart: HostReq[] = []

for (const item of list) {
existingHostnames.add(item.hostname)
const strategy = strategyMap.get(item.hostname)

if (!strategy) {
mainPart.push(item)
} else if (strategy.strategy === 'override') {
mainPart.push(generateNewHostItem(item.hostname, config))
} else {
mainPart.push(item)
}
}

for (const s of duplicateHosts) {
if (!existingHostnames.has(s.hostname)) {
prependPart.push(generateNewHostItem(s.hostname, config))
}
}

return [...prependPart, ...mainPart]
}

const generateNewHostItem = (hostname: string, config: HostReq): HostReq => ({
...config,
key: generateRandomId(),
hostname: hostname,
status: 'UNKNOWN'
})

/**
* Handles successful addition or editing of hosts.
*/
const addHostSuccess = (type: 'ADD' | 'EDIT', item: HostReq, duplicateHosts: any) => {
if (type === 'ADD') {
const items = item.hostnames?.map((v) => {
return {
...item,
key: generateRandomId(),
hostname: v,
status: 'UNKNOWN'
}
}) as HostReq[]
dataSource.value?.unshift(...items)
} else {
if (duplicateHosts.length > 0) {
dataSource.value = mergeByStrategy(dataSource.value, duplicateHosts, item)
} else {
const items = item.hostnames?.map((v) => generateNewHostItem(v, item)) as HostReq[]
dataSource.value?.unshift(...items)
}
}

if (type === 'EDIT') {
const index = dataSource.value.findIndex((data) => data.key === item.key)

if (index !== -1) {
dataSource.value[index] = item
}
}

updateStepData()
}

const deleteHost = (row?: HostReq) => {
if (!row?.key) {
state.selectedRowKeys.length > 0 &&
(dataSource.value = dataSource.value?.filter((v) => !state.selectedRowKeys.includes(v.key)) || [])
} else {
dataSource.value = dataSource.value?.filter((v) => row.key !== v.key)
watch(
() => props.stepData,
(val) => {
dataSource.value = JSON.parse(JSON.stringify(val))
},
{
immediate: true
}
updateStepData()
}
)
</script>

<template>
<div class="host-config">
<header>
<a-space :size="16">
<a-button type="primary" @click="addHost">{{ $t('cluster.add_host') }}</a-button>
<a-button type="primary" @click="updateHost('ADD')">{{ $t('cluster.add_host') }}</a-button>
<a-button type="primary" danger @click="deleteHost">{{ $t('common.bulk_remove') }}</a-button>
</a-space>
</header>
Expand Down Expand Up @@ -246,7 +276,7 @@
</template>
</template>
</a-table>
<host-create ref="hostCreateRef" @on-ok="addHostSuccess" />
<host-create ref="hostCreateRef" :current-hosts="dataSource" @on-ok="addHostSuccess" />
</div>
</template>

Expand Down
Loading
Loading