mirror of https://github.com/rancher/dashboard.git
255 lines
6.4 KiB
Vue
255 lines
6.4 KiB
Vue
<script>
|
|
/*
|
|
Tab component for resource CRU pages featuring:
|
|
Labels and Annotation tabs with content filtered by create-edit-view mixin
|
|
*/
|
|
import Tabbed from '@shell/components/Tabbed';
|
|
import Tab from '@shell/components/Tabbed/Tab';
|
|
import CreateEditView from '@shell/mixins/create-edit-view';
|
|
import Conditions from '@shell/components/form/Conditions';
|
|
import { EVENT } from '@shell/config/types';
|
|
import SortableTable from '@shell/components/SortableTable';
|
|
import { _VIEW } from '@shell/config/query-params';
|
|
import RelatedResources from '@shell/components/RelatedResources';
|
|
import { ExtensionPoint, TabLocation } from '@shell/core/types';
|
|
import { getApplicableExtensionEnhancements } from '@shell/core/plugin-helpers';
|
|
import { isConditionReadyAndWaiting } from '@shell/plugins/dashboard-store/resource-class';
|
|
|
|
export default {
|
|
|
|
name: 'ResourceTabs',
|
|
|
|
components: {
|
|
Tabbed,
|
|
Tab,
|
|
Conditions,
|
|
SortableTable,
|
|
RelatedResources,
|
|
},
|
|
|
|
mixins: [CreateEditView],
|
|
|
|
props: {
|
|
// resource instance
|
|
value: {
|
|
type: Object,
|
|
default: () => {
|
|
return {};
|
|
}
|
|
},
|
|
// create-edit-view mode
|
|
mode: {
|
|
type: String,
|
|
default: _VIEW,
|
|
},
|
|
|
|
defaultTab: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
|
|
needConditions: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
|
|
needEvents: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
|
|
needRelated: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
|
|
extensionParams: {
|
|
type: Object,
|
|
default: null
|
|
}
|
|
},
|
|
|
|
data() {
|
|
const inStore = this.$store.getters['currentStore'](EVENT);
|
|
|
|
return {
|
|
hasEvents: this.$store.getters[`${ inStore }/schemaFor`](EVENT), // @TODO be smarter about which resources actually ever have events
|
|
allEvents: [],
|
|
selectedTab: this.defaultTab,
|
|
didLoadEvents: false,
|
|
extensionTabs: getApplicableExtensionEnhancements(this, ExtensionPoint.TAB, TabLocation.RESOURCE_DETAIL, this.$route, this, this.extensionParams),
|
|
};
|
|
},
|
|
|
|
beforeDestroy() {
|
|
this.$store.dispatch('cluster/forgetType', EVENT);
|
|
},
|
|
|
|
computed: {
|
|
showConditions() {
|
|
const inStore = this.$store.getters['currentStore'](this.value.type);
|
|
|
|
if ( this.$store.getters[`${ inStore }/schemaFor`](this.value.type) ) {
|
|
return this.isView && this.needConditions && this.value?.type && this.$store.getters[`${ inStore }/pathExistsInSchema`](this.value.type, 'status.conditions');
|
|
}
|
|
|
|
return false;
|
|
},
|
|
showEvents() {
|
|
return this.isView && this.needEvents && this.hasEvents;
|
|
},
|
|
showRelated() {
|
|
return this.isView && this.needRelated;
|
|
},
|
|
eventHeaders() {
|
|
return [
|
|
{
|
|
name: 'type',
|
|
label: this.t('tableHeaders.type'),
|
|
value: 'eventType',
|
|
sort: 'eventType',
|
|
},
|
|
{
|
|
name: 'reason',
|
|
label: this.t('tableHeaders.reason'),
|
|
value: 'reason',
|
|
sort: 'reason',
|
|
},
|
|
{
|
|
name: 'date',
|
|
label: this.t('tableHeaders.updated'),
|
|
value: 'date',
|
|
sort: 'date:desc',
|
|
formatter: 'LiveDate',
|
|
formatterOpts: { addSuffix: true },
|
|
width: 125
|
|
},
|
|
{
|
|
name: 'message',
|
|
label: this.t('tableHeaders.message'),
|
|
value: 'message',
|
|
sort: 'message',
|
|
},
|
|
];
|
|
},
|
|
events() {
|
|
return this.allEvents.filter((event) => {
|
|
return event.involvedObject?.uid === this.value?.metadata?.uid;
|
|
}).map((event) => {
|
|
return {
|
|
reason: (`${ event.reason || this.t('generic.unknown') }${ event.count > 1 ? ` (${ event.count })` : '' }`).trim(),
|
|
message: event.message || this.t('generic.unknown'),
|
|
date: event.lastTimestamp || event.firstTimestamp || event.metadata.creationTimestamp,
|
|
eventType: event.eventType
|
|
};
|
|
});
|
|
},
|
|
conditionsHaveIssues() {
|
|
if (this.showConditions) {
|
|
return this.value.status?.conditions?.filter((cond) => !isConditionReadyAndWaiting(cond)).some((cond) => cond.error);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
// Ensures we only fetch events and show the table when the events tab has been activated
|
|
tabChange(neu) {
|
|
this.selectedTab = neu?.selectedName;
|
|
|
|
if (!this.didLoadEvents && this.selectedTab === 'events') {
|
|
const inStore = this.$store.getters['currentStore'](EVENT);
|
|
|
|
this.$store.dispatch(`${ inStore }/findAll`, { type: EVENT }).then((events) => {
|
|
this.allEvents = events;
|
|
this.didLoadEvents = true;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<Tabbed
|
|
v-bind="$attrs"
|
|
:default-tab="defaultTab"
|
|
@changed="tabChange"
|
|
>
|
|
<slot />
|
|
|
|
<Tab
|
|
v-if="showConditions"
|
|
label-key="resourceTabs.conditions.tab"
|
|
name="conditions"
|
|
:weight="-1"
|
|
:display-alert-icon="conditionsHaveIssues"
|
|
>
|
|
<Conditions :value="value" />
|
|
</Tab>
|
|
|
|
<Tab
|
|
v-if="showEvents"
|
|
label-key="resourceTabs.events.tab"
|
|
name="events"
|
|
:weight="-2"
|
|
>
|
|
<SortableTable
|
|
v-if="selectedTab === 'events'"
|
|
:rows="events"
|
|
:headers="eventHeaders"
|
|
key-field="id"
|
|
:search="false"
|
|
:table-actions="false"
|
|
:row-actions="false"
|
|
default-sort-by="date"
|
|
/>
|
|
</Tab>
|
|
|
|
<Tab
|
|
v-if="showRelated"
|
|
name="related"
|
|
label-key="resourceTabs.related.tab"
|
|
:weight="-3"
|
|
>
|
|
<h3 v-t="'resourceTabs.related.from'" />
|
|
<RelatedResources
|
|
:ignore-types="[value.type]"
|
|
:value="value"
|
|
direction="from"
|
|
/>
|
|
|
|
<h3
|
|
v-t="'resourceTabs.related.to'"
|
|
class="mt-20"
|
|
/>
|
|
<RelatedResources
|
|
:ignore-types="[value.type]"
|
|
:value="value"
|
|
direction="to"
|
|
/>
|
|
</Tab>
|
|
|
|
<!-- Extension tabs -->
|
|
<Tab
|
|
v-for="tab, i in extensionTabs"
|
|
:key="`${tab.name}${i}`"
|
|
:name="tab.name"
|
|
:label="tab.label"
|
|
:label-key="tab.labelKey"
|
|
:weight="tab.weight"
|
|
:tooltip="tab.tooltip"
|
|
:show-header="tab.showHeader"
|
|
:display-alert-icon="tab.displayAlertIcon"
|
|
:error="tab.error"
|
|
:badge="tab.badge"
|
|
>
|
|
<component
|
|
:is="tab.component"
|
|
:resource="value"
|
|
/>
|
|
</Tab>
|
|
</Tabbed>
|
|
</template>
|