-
- {{ t('fleet.fdc.loadingChart') }}
+
+ {{ t('graph.noPermissions') }}
-
- {{ t('fleet.fdc.renderingChart') }}
+
+ {{ t('graph.loading') }}
-
+
+ {{ t('graph.rendering') }}
+
+
@@ -416,6 +422,9 @@ export default {
>
{{ item.value }}
+
+ {{ t(`typeLabel."${ item.valueKey }"`, { count: 1 }) }}
+ |
{{ item.value }}
@@ -478,32 +487,29 @@ export default {
}
}
- &.repo.active > circle {
- transform: scale(1.2);
- }
-
&.bundle.active > circle {
transform: scale(1.35);
}
- &.bundle-deployment.active > circle {
+ &.bundledeployment.active > circle {
transform: scale(1.6);
}
- &.node-default-fill > circle,
- &.repo > circle {
+ &.node-default-fill > circle {
+ transform: scale(1.2);
fill: var(--muted);
}
- &:not(.repo).node-success > circle {
+
+ &.node-success > circle {
fill: var(--success);
}
- &:not(.repo).node-info > circle {
+ &.node-info > circle {
fill: var(--info);
}
- &:not(.repo).node-warning > circle {
+ &.node-warning > circle {
fill: var(--warning);
}
- &:not(.repo).node-error > circle {
+ &.node-error > circle {
fill: var(--error);
}
diff --git a/shell/components/ResourceDetail/index.vue b/shell/components/ResourceDetail/index.vue
index d471b5f444..38f1837f86 100644
--- a/shell/components/ResourceDetail/index.vue
+++ b/shell/components/ResourceDetail/index.vue
@@ -6,14 +6,13 @@ import {
_VIEW, _EDIT, _CLONE, _IMPORT, _STAGE, _CREATE,
AS, _YAML, _DETAIL, _CONFIG, _GRAPH, PREVIEW, MODE,
} from '@shell/config/query-params';
-import { FLEET, SCHEMA } from '@shell/config/types';
+import { SCHEMA } from '@shell/config/types';
import { createYaml } from '@shell/utils/create-yaml';
import Masthead from '@shell/components/ResourceDetail/Masthead';
import DetailTop from '@shell/components/DetailTop';
import { clone, diff } from '@shell/utils/object';
import IconMessage from '@shell/components/IconMessage';
-import ForceDirectedTreeChart from '@shell/components/fleet/ForceDirectedTreeChart';
-import { checkSchemasForFindAllHash } from '@shell/utils/auth';
+import ForceDirectedTreeChart from '@shell/components/ForceDirectedTreeChart';
import { stringify } from '@shell/utils/error';
import { Banner } from '@components/Banner';
@@ -172,28 +171,6 @@ export default {
yaml = createYaml(schemas, resourceType, data);
}
} else {
- if ( as === _GRAPH ) {
- const graphSchema = await checkSchemasForFindAllHash({
- cluster: {
- inStoreType: 'management',
- type: FLEET.CLUSTER
- },
- bundle: {
- inStoreType: 'management',
- type: FLEET.BUNDLE,
- opt: { excludeFields: ['metadata.managedFields', 'spec.resources'] },
- },
-
- bundleDeployment: {
- inStoreType: 'management',
- type: FLEET.BUNDLE_DEPLOYMENT
- }
-
- }, this.$store);
-
- this.canViewChart = graphSchema.cluster && graphSchema.bundle && graphSchema.bundleDeployment;
- }
-
let fqid = id;
if ( schema.attributes?.namespaced && namespace ) {
@@ -296,7 +273,6 @@ export default {
value: null,
model: null,
notFound: null,
- canViewChart: true,
canViewYaml: null,
errors: []
};
@@ -493,7 +469,7 @@ export default {
diff --git a/shell/components/fleet/ForceDirectedTreeChart/chartIcons.js b/shell/components/fleet/ForceDirectedTreeChart/chartIcons.js
deleted file mode 100644
index 0db8a83246..0000000000
--- a/shell/components/fleet/ForceDirectedTreeChart/chartIcons.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// This is to mitigate an issue where the SVG icons being imported from the project weren't being rendered on Firefox
-// To know more about this technique, check this doc: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs
-export const getChartIcon = (type) => `
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
diff --git a/shell/config/product/fleet.js b/shell/config/product/fleet.js
index a915250bc7..6ab44d8a25 100644
--- a/shell/config/product/fleet.js
+++ b/shell/config/product/fleet.js
@@ -2,7 +2,7 @@ import { DSL } from '@shell/store/type-map';
import { FLEET } from '@shell/config/types';
import { STATE, NAME as NAME_COL, AGE, FLEET_APPLICATION_TYPE } from '@shell/config/table-headers';
import { FLEET as FLEET_FEATURE } from '@shell/store/features';
-import { gitRepoGraphConfig } from '@shell/pages/c/_cluster/fleet/GitRepoGraphConfig';
+import { graphConfig } from '@shell/pages/c/_cluster/fleet/graph/config';
import { BLANK_CLUSTER } from '@shell/store/store-types.js';
export const SOURCE_TYPE = {
@@ -142,9 +142,11 @@ export function init(store) {
], 'resources');
configureType(FLEET.GIT_REPO, {
- showListMasthead: false, hasGraph: true, graphConfig: gitRepoGraphConfig
+ showListMasthead: false, hasGraph: true, graphConfig
+ });
+ configureType(FLEET.HELM_OP, {
+ showListMasthead: false, hasGraph: true, graphConfig
});
- configureType(FLEET.HELM_OP, { showListMasthead: false, hasGraph: false });
weightType(FLEET.GIT_REPO, 110, true);
weightType(FLEET.HELM_OP, 109, true);
diff --git a/shell/pages/c/_cluster/fleet/GitRepoGraphConfig.js b/shell/pages/c/_cluster/fleet/GitRepoGraphConfig.js
deleted file mode 100644
index c0b2a24e24..0000000000
--- a/shell/pages/c/_cluster/fleet/GitRepoGraphConfig.js
+++ /dev/null
@@ -1,249 +0,0 @@
-import { STATES } from '@shell/plugins/dashboard-store/resource-class';
-import { FLEET } from '@shell/config/types';
-
-// some default values
-const defaultNodeRadius = 20;
-const defaultNodePadding = 15;
-const chartWidth = 800;
-const chartHeight = 500;
-const fdcStrength = -300;
-const fdcDistanceMax = 500;
-const fdcForceCollide = 80;
-const fdcAlphaDecay = 0.05;
-
-// setting up default sim params
-// check documentation here: https://github.com/d3/d3-force#forceSimulation
-const simulationParams = {
- fdcStrength,
- fdcDistanceMax,
- fdcForceCollide,
- fdcAlphaDecay
-};
-
-/**
- * Represents a config object for FDC type
- * @param {Function} parseData - Parses the specific data for each chart. Format must be compliant with d3 data format
- * @example data format => { parent: {..., children: [ {..., children: []} ] } }
- * @param {Function} extendNodeClass - Extends the classes for each node so that the styling is correctly applied
- * @param {Function} nodeDimensions - Sets the radius of the nodes according each data type
- * @param {Function} infoDetails - Prepares the data to be displayed in the info box on the right-side of the ForceDirectedTreeChart component
- */
-export const gitRepoGraphConfig = {
- chartWidth,
- chartHeight,
- simulationParams,
- /**
- * data prop that is used to trigger the watcher in the component. Should follow format "data.xxxxxx"
- */
- watcherProp: 'data.bundles',
- /**
- * Mandatory params for a child object in parseData (for statuses to work)
- * @param {String} state
- * @param {String} stateDisplay
- * @param {String} stateColor
- * @param {String} matchingId (this can be different than the actual ID, depends on the usecase)
- */
- parseData: (data) => {
- const bundles = data.bundles.map((bundle, i) => {
- const bundleLowercaseState = bundle.state ? bundle.state.toLowerCase() : 'unknown';
- const bundleStateColor = STATES[bundleLowercaseState].color;
-
- const repoChild = {
- id: bundle.id,
- matchingId: bundle.id,
- type: bundle.type,
- state: bundle.state,
- stateLabel: bundle.stateDisplay,
- stateColor: bundleStateColor,
- isBundle: true,
- errorMsg: bundle.stateDescription,
- detailLocation: bundle.detailLocation,
- children: []
- };
-
- const bds = data.bundleDeployments.filter((bd) => bundle.id === `${ bd.metadata?.labels?.['fleet.cattle.io/bundle-namespace'] }/${ bd.metadata?.labels?.['fleet.cattle.io/bundle-name'] }`);
-
- bds.forEach((bd) => {
- const bdLowercaseState = bd.state ? bd.state.toLowerCase() : 'unknown';
- const bdStateColor = STATES[bdLowercaseState]?.color;
-
- const cluster = data.clustersList.find((cluster) => {
- const clusterString = `${ cluster.namespace }-${ cluster.name }`;
-
- return bd.id.includes(clusterString);
- });
-
- repoChild.children.push({
- id: bd.id,
- matchingId: bd.id,
- type: bd.type,
- clusterLabel: cluster ? cluster.namespacedName : undefined,
- clusterDetailLocation: cluster ? cluster.detailLocation : undefined,
- state: bd.state,
- stateLabel: bd.stateDisplay,
- stateColor: bdStateColor,
- isBundleDeployment: true,
- errorMsg: bd.stateDescription,
- detailLocation: bd.detailLocation,
- });
- });
-
- return repoChild;
- });
-
- const repoLowercaseState = data.state ? data.state.toLowerCase() : 'unknown';
- const repoStateColor = STATES[repoLowercaseState].color;
-
- const finalData = {
- id: data.id,
- matchingId: data.id,
- type: data.type,
- state: data.state,
- stateLabel: data.stateDisplay,
- stateColor: repoStateColor,
- isRepo: true,
- errorMsg: data.stateDescription,
- detailLocation: data.detailLocation,
- children: bundles
- };
-
- return finalData;
- },
- /**
- * Used to add relevant classes to each main node instance
- */
- extendNodeClass: ({ data }) => {
- const classArray = [];
-
- // node type
- data?.isRepo ? classArray.push('repo') : data?.isBundle ? classArray.push('bundle') : classArray.push('bundle-deployment');
-
- return classArray;
- },
- /**
- * Used to add the correct icon to each node
- */
- fetchNodeIcon: ({ data }) => {
- if (data?.isRepo) {
- return 'git';
- }
-
- if ( data?.isBundle) {
- if (data?.id.indexOf('helm') !== -1) {
- return 'helm';
- }
-
- return 'bundle';
- }
-
- if (data?.isBundleDeployment) {
- return 'node';
- }
- },
- /**
- * Used to set node dimensions
- */
- nodeDimensions: ({ data }) => {
- if (data?.isRepo) {
- const radius = defaultNodeRadius * 3;
- const padding = defaultNodePadding * 2.5;
-
- return {
- radius,
- size: (radius * 2) - padding,
- position: -(((radius * 2) - padding) / 2)
- };
- }
- if (data?.isBundle) {
- const radius = defaultNodeRadius * 2;
- const padding = defaultNodePadding;
-
- if (data?.id.indexOf('helm') !== -1) {
- return {
- radius,
- size: (radius * 1.5) - padding,
- position: -(((radius * 1.5) - padding) / 2)
- };
- }
-
- return {
- radius,
- size: (radius * 1.7) - padding,
- position: -(((radius * 1.7) - padding) / 2)
- };
- }
-
- return {
- radius: defaultNodeRadius,
- size: (defaultNodeRadius * 2) - defaultNodePadding,
- position: -(((defaultNodeRadius * 2) - defaultNodePadding) / 2)
- };
- },
- /**
- * Use @param {Obj} valueObj for compound values (usually associated with a template of some sort on the actual component)
- * or @param value for a simple straightforward value
- */
- infoDetails: (data) => {
- let dataType;
-
- switch (data.type) {
- case FLEET.GIT_REPO:
- dataType = 'GitRepo';
- break;
- case FLEET.BUNDLE:
- dataType = 'Bundle';
- break;
- case FLEET.BUNDLE_DEPLOYMENT:
- dataType = 'BundleDeployment';
- break;
- default:
- dataType = data.type;
- break;
- }
-
- const moreInfo = [
- {
- labelKey: 'fleet.fdc.type',
- value: dataType
- },
- {
- type: 'title-link',
- labelKey: 'fleet.fdc.id',
- valueObj: {
- label: data.id,
- detailLocation: data.detailLocation
- }
- }
- ];
-
- if (data.isBundleDeployment) {
- moreInfo.push({
- type: 'title-link',
- labelKey: 'fleet.fdc.cluster',
- valueObj: {
- label: data.clusterLabel,
- detailLocation: data.clusterDetailLocation
- }
- });
- }
-
- moreInfo.push({
- type: 'state-badge',
- labelKey: 'fleet.fdc.state',
- valueObj: {
- stateColor: data.stateColor,
- stateLabel: data.stateLabel
- }
- });
-
- if (data.errorMsg) {
- moreInfo.push({
- type: 'single-error',
- labelKey: 'fleet.fdc.error',
- value: data.errorMsg
- });
- }
-
- return moreInfo;
- }
-};
diff --git a/shell/pages/c/_cluster/fleet/graph/config.js b/shell/pages/c/_cluster/fleet/graph/config.js
new file mode 100644
index 0000000000..f8061a3a0c
--- /dev/null
+++ b/shell/pages/c/_cluster/fleet/graph/config.js
@@ -0,0 +1,277 @@
+import { STATES } from '@shell/plugins/dashboard-store/resource-class';
+import { FLEET } from '@shell/config/types';
+import { checkSchemasForFindAllHash } from '@shell/utils/auth';
+
+// TODO use Rancher icons
+const chartIcon = (type) => `
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+// some default values
+const defaultNodeRadius = 20;
+const defaultNodePadding = 15;
+const chartWidth = 800;
+const chartHeight = 500;
+const fdcStrength = -300;
+const fdcDistanceMax = 500;
+const fdcForceCollide = 80;
+const fdcAlphaDecay = 0.05;
+
+// setting up default sim params
+// check documentation here: https://github.com/d3/d3-force#forceSimulation
+const simulationParams = {
+ fdcStrength,
+ fdcDistanceMax,
+ fdcForceCollide,
+ fdcAlphaDecay
+};
+
+/**
+ * Represents a config object for FDC type
+ * @param {Function} parseData - Parses the specific data for each chart. Format must be compliant with d3 data format
+ * @example data format => { parent: {..., children: [ {..., children: []} ] } }
+ * @param {Function} extendNodeClass - Extends the classes for each node so that the styling is correctly applied
+ * @param {Function} nodeDimensions - Sets the radius of the nodes according each data type
+ * @param {Function} infoDetails - Prepares the data to be displayed in the info box on the right-side of the ForceDirectedTreeChart component
+ */
+export const graphConfig = {
+ chartWidth,
+ chartHeight,
+ simulationParams,
+ /**
+ * data prop that is used to trigger the watcher in the component. Should follow format "data.xxxxxx"
+ */
+ watcherProp: 'data.bundles',
+ /**
+ * Mandatory params for a child object in parseData (for statuses to work)
+ * @param {String} state
+ * @param {String} stateDisplay
+ * @param {String} stateColor
+ * @param {String} matchingId (this can be different than the actual ID, depends on the usecase)
+ */
+ parseData: (data) => {
+ const bundles = data.bundles.map((bundle) => {
+ const bundleLowercaseState = bundle.state ? bundle.state.toLowerCase() : 'unknown';
+ const bundleStateColor = STATES[bundleLowercaseState].color;
+
+ const appChild = {
+ id: bundle.id,
+ type: bundle.type,
+ matchingId: `${ bundle.type }-${ bundle.id }`,
+ state: bundle.state,
+ stateLabel: bundle.stateDisplay,
+ stateColor: bundleStateColor,
+ errorMsg: bundle.stateDescription,
+ detailLocation: bundle.detailLocation,
+ children: []
+ };
+
+ const bds = data.bundleDeployments.filter((bd) => bundle.id === `${ bd.metadata?.labels?.['fleet.cattle.io/bundle-namespace'] }/${ bd.metadata?.labels?.['fleet.cattle.io/bundle-name'] }`);
+
+ bds.forEach((bd) => {
+ const bdLowercaseState = bd.state ? bd.state.toLowerCase() : 'unknown';
+ const bdStateColor = STATES[bdLowercaseState]?.color;
+
+ const cluster = data.clustersList.find((cluster) => {
+ const clusterString = `${ cluster.namespace }-${ cluster.name }`;
+
+ return bd.id.includes(clusterString);
+ });
+
+ appChild.children.push({
+ id: bd.id,
+ type: bd.type,
+ matchingId: `${ bd.type }-${ bd.id }`,
+ clusterLabel: cluster ? cluster.namespacedName : undefined,
+ clusterDetailLocation: cluster ? cluster.detailLocation : undefined,
+ state: bd.state,
+ stateLabel: bd.stateDisplay,
+ stateColor: bdStateColor,
+ errorMsg: bd.stateDescription,
+ detailLocation: bd.detailLocation,
+ });
+ });
+
+ return appChild;
+ });
+
+ const appLowercaseState = data.state ? data.state.toLowerCase() : 'unknown';
+ const appStateColor = STATES[appLowercaseState].color;
+
+ return {
+ id: data.id,
+ type: data.type,
+ matchingId: `${ data.type }-${ data.id }`,
+ state: data.state,
+ stateLabel: data.stateDisplay,
+ stateColor: appStateColor,
+ errorMsg: data.stateDescription,
+ detailLocation: data.detailLocation,
+ children: bundles,
+ muteStatus: true
+ };
+ },
+ /**
+ * Used to add relevant classes to each main node instance
+ */
+ extendNodeClass: ({ data }) => {
+ const classArray = [];
+
+ if (data?.type) {
+ const nodeType = data.type.replaceAll('fleet.cattle.io.', '');
+
+ classArray.push(nodeType);
+ }
+
+ return classArray;
+ },
+ /**
+ * Used to add the correct icon to each node
+ */
+ fetchNodeIcon: ({ data }) => {
+ let type = '';
+
+ switch (data?.type) {
+ case FLEET.GIT_REPO:
+ type = 'git';
+ break;
+ case FLEET.HELM_OP:
+ type = 'helm';
+ break;
+ case FLEET.BUNDLE:
+ if (data?.id.indexOf('helm') !== -1) {
+ type = 'helm';
+ }
+
+ type = 'bundle';
+ break;
+ case FLEET.BUNDLE_DEPLOYMENT:
+ type = 'node';
+ break;
+ }
+
+ return chartIcon(type);
+ },
+ /**
+ * Used to set node dimensions
+ */
+ nodeDimensions: ({ data }) => {
+ if (data?.type === FLEET.GIT_REPO || data?.type === FLEET.HELM_OP) {
+ const radius = defaultNodeRadius * 3;
+ const padding = defaultNodePadding * 2.5;
+
+ return {
+ radius,
+ size: (radius * 2) - padding,
+ position: -(((radius * 2) - padding) / 2)
+ };
+ }
+ if (data?.type === FLEET.BUNDLE) {
+ const radius = defaultNodeRadius * 2;
+ const padding = defaultNodePadding;
+
+ if (data?.id.indexOf('helm') !== -1) {
+ return {
+ radius,
+ size: (radius * 1.5) - padding,
+ position: -(((radius * 1.5) - padding) / 2)
+ };
+ }
+
+ return {
+ radius,
+ size: (radius * 1.7) - padding,
+ position: -(((radius * 1.7) - padding) / 2)
+ };
+ }
+
+ return {
+ radius: defaultNodeRadius,
+ size: (defaultNodeRadius * 2) - defaultNodePadding,
+ position: -(((defaultNodeRadius * 2) - defaultNodePadding) / 2)
+ };
+ },
+ /**
+ * Use @param {Obj} valueObj for compound values (usually associated with a template of some sort on the actual component)
+ * or @param value for a simple straightforward value
+ */
+ infoDetails: (data) => {
+ const moreInfo = [
+ {
+ type: 'resource-type',
+ labelKey: 'fleet.fdc.type',
+ valueKey: data.type
+ },
+ {
+ type: 'title-link',
+ labelKey: 'fleet.fdc.id',
+ valueObj: {
+ label: data.id,
+ detailLocation: data.detailLocation
+ }
+ }
+ ];
+
+ if (data?.type === FLEET.BUNDLE_DEPLOYMENT) {
+ moreInfo.push({
+ type: 'title-link',
+ labelKey: 'fleet.fdc.cluster',
+ valueObj: {
+ label: data.clusterLabel,
+ detailLocation: data.clusterDetailLocation
+ }
+ });
+ }
+
+ moreInfo.push({
+ type: 'state-badge',
+ labelKey: 'fleet.fdc.state',
+ valueObj: {
+ stateColor: data.stateColor,
+ stateLabel: data.stateLabel
+ }
+ });
+
+ if (data.errorMsg) {
+ moreInfo.push({
+ type: 'single-error',
+ labelKey: 'fleet.fdc.error',
+ value: data.errorMsg
+ });
+ }
+
+ return moreInfo;
+ },
+
+ checkSchemaPermissions: async(store) => {
+ const schemas = await checkSchemasForFindAllHash({
+ cluster: {
+ inStoreType: 'management',
+ type: FLEET.CLUSTER
+ },
+ bundle: {
+ inStoreType: 'management',
+ type: FLEET.BUNDLE,
+ opt: { excludeFields: ['metadata.managedFields', 'spec.resources'] },
+ },
+ bundleDeployment: {
+ inStoreType: 'management',
+ type: FLEET.BUNDLE_DEPLOYMENT
+ }
+ }, store);
+
+ return schemas.cluster && schemas.bundle && schemas.bundleDeployment;
+ }
+};
diff --git a/shell/pages/c/_cluster/fleet/index.vue b/shell/pages/c/_cluster/fleet/index.vue
index 332bd67423..0726913963 100644
--- a/shell/pages/c/_cluster/fleet/index.vue
+++ b/shell/pages/c/_cluster/fleet/index.vue
@@ -20,6 +20,11 @@ import FleetApplications from '@shell/components/fleet/FleetApplications.vue';
import FleetUtils from '@shell/utils/fleet';
import Preset from '@shell/mixins/preset';
+const VIEW_MODE = {
+ TABLE: 'flat',
+ CARDS: 'cards'
+};
+
export default {
name: 'FleetDashboard',
components: {
@@ -101,25 +106,26 @@ export default {
createRoute: { name: 'c-cluster-fleet-application-create' },
permissions: {},
FLEET,
- [FLEET.REPO]: [],
- [FLEET.HELM_OP]: [],
- fleetWorkspaces: [],
- viewModeOptions: [
+ [FLEET.REPO]: [],
+ [FLEET.HELM_OP]: [],
+ fleetWorkspaces: [],
+ VIEW_MODE,
+ viewModeOptions: [
{
tooltipKey: 'fleet.dashboard.viewMode.table',
icon: 'icon-list-flat',
- value: 'flat',
+ value: VIEW_MODE.TABLE,
},
{
tooltipKey: 'fleet.dashboard.viewMode.cards',
icon: 'icon-apps',
- value: 'cards',
+ value: VIEW_MODE.CARDS,
},
],
CARDS_MIN: 50,
CARDS_SIZE: 50,
cardsCount: {},
- viewMode: 'cards',
+ viewMode: VIEW_MODE.CARDS,
isWorkspaceCollapsed: {},
isStateCollapsed: {},
typeFilter: {},
@@ -671,7 +677,7 @@ export default {
|