Skip to content

Commit

Permalink
Fleet details
Browse files Browse the repository at this point in the history
  • Loading branch information
vincent99 committed Sep 24, 2020
1 parent aba3693 commit 264aa27
Show file tree
Hide file tree
Showing 17 changed files with 329 additions and 136 deletions.
3 changes: 2 additions & 1 deletion assets/translations/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,7 @@ resourceDetail:
error: This resource is currently in an error state, but there isn't a detailed message available.
transitioning: This resource is currently in a transitioning state,but there isn't a detailed message available.
namespace: Namespace
workspace: Workspace
overview: Overview
project: Project
yaml: YAML
Expand Down Expand Up @@ -1104,8 +1105,8 @@ tableHeaders:
internalExternalIp: External/Internal IP
key: Key
keys: Data
lastHeartbeatTime: Last update
lastUpdated: Last Updated
lastSeen: Last Seen
matches: Matches
message: Message
name: Name
Expand Down
139 changes: 139 additions & 0 deletions components/FleetClusters.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<script>
import ButtonGroup from '@/components/ButtonGroup';
import SortableTable from '@/components/SortableTable';
import { removeObject } from '@/utils/array';
import { STATE, NAME, AGE } from '@/config/table-headers';
import { FLEET, MANAGEMENT } from '@/config/types';
export default {
components: { ButtonGroup, SortableTable },
props: {
rows: {
type: Array,
required: true,
},
groupable: {
type: Boolean,
default: false,
},
group: {
type: String,
default: null,
},
groupBy: {
type: String,
default: null,
},
groupOptions: {
type: Array,
default: null,
},
},
computed: {
MANAGEMENT_CLUSTER() {
return MANAGEMENT.CLUSTER;
},
headers() {
const workspace = {
name: 'workspace',
label: 'Workspace',
value: 'metadata.namespace',
sort: ['metadata.namespace', 'nameSort'],
};
const out = [
STATE,
NAME,
workspace,
{
name: 'bundlesReady',
labelKey: 'tableHeaders.bundlesReady',
value: 'status.display.readyBundles',
sort: 'status.summary.ready',
search: false,
},
{
name: 'nodesReady',
labelKey: 'tableHeaders.nodesReady',
value: 'status.display.readyBundles',
sort: 'status.summary.ready',
search: false,
},
{
name: 'lastSeen',
labelKey: 'tableHeaders.lastSeen',
value: 'status.agent.lastSeen',
sort: 'status.agent.lastSeen',
search: false,
formatter: 'LiveDate',
formatterOpts: { addSuffix: true },
width: 120,
align: 'right'
},
AGE,
];
if ( this.groupBy || !this.groupable ) {
removeObject(out, workspace);
}
return out;
},
pagingParams() {
const inStore = this.$store.getters['currentProduct'].inStore;
const schema = this.$store.getters[`${ inStore }/schemaFor`](FLEET.CLUSTER);
return {
singularLabel: this.$store.getters['type-map/labelFor'](schema),
pluralLabel: this.$store.getters['type-map/labelFor'](schema, 99),
};
},
}
};
</script>

<template>
<SortableTable
v-bind="$attrs"
:headers="headers"
:rows="rows"
:group-by="groupBy"
:paging-params="pagingParams"
key-field="_key"
v-on="$listeners"
>
<template v-if="groupable" #header-middle>
<slot name="more-header-middle" />
<ButtonGroup :value="group" :options="groupOptions" @input="$emit('set-group', $event)" />
</template>

<template #group-by="{group: thisGroup}">
<div class="group-tab" v-html="thisGroup.ref" />
</template>

<template #cell:workspace="{row}">
<span v-if="row.type !== MANAGEMENT_CLUSTER && row.metadata.namespace">{{ row.metadata.namespace }}</span>
<span v-else class="text-muted">&mdash;</span>
</template>

<template #cell:bundlesReady="{row}">
<span v-if="!row.bundleInfo" class="text-muted">&mdash;</span>
<span v-else-if="row.bundleInfo.unready" class="text-warning">{{ row.bundleInfo.ready }}/{{ row.bundleInfo.total }}</span>
<span v-else>{{ row.bundleInfo.total }}</span>
</template>

<template #cell:nodesReady="{row}">
<span v-if="!row.nodeInfo" class="text-muted">&mdash;</span>
<span v-else-if="row.nodeInfo.unready" class="text-warning">{{ row.nodeInfo.ready }}/{{ row.nodeInfo.total }}</span>
<span v-else :class="{'text-error': !row.nodeInfo.total}">{{ row.nodeInfo.total }}</span>
</template>
</SortableTable>
</template>
20 changes: 19 additions & 1 deletion components/ResourceDetail/Masthead.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<script>
import { PROJECT } from '@/config/labels-annotations';
import { NAMESPACE, MANAGEMENT } from '@/config/types';
import { FLEET, NAMESPACE, MANAGEMENT } from '@/config/types';
import ButtonGroup from '@/components/ButtonGroup';
import BadgeState from '@/components/BadgeState';
import Banner from '@/components/Banner';
import { get } from '@/utils/object';
import { NAME as FLEET_NAME } from '@/config/product/fleet';
export default {
components: {
Expand Down Expand Up @@ -88,6 +89,22 @@ export default {
return null;
},
isWorkspace() {
return this.$store.getters['productId'] === FLEET_NAME && !!this.value?.metadata?.namespace;
},
workspaceLocation() {
return {
name: 'c-cluster-product-resource-id',
params: {
cluster: this.$route.params.cluster,
product: this.$store.getters['productId'],
resource: FLEET.WORKSPACE,
id: this.$route.params.namespace
}
};
},
project() {
if (this.isNamespace) {
const id = (this.value?.metadata?.labels || {})[PROJECT];
Expand Down Expand Up @@ -167,6 +184,7 @@ export default {
<!-- //TODO use nuxt-link for an internal project detail page once it exists -->
<div v-if="mode==='view'" class="subheader">
<span v-if="isNamespace && project">{{ t("resourceDetail.masthead.project") }}: {{ project.nameDisplay }}</span>
<span v-else-if="isWorkspace">{{ t("resourceDetail.masthead.workspace") }}: <nuxt-link :to="workspaceLocation">{{ namespace }}</nuxt-link></span>
<span v-else-if="namespace">{{ t("resourceDetail.masthead.namespace") }}: <nuxt-link :to="namespaceLocation">{{ namespace }}</nuxt-link></span>
<span v-if="!parent.hideAge">{{ t("resourceDetail.masthead.age") }}: <LiveDate class="live-date" :value="get(value, 'metadata.creationTimestamp')" /></span>
</div>
Expand Down
14 changes: 9 additions & 5 deletions components/form/MatchExpressions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -309,17 +309,21 @@ export default {
}
.match-expression-row, .match-expression-header {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: $column-gutter;
align-items: center;
&:not(.view){
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: $column-gutter;
align-items: center;
&:not(.view){
margin-bottom: 10px;
grid-template-columns: 1fr 1fr 1fr 100px;
}
INPUT {
height: 50px;
}
}
.match-expression-header{
color: var(--input-label);
margin-top: 20px;
Expand Down
6 changes: 5 additions & 1 deletion components/form/NameNsDescription.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ export default {
type: Boolean,
default: true,
},
namespaceType: {
type: String,
default: NAMESPACE,
},
namespaceLabel: {
type: String,
default: 'nameNsDescription.namespace.label',
Expand Down Expand Up @@ -147,7 +151,7 @@ export default {
namespaces() {
const inStore = this.$store.getters['currentProduct'].inStore;
const choices = this.$store.getters[`${ inStore }/all`](NAMESPACE);
const choices = this.$store.getters[`${ inStore }/all`](this.namespaceType);
const out = sortBy(choices.map((obj) => {
return {
Expand Down
2 changes: 2 additions & 0 deletions config/labels-annotations.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export const CATALOG = {

const CATTLE_REGEX = /cattle\.io\//;

export const FLEET = { CLUSTER_NAME: 'management.cattle.io/cluster-display-name' };

export const RKE = { EXTERNAL_IP: 'rke.cattle.io/external-ip' };

export const LABELS_TO_IGNORE_REGEX = [
Expand Down
2 changes: 1 addition & 1 deletion config/table-headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ export const STATUS = {
};
export const LAST_HEARTBEAT_TIME = {
name: 'lastHeartbeatTime',
labelKey: 'tableHeaders.lastHeartbeatTime',
labelKey: 'tableHeaders.lastSeen',
value: 'lastHeartbeatTime',
sort: ['lastHeartbeatTime'],
formatter: 'LiveDate',
Expand Down
51 changes: 51 additions & 0 deletions detail/fleet.cattle.io.clustergroup.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<script>
import Loading from '@/components/Loading';
import FleetSummary from '@/components/FleetSummary';
import FleetClusters from '@/components/FleetClusters';
import ResourceTabs from '@/components/form/ResourceTabs';
import Tab from '@/components/Tabbed/Tab';
import { FLEET } from '@/config/types';
export default {
name: 'DetailClusterGroup',
components: {
Loading,
ResourceTabs,
FleetSummary,
FleetClusters,
Tab,
},
props: {
value: {
type: Object,
required: true,
},
},
async fetch() {
await this.$store.dispatch('management/findAll', { type: FLEET.WORKSPACE });
await this.$store.dispatch('management/findAll', { type: FLEET.CLUSTER });
},
};
</script>

<template>
<Loading v-if="$fetchState.pending" />
<div v-else>
<FleetSummary :value="value.status.summary" />

<ResourceTabs v-model="value" mode="view" class="mt-20">
<Tab label="Clusters" name="clusters">
<FleetClusters
:rows="value.targetClusters"
:paging="true"
:table-actions="false"
:search="false"
paging-label="sortableTable.paging.resource"
/>
</Tab>
</ResourceTabs>
</div>
</template>
29 changes: 26 additions & 3 deletions edit/fleet.cattle.io.clustergroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default {
async fetch() {
this.allClusters = await this.$store.dispatch('management/findAll', { type: FLEET.CLUSTER });
this.allWorkspaces = await this.$store.dispatch('management/findAll', { type: FLEET.WORKSPACE });
if ( !this.value.spec?.selector ) {
this.value.spec = this.value.spec || {};
Expand All @@ -43,6 +44,7 @@ export default {
data() {
return {
allClusters: null,
allWorkspaces: null,
matchingClusters: null,
expressions: [
...convert(this.value.spec.selector.matchLabels || {}),
Expand All @@ -51,6 +53,20 @@ export default {
};
},
computed: {
FLEET_WORKSPACE() {
return FLEET.WORKSPACE;
},
clustersForWorkspace() {
const workspace = this.$getters['byId'](FLEET.WORKSPACE, this.metadata.namespace);
return workspace.clusters;
},
},
watch: { 'value.metadata.namespace': 'updateMatchingClusters' },
methods: {
set,
Expand All @@ -65,7 +81,7 @@ export default {
},
updateMatchingClusters: throttle(function() {
const all = this.allClusters;
const all = this.clustersForWorkspace;
const match = matching(all, this.expressions);
const matched = match.length || 0;
const sample = match[0]?.nameDisplay;
Expand All @@ -78,7 +94,7 @@ export default {
sample,
};
}, 250, { leading: true }),
}
},
};
</script>
Expand All @@ -96,7 +112,14 @@ export default {
@finish="save"
@cancel="done"
>
<NameNsDescription v-if="!isView" v-model="value" :mode="mode" :namespaced="isNamespaced" />
<NameNsDescription
v-if="!isView"
v-model="value"
:mode="mode"
:namespaced="true"
namespace-label="nameNsDescription.workspace.label"
:namespace-type="FLEET_WORKSPACE"
/>
<hr v-if="!isView" class="mt-20 mb-20" />
Expand Down
Loading

0 comments on commit 264aa27

Please sign in to comment.