mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2025-12-13 21:21:44 +00:00
292 lines
7.7 KiB
Vue
292 lines
7.7 KiB
Vue
<script>
|
|
import Loading from '@shell/components/Loading';
|
|
import ResourceTable from '@shell/components/ResourceTable';
|
|
import Masthead from '@shell/components/ResourceList/Masthead';
|
|
import { allHash } from '@shell/utils/promise';
|
|
import { STATE, AGE, NAME } from '@shell/config/table-headers';
|
|
import { mapPref, GROUP_RESOURCES } from '@shell/store/prefs';
|
|
import { NODE } from '@shell/config/types';
|
|
import { PRODUCT_NAME as HARVESTER_PRODUCT } from '../config/harvester';
|
|
import { CLUSTER_NETWORK } from '../config/query-params';
|
|
import { HCI } from '../types';
|
|
|
|
export default {
|
|
name: 'ListHarvesterVLANConfigs',
|
|
|
|
components: {
|
|
ResourceTable,
|
|
Loading,
|
|
Masthead,
|
|
},
|
|
|
|
async fetch() {
|
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
|
|
await allHash({
|
|
configs: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.VLAN_CONFIG }),
|
|
clusterNetworks: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.CLUSTER_NETWORK }),
|
|
vlanStatuses: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.VLAN_STATUS }),
|
|
nodes: this.$store.dispatch(`${ inStore }/findAll`, { type: NODE })
|
|
});
|
|
},
|
|
|
|
data() {
|
|
return { HCI };
|
|
},
|
|
|
|
computed: {
|
|
groupPreference: mapPref(GROUP_RESOURCES),
|
|
headers() {
|
|
return [
|
|
STATE,
|
|
{
|
|
...NAME,
|
|
width: 300,
|
|
},
|
|
{
|
|
name: 'type',
|
|
labelKey: 'tableHeaders.type',
|
|
value: 'typeDisplay',
|
|
getValue: (row) => row.typeDisplay,
|
|
sort: ['typeDisplay'],
|
|
},
|
|
AGE,
|
|
];
|
|
},
|
|
|
|
rows() {
|
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
|
|
const configs = this.$store.getters[`${ inStore }/all`](HCI.VLAN_CONFIG);
|
|
|
|
return configs;
|
|
},
|
|
|
|
vlanConfigSchema() {
|
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
|
|
return this.$store.getters[`${ inStore }/schemaFor`](HCI.VLAN_CONFIG);
|
|
},
|
|
|
|
clusterNetworkSchema() {
|
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
|
|
return this.$store.getters[`${ inStore }/schemaFor`](HCI.CLUSTER_NETWORK);
|
|
},
|
|
|
|
isClusterNetworkCreatable() {
|
|
return (this.clusterNetworkSchema?.collectionMethods || []).includes('POST');
|
|
},
|
|
|
|
createClusterNetworkLocation() {
|
|
const location = {
|
|
name: `${ HARVESTER_PRODUCT }-c-cluster-resource-create`,
|
|
params: {
|
|
product: HARVESTER_PRODUCT,
|
|
resource: HCI.CLUSTER_NETWORK,
|
|
},
|
|
};
|
|
|
|
return location;
|
|
},
|
|
|
|
clusterNetworkWithoutConfigs() {
|
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
|
|
const clusterNetworks = this.$store.getters[`${ inStore }/all`](HCI.CLUSTER_NETWORK);
|
|
|
|
const out = clusterNetworks.map((network) => {
|
|
const hasChild = !!this.rows.find((config) => config?.spec?.clusterNetwork === network.id);
|
|
|
|
return {
|
|
...network,
|
|
hasChild
|
|
};
|
|
});
|
|
|
|
return out;
|
|
},
|
|
|
|
rowsWithFakeClusterNetworks() {
|
|
const fakeRows = this.clusterNetworkWithoutConfigs.map((network) => {
|
|
return {
|
|
groupByLabel: network.id,
|
|
isFake: true,
|
|
mainRowKey: network.id,
|
|
nameDisplay: network.id,
|
|
groupByClusterNetwork: network.id,
|
|
availableActions: []
|
|
};
|
|
});
|
|
|
|
return [...this.rows, ...fakeRows];
|
|
},
|
|
},
|
|
|
|
methods: {
|
|
showClusterNetworkActionButton(group) {
|
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
const clusterNetwork = group.key;
|
|
|
|
const resource = this.$store.getters[`${ inStore }/byId`](HCI.CLUSTER_NETWORK, clusterNetwork);
|
|
|
|
return !!resource;
|
|
},
|
|
|
|
showClusterNetworkAction(event, group) {
|
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
const clusterNetwork = group.key;
|
|
|
|
const resource = this.$store.getters[`${ inStore }/byId`](HCI.CLUSTER_NETWORK, clusterNetwork);
|
|
|
|
this.$store.commit(`action-menu/show`, {
|
|
resources: [resource],
|
|
elem: event.target
|
|
});
|
|
},
|
|
|
|
createVlanConfigLocation(group) {
|
|
const clusterNetwork = group.key;
|
|
|
|
const location = {
|
|
name: `${ HARVESTER_PRODUCT }-c-cluster-resource-create`,
|
|
params: {
|
|
product: HARVESTER_PRODUCT,
|
|
resource: HCI.VLAN_CONFIG,
|
|
},
|
|
};
|
|
|
|
location.query = { [CLUSTER_NETWORK]: clusterNetwork };
|
|
|
|
return location;
|
|
},
|
|
|
|
slotName(clusterNetwork) {
|
|
return `main-row:${ clusterNetwork }`;
|
|
},
|
|
|
|
groupLabel(group) {
|
|
const row = group.rows[0];
|
|
|
|
if (row.isFake) {
|
|
return `${ this.t('harvester.network.clusterNetwork.label') }: ${ row.nameDisplay }`;
|
|
}
|
|
|
|
return `${ this.t('harvester.network.clusterNetwork.label') }: ${ group.key }`;
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<Loading v-if="$fetchState.pending" />
|
|
<div v-else>
|
|
<Masthead
|
|
:schema="clusterNetworkSchema"
|
|
:type-display="t('harvester.clusterNetwork.title')"
|
|
:resource="HCI.CLUSTER_NETWORK"
|
|
:create-location="createClusterNetworkLocation"
|
|
:create-button-label="t('harvester.clusterNetwork.create.button.label')"
|
|
/>
|
|
<ResourceTable
|
|
:rows="rowsWithFakeClusterNetworks"
|
|
:headers="headers"
|
|
:groupable="true"
|
|
:schema="vlanConfigSchema"
|
|
group-by="groupByClusterNetwork"
|
|
>
|
|
<template #header-middle>
|
|
<div />
|
|
</template>
|
|
<template #group-by="{group}">
|
|
<div class="group-bar">
|
|
<div class="group-tab">
|
|
<span>
|
|
{{ groupLabel(group) }}
|
|
</span>
|
|
</div>
|
|
<div class="right">
|
|
<router-link
|
|
v-if="isClusterNetworkCreatable && group.key !== 'mgmt'"
|
|
class="btn btn-sm role-secondary mr-5"
|
|
:to="createVlanConfigLocation(group)"
|
|
>
|
|
{{ t('harvester.vlanConfig.createNetworkConfig') }}
|
|
</router-link>
|
|
<button
|
|
type="button"
|
|
class="btn btn-sm role-multi-action actions mr-10"
|
|
:class="{invisible: !showClusterNetworkActionButton(group)}"
|
|
@click="showClusterNetworkAction($event, group)"
|
|
>
|
|
<i class="icon icon-actions" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template
|
|
v-for="(clusterNetwork, i) in clusterNetworkWithoutConfigs"
|
|
:key="i"
|
|
v-slot:[slotName(clusterNetwork.id)]
|
|
>
|
|
<tr
|
|
v-show="!clusterNetwork.hasChild"
|
|
:key="clusterNetwork.id"
|
|
class="main-row"
|
|
>
|
|
<td
|
|
class="empty text-center"
|
|
colspan="12"
|
|
>
|
|
{{ clusterNetwork.id === 'mgmt' ? t('harvester.clusterNetwork.mgmt') : t('harvester.clusterNetwork.clusterNetwork') }}
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
</ResourceTable>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.group-bar {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
|
|
.right {
|
|
margin-top: 5px;
|
|
margin-bottom: 3px;
|
|
}
|
|
|
|
.group-tab {
|
|
&, &::after {
|
|
height: 50px;
|
|
}
|
|
|
|
&::after {
|
|
right: -20px;
|
|
}
|
|
|
|
SPAN {
|
|
color: var(--body-text) !important;
|
|
}
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<style lang="scss">
|
|
.col-link-detail {
|
|
// Avoid 'Create Network Config' button to overlap the namespace tab when resize table to min length
|
|
min-width: 200px;
|
|
}
|
|
|
|
.group-bar .right {
|
|
display: flex;
|
|
margin-left: 50px;
|
|
a {
|
|
height: 30px;
|
|
}
|
|
}
|
|
</style>
|