@red-hat-developer-hub/plugin-cost-management 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @red-hat-developer-hub/plugin-cost-management
2
2
 
3
+ ## 2.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ef3257c: Add a New Frontend System `/alpha` export so the plugin loads in RHDH 2.1, with Optimizations and Cost Management sidebar pages. Legacy PluginRoot exports are unchanged.
8
+
9
+ ### Patch Changes
10
+
11
+ - @red-hat-developer-hub/plugin-cost-management-common@2.4.0
12
+
3
13
  ## 2.3.0
4
14
 
5
15
  ### Minor Changes
package/README.md CHANGED
@@ -44,7 +44,34 @@ You can follow one of these options depending on your environment and how you ch
44
44
  backend.add(import('@red-hat-developer-hub/plugin-cost-management-backend'));
45
45
  ```
46
46
 
47
- 1. Add the `ResourceOptimizationPage` extension to your `App.tsx` routes
47
+ 1. Add the frontend plugin to your app.
48
+
49
+ **New Frontend System** (RHDH 2.1 / `app-next`):
50
+
51
+ ```ts
52
+ import costManagementPlugin from '@red-hat-developer-hub/plugin-cost-management/alpha';
53
+
54
+ const app = createApp({
55
+ features: [costManagementPlugin],
56
+ });
57
+ ```
58
+
59
+ Sidebar items come from the plugin: **Optimizations** (`/cost-management/optimizations`) and **Cost Management** (`/cost-management/openshift`). Optional overrides:
60
+
61
+ ```yaml
62
+ app:
63
+ extensions:
64
+ - page:cost-management:
65
+ config:
66
+ title: Optimizations
67
+ path: /cost-management/optimizations
68
+ - page:cost-management/openshift:
69
+ config:
70
+ title: Cost Management
71
+ path: /cost-management/openshift
72
+ ```
73
+
74
+ **Legacy frontend** (`FlatRoutes`):
48
75
 
49
76
  ```ts
50
77
  // packages/app/src/App.tsx
@@ -3,25 +3,25 @@ import { ErrorPage } from '@backstage/core-components';
3
3
  import { Routes, Route } from 'react-router-dom';
4
4
  import { OptimizationsPage } from './pages/optimizations/OptimizationsPage.esm.js';
5
5
  import { OptimizationsBreakdownPage } from './pages/optimizations-breakdown/OptimizationsBreakdownPage.esm.js';
6
- import { OpenShiftPage } from './pages/openshift/OpenShiftPage.esm.js';
7
6
  import { usePatternFlyTheme } from './hooks/usePatternFlyTheme.esm.js';
8
7
 
8
+ const notFound = /* @__PURE__ */ jsx(ErrorPage, { status: "404", statusMessage: "Page not found" });
9
+ function OptimizationsRouter() {
10
+ usePatternFlyTheme();
11
+ return /* @__PURE__ */ jsxs(Routes, { children: [
12
+ /* @__PURE__ */ jsx(Route, { path: "/", element: /* @__PURE__ */ jsx(OptimizationsPage, {}) }),
13
+ /* @__PURE__ */ jsx(Route, { path: "/:id/*", element: /* @__PURE__ */ jsx(OptimizationsBreakdownPage, {}) }),
14
+ /* @__PURE__ */ jsx(Route, { path: "*", element: notFound })
15
+ ] });
16
+ }
9
17
  function Router() {
10
18
  usePatternFlyTheme();
11
19
  return /* @__PURE__ */ jsxs(Routes, { children: [
12
20
  /* @__PURE__ */ jsx(Route, { path: "/", element: /* @__PURE__ */ jsx(OptimizationsPage, {}) }),
13
- /* @__PURE__ */ jsx(Route, { path: "/optimizations", element: /* @__PURE__ */ jsx(OptimizationsPage, {}) }),
14
- /* @__PURE__ */ jsx(Route, { path: "/openshift", element: /* @__PURE__ */ jsx(OpenShiftPage, {}) }),
15
21
  /* @__PURE__ */ jsx(Route, { path: "/:id/*", element: /* @__PURE__ */ jsx(OptimizationsBreakdownPage, {}) }),
16
- /* @__PURE__ */ jsx(
17
- Route,
18
- {
19
- path: "*",
20
- element: /* @__PURE__ */ jsx(ErrorPage, { status: "404", statusMessage: "Page not found" })
21
- }
22
- )
22
+ /* @__PURE__ */ jsx(Route, { path: "*", element: notFound })
23
23
  ] });
24
24
  }
25
25
 
26
- export { Router };
26
+ export { OptimizationsRouter, Router };
27
27
  //# sourceMappingURL=Router.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Router.esm.js","sources":["../src/Router.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ErrorPage } from '@backstage/core-components';\nimport { Routes, Route } from 'react-router-dom';\nimport { OptimizationsPage } from './pages/optimizations/OptimizationsPage';\nimport { OptimizationsBreakdownPage } from './pages/optimizations-breakdown/OptimizationsBreakdownPage';\nimport { OpenShiftPage } from './pages/openshift/OpenShiftPage';\nimport { usePatternFlyTheme } from './hooks/usePatternFlyTheme';\n\n/** @public */\nexport function Router() {\n usePatternFlyTheme();\n\n return (\n <Routes>\n <Route path=\"/\" element={<OptimizationsPage />} />\n <Route path=\"/optimizations\" element={<OptimizationsPage />} />\n <Route path=\"/openshift\" element={<OpenShiftPage />} />\n <Route path=\"/:id/*\" element={<OptimizationsBreakdownPage />} />\n <Route\n path=\"*\"\n element={<ErrorPage status=\"404\" statusMessage=\"Page not found\" />}\n />\n </Routes>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAwBO,SAAS,MAAA,GAAS;AACvB,EAAA,kBAAA,EAAmB;AAEnB,EAAA,4BACG,MAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,SAAM,IAAA,EAAK,GAAA,EAAI,OAAA,kBAAS,GAAA,CAAC,qBAAkB,CAAA,EAAI,CAAA;AAAA,wBAC/C,KAAA,EAAA,EAAM,IAAA,EAAK,kBAAiB,OAAA,kBAAS,GAAA,CAAC,qBAAkB,CAAA,EAAI,CAAA;AAAA,wBAC5D,KAAA,EAAA,EAAM,IAAA,EAAK,cAAa,OAAA,kBAAS,GAAA,CAAC,iBAAc,CAAA,EAAI,CAAA;AAAA,wBACpD,KAAA,EAAA,EAAM,IAAA,EAAK,UAAS,OAAA,kBAAS,GAAA,CAAC,8BAA2B,CAAA,EAAI,CAAA;AAAA,oBAC9D,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,GAAA;AAAA,QACL,yBAAS,GAAA,CAAC,SAAA,EAAA,EAAU,MAAA,EAAO,KAAA,EAAM,eAAc,gBAAA,EAAiB;AAAA;AAAA;AAClE,GAAA,EACF,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"Router.esm.js","sources":["../src/Router.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ErrorPage } from '@backstage/core-components';\nimport { Routes, Route } from 'react-router-dom';\nimport { OptimizationsPage } from './pages/optimizations/OptimizationsPage';\nimport { OptimizationsBreakdownPage } from './pages/optimizations-breakdown/OptimizationsBreakdownPage';\nimport { usePatternFlyTheme } from './hooks/usePatternFlyTheme';\n\nconst notFound = <ErrorPage status=\"404\" statusMessage=\"Page not found\" />;\n\n/**\n * NFS Optimizations page loader: list + breakdown only.\n * OpenShift is a separate PageBlueprint, not a child of this mount.\n */\nexport function OptimizationsRouter() {\n usePatternFlyTheme();\n\n return (\n <Routes>\n <Route path=\"/\" element={<OptimizationsPage />} />\n <Route path=\"/:id/*\" element={<OptimizationsBreakdownPage />} />\n <Route path=\"*\" element={notFound} />\n </Routes>\n );\n}\n\n/** @public Legacy ResourceOptimizationPage mount (list + breakdown). */\nexport function Router() {\n usePatternFlyTheme();\n\n return (\n <Routes>\n <Route path=\"/\" element={<OptimizationsPage />} />\n <Route path=\"/:id/*\" element={<OptimizationsBreakdownPage />} />\n <Route path=\"*\" element={notFound} />\n </Routes>\n );\n}\n"],"names":[],"mappings":";;;;;;;AAsBA,MAAM,2BAAW,GAAA,CAAC,SAAA,EAAA,EAAU,MAAA,EAAO,KAAA,EAAM,eAAc,gBAAA,EAAiB,CAAA;AAMjE,SAAS,mBAAA,GAAsB;AACpC,EAAA,kBAAA,EAAmB;AAEnB,EAAA,4BACG,MAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,SAAM,IAAA,EAAK,GAAA,EAAI,OAAA,kBAAS,GAAA,CAAC,qBAAkB,CAAA,EAAI,CAAA;AAAA,wBAC/C,KAAA,EAAA,EAAM,IAAA,EAAK,UAAS,OAAA,kBAAS,GAAA,CAAC,8BAA2B,CAAA,EAAI,CAAA;AAAA,oBAC9D,GAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAK,GAAA,EAAI,SAAS,QAAA,EAAU;AAAA,GAAA,EACrC,CAAA;AAEJ;AAGO,SAAS,MAAA,GAAS;AACvB,EAAA,kBAAA,EAAmB;AAEnB,EAAA,4BACG,MAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,SAAM,IAAA,EAAK,GAAA,EAAI,OAAA,kBAAS,GAAA,CAAC,qBAAkB,CAAA,EAAI,CAAA;AAAA,wBAC/C,KAAA,EAAA,EAAM,IAAA,EAAK,UAAS,OAAA,kBAAS,GAAA,CAAC,8BAA2B,CAAA,EAAI,CAAA;AAAA,oBAC9D,GAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAK,GAAA,EAAI,SAAS,QAAA,EAAU;AAAA,GAAA,EACrC,CAAA;AAEJ;;;;"}
@@ -0,0 +1,136 @@
1
+ import * as react from 'react';
2
+ import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
3
+ import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
4
+
5
+ /**
6
+ * Cost Management plugin for the Backstage new frontend system.
7
+ * @alpha
8
+ */
9
+ declare const _default: _backstage_frontend_plugin_api.OverridableFrontendPlugin<{
10
+ root: _backstage_core_plugin_api.RouteRef<undefined>;
11
+ openShift: _backstage_core_plugin_api.RouteRef<undefined>;
12
+ breakdown: _backstage_core_plugin_api.SubRouteRef<_backstage_core_plugin_api.PathParams<"/:id/*">>;
13
+ }, {}, {
14
+ "api:cost-management/cost-management-slim": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
15
+ kind: "api";
16
+ name: "cost-management-slim";
17
+ config: {};
18
+ configInput: {};
19
+ output: _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.AnyApiFactory, "core.api.factory", {}>;
20
+ inputs: {};
21
+ params: <TApi, TImpl extends TApi, TDeps extends { [name in string]: unknown; }>(params: _backstage_frontend_plugin_api.ApiFactory<TApi, TImpl, TDeps>) => _backstage_frontend_plugin_api.ExtensionBlueprintParams<_backstage_frontend_plugin_api.AnyApiFactory>;
22
+ }>;
23
+ "api:cost-management/optimizations": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
24
+ kind: "api";
25
+ name: "optimizations";
26
+ config: {};
27
+ configInput: {};
28
+ output: _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.AnyApiFactory, "core.api.factory", {}>;
29
+ inputs: {};
30
+ params: <TApi, TImpl extends TApi, TDeps extends { [name in string]: unknown; }>(params: _backstage_frontend_plugin_api.ApiFactory<TApi, TImpl, TDeps>) => _backstage_frontend_plugin_api.ExtensionBlueprintParams<_backstage_frontend_plugin_api.AnyApiFactory>;
31
+ }>;
32
+ "api:cost-management/orchestrator-slim": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
33
+ kind: "api";
34
+ name: "orchestrator-slim";
35
+ config: {};
36
+ configInput: {};
37
+ output: _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.AnyApiFactory, "core.api.factory", {}>;
38
+ inputs: {};
39
+ params: <TApi, TImpl extends TApi, TDeps extends { [name in string]: unknown; }>(params: _backstage_frontend_plugin_api.ApiFactory<TApi, TImpl, TDeps>) => _backstage_frontend_plugin_api.ExtensionBlueprintParams<_backstage_frontend_plugin_api.AnyApiFactory>;
40
+ }>;
41
+ "icon-bundle:cost-management/cost-management-icons": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
42
+ kind: "icon-bundle";
43
+ name: "cost-management-icons";
44
+ config: {};
45
+ configInput: {};
46
+ output: _backstage_frontend_plugin_api.ExtensionDataRef<{
47
+ [x: string]: _backstage_frontend_plugin_api.IconComponent | _backstage_frontend_plugin_api.IconElement;
48
+ }, "core.icons", {}>;
49
+ inputs: {};
50
+ params: {
51
+ icons: { [key in string]: _backstage_frontend_plugin_api.IconComponent | _backstage_frontend_plugin_api.IconElement; };
52
+ };
53
+ }>;
54
+ "page:cost-management": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
55
+ kind: "page";
56
+ name: undefined;
57
+ config: {
58
+ path: string | undefined;
59
+ title: string | undefined;
60
+ };
61
+ configInput: {
62
+ path?: string | undefined;
63
+ title?: string | undefined;
64
+ };
65
+ output: _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
66
+ optional: true;
67
+ }> | _backstage_frontend_plugin_api.ExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.title", {
68
+ optional: true;
69
+ }> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.IconElement, "core.icon", {
70
+ optional: true;
71
+ }>;
72
+ inputs: {
73
+ pages: _backstage_frontend_plugin_api.ExtensionInput<_backstage_frontend_plugin_api.ConfigurableExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
74
+ optional: true;
75
+ }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.title", {
76
+ optional: true;
77
+ }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<_backstage_frontend_plugin_api.IconElement, "core.icon", {
78
+ optional: true;
79
+ }>, {
80
+ singleton: false;
81
+ optional: false;
82
+ internal: false;
83
+ }>;
84
+ };
85
+ params: {
86
+ path: string;
87
+ title?: string;
88
+ icon?: _backstage_frontend_plugin_api.IconElement;
89
+ loader?: () => Promise<react.JSX.Element>;
90
+ routeRef?: _backstage_frontend_plugin_api.RouteRef;
91
+ noHeader?: boolean;
92
+ };
93
+ }>;
94
+ "page:cost-management/openshift": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
95
+ kind: "page";
96
+ name: "openshift";
97
+ config: {
98
+ path: string | undefined;
99
+ title: string | undefined;
100
+ };
101
+ configInput: {
102
+ path?: string | undefined;
103
+ title?: string | undefined;
104
+ };
105
+ output: _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
106
+ optional: true;
107
+ }> | _backstage_frontend_plugin_api.ExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.title", {
108
+ optional: true;
109
+ }> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.IconElement, "core.icon", {
110
+ optional: true;
111
+ }>;
112
+ inputs: {
113
+ pages: _backstage_frontend_plugin_api.ExtensionInput<_backstage_frontend_plugin_api.ConfigurableExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
114
+ optional: true;
115
+ }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.title", {
116
+ optional: true;
117
+ }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<_backstage_frontend_plugin_api.IconElement, "core.icon", {
118
+ optional: true;
119
+ }>, {
120
+ singleton: false;
121
+ optional: false;
122
+ internal: false;
123
+ }>;
124
+ };
125
+ params: {
126
+ path: string;
127
+ title?: string;
128
+ icon?: _backstage_frontend_plugin_api.IconElement;
129
+ loader?: () => Promise<react.JSX.Element>;
130
+ routeRef?: _backstage_frontend_plugin_api.RouteRef;
131
+ noHeader?: boolean;
132
+ };
133
+ }>;
134
+ }>;
135
+
136
+ export { _default as default };
@@ -0,0 +1,108 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { fetchApiRef, discoveryApiRef, identityApiRef } from '@backstage/core-plugin-api';
3
+ import { ApiBlueprint, createApiFactory, PageBlueprint, createFrontendPlugin } from '@backstage/frontend-plugin-api';
4
+ import { IconBundleBlueprint } from '@backstage/plugin-app-react';
5
+ import { OptimizationsClient, OrchestratorSlimClient, CostManagementSlimClient } from '@red-hat-developer-hub/plugin-cost-management-common/clients';
6
+ import { optimizationsApiRef, orchestratorSlimApiRef, costManagementSlimApiRef } from './apis.esm.js';
7
+ import '@material-ui/core/SvgIcon';
8
+ import { CostManagementIconOutlined } from './components/icon/CostManagementIconOutlined.esm.js';
9
+ import { rootRouteRef, openShiftRouteRef, optimizationsBreakdownRouteRef } from './routes.esm.js';
10
+
11
+ const optimizationsApi = ApiBlueprint.make({
12
+ name: "optimizations",
13
+ params: (defineParams) => defineParams(
14
+ createApiFactory({
15
+ api: optimizationsApiRef,
16
+ deps: {
17
+ discoveryApi: discoveryApiRef,
18
+ fetchApi: fetchApiRef
19
+ },
20
+ factory: ({ discoveryApi, fetchApi }) => new OptimizationsClient({
21
+ discoveryApi,
22
+ fetchApi
23
+ })
24
+ })
25
+ )
26
+ });
27
+ const orchestratorSlimApi = ApiBlueprint.make({
28
+ name: "orchestrator-slim",
29
+ params: (defineParams) => defineParams(
30
+ createApiFactory({
31
+ api: orchestratorSlimApiRef,
32
+ deps: {
33
+ discoveryApi: discoveryApiRef,
34
+ fetchApi: fetchApiRef,
35
+ identityApi: identityApiRef
36
+ },
37
+ factory: ({ discoveryApi, fetchApi, identityApi }) => new OrchestratorSlimClient({
38
+ discoveryApi,
39
+ fetchApi,
40
+ identityApi
41
+ })
42
+ })
43
+ )
44
+ });
45
+ const costManagementSlimApi = ApiBlueprint.make({
46
+ name: "cost-management-slim",
47
+ params: (defineParams) => defineParams(
48
+ createApiFactory({
49
+ api: costManagementSlimApiRef,
50
+ deps: {
51
+ discoveryApi: discoveryApiRef,
52
+ fetchApi: fetchApiRef
53
+ },
54
+ factory: ({ discoveryApi, fetchApi }) => new CostManagementSlimClient({
55
+ discoveryApi,
56
+ fetchApi
57
+ })
58
+ })
59
+ )
60
+ });
61
+ const costManagementIcons = IconBundleBlueprint.make({
62
+ name: "cost-management-icons",
63
+ params: {
64
+ icons: {
65
+ costManagementIconOutlined: CostManagementIconOutlined
66
+ }
67
+ }
68
+ });
69
+ const optimizationsPage = PageBlueprint.make({
70
+ params: {
71
+ path: "/cost-management/optimizations",
72
+ routeRef: rootRouteRef,
73
+ title: "Optimizations",
74
+ icon: /* @__PURE__ */ jsx(CostManagementIconOutlined, {}),
75
+ noHeader: true,
76
+ loader: () => import('./Router.esm.js').then((m) => /* @__PURE__ */ jsx(m.OptimizationsRouter, {}))
77
+ }
78
+ });
79
+ const openShiftPage = PageBlueprint.make({
80
+ name: "openshift",
81
+ params: {
82
+ path: "/cost-management/openshift",
83
+ routeRef: openShiftRouteRef,
84
+ title: "Cost Management",
85
+ icon: /* @__PURE__ */ jsx(CostManagementIconOutlined, {}),
86
+ noHeader: true,
87
+ loader: () => import('./pages/openshift/OpenShiftPage.esm.js').then((m) => /* @__PURE__ */ jsx(m.OpenShiftPage, {}))
88
+ }
89
+ });
90
+ var alpha = createFrontendPlugin({
91
+ pluginId: "cost-management",
92
+ extensions: [
93
+ optimizationsApi,
94
+ orchestratorSlimApi,
95
+ costManagementSlimApi,
96
+ costManagementIcons,
97
+ optimizationsPage,
98
+ openShiftPage
99
+ ],
100
+ routes: {
101
+ root: rootRouteRef,
102
+ openShift: openShiftRouteRef,
103
+ breakdown: optimizationsBreakdownRouteRef
104
+ }
105
+ });
106
+
107
+ export { alpha as default };
108
+ //# sourceMappingURL=alpha.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alpha.esm.js","sources":["../src/alpha.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * New Frontend System entry (`./alpha`).\n *\n * @packageDocumentation\n */\n\nimport {\n discoveryApiRef,\n fetchApiRef,\n identityApiRef,\n} from '@backstage/core-plugin-api';\nimport {\n ApiBlueprint,\n createApiFactory,\n createFrontendPlugin,\n PageBlueprint,\n} from '@backstage/frontend-plugin-api';\nimport { IconBundleBlueprint } from '@backstage/plugin-app-react';\nimport {\n CostManagementSlimClient,\n OptimizationsClient,\n OrchestratorSlimClient,\n} from '@red-hat-developer-hub/plugin-cost-management-common/clients';\nimport {\n costManagementSlimApiRef,\n optimizationsApiRef,\n orchestratorSlimApiRef,\n} from './apis';\nimport { CostManagementIconOutlined } from './components/icon';\nimport {\n optimizationsBreakdownRouteRef,\n openShiftRouteRef,\n rootRouteRef,\n} from './routes';\n\nconst optimizationsApi = ApiBlueprint.make({\n name: 'optimizations',\n params: defineParams =>\n defineParams(\n createApiFactory({\n api: optimizationsApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ discoveryApi, fetchApi }) =>\n new OptimizationsClient({\n discoveryApi,\n fetchApi,\n }),\n }),\n ),\n});\n\nconst orchestratorSlimApi = ApiBlueprint.make({\n name: 'orchestrator-slim',\n params: defineParams =>\n defineParams(\n createApiFactory({\n api: orchestratorSlimApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n identityApi: identityApiRef,\n },\n factory: ({ discoveryApi, fetchApi, identityApi }) =>\n new OrchestratorSlimClient({\n discoveryApi,\n fetchApi,\n identityApi,\n }),\n }),\n ),\n});\n\nconst costManagementSlimApi = ApiBlueprint.make({\n name: 'cost-management-slim',\n params: defineParams =>\n defineParams(\n createApiFactory({\n api: costManagementSlimApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ discoveryApi, fetchApi }) =>\n new CostManagementSlimClient({\n discoveryApi,\n fetchApi,\n }),\n }),\n ),\n});\n\nconst costManagementIcons = IconBundleBlueprint.make({\n name: 'cost-management-icons',\n params: {\n icons: {\n costManagementIconOutlined: CostManagementIconOutlined,\n },\n },\n});\n\nconst optimizationsPage = PageBlueprint.make({\n params: {\n path: '/cost-management/optimizations',\n routeRef: rootRouteRef,\n title: 'Optimizations',\n icon: <CostManagementIconOutlined />,\n noHeader: true,\n loader: () => import('./Router').then(m => <m.OptimizationsRouter />),\n },\n});\n\nconst openShiftPage = PageBlueprint.make({\n name: 'openshift',\n params: {\n path: '/cost-management/openshift',\n routeRef: openShiftRouteRef,\n title: 'Cost Management',\n icon: <CostManagementIconOutlined />,\n noHeader: true,\n loader: () =>\n import('./pages/openshift/OpenShiftPage').then(m => <m.OpenShiftPage />),\n },\n});\n\n/**\n * Cost Management plugin for the Backstage new frontend system.\n * @alpha\n */\nexport default createFrontendPlugin({\n pluginId: 'cost-management',\n extensions: [\n optimizationsApi,\n orchestratorSlimApi,\n costManagementSlimApi,\n costManagementIcons,\n optimizationsPage,\n openShiftPage,\n ],\n routes: {\n root: rootRouteRef,\n openShift: openShiftRouteRef,\n breakdown: optimizationsBreakdownRouteRef,\n },\n});\n"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -48,7 +48,7 @@ declare const AnalyticsIconOutlined: (props: SvgIconProps) => react_jsx_runtime.
48
48
  */
49
49
  declare const AnalyticsIconFilled: (props: SvgIconProps) => react_jsx_runtime.JSX.Element;
50
50
 
51
- /** @public */
51
+ /** @public Legacy ResourceOptimizationPage mount (list + breakdown). */
52
52
  declare function Router(): react_jsx_runtime.JSX.Element;
53
53
 
54
54
  /** @public */
@@ -10,6 +10,7 @@ import { PageHeader } from './components/PageHeader.esm.js';
10
10
  import { TableToolbar } from './components/TableToolbar.esm.js';
11
11
  import { useApi } from '@backstage/core-plugin-api';
12
12
  import { costManagementSlimApiRef } from '../../apis.esm.js';
13
+ import { usePatternFlyTheme } from '../../hooks/usePatternFlyTheme.esm.js';
13
14
  import useAsync from 'react-use/lib/useAsync';
14
15
  import { CURRENCY_SYMBOLS } from '../../constants/currencies.esm.js';
15
16
  import { DownloadIconButton } from './components/DownloadIconButton.esm.js';
@@ -109,6 +110,7 @@ function buildCostManagementQueryParams(config, options = {}) {
109
110
  return queryParams;
110
111
  }
111
112
  function OpenShiftPage() {
113
+ usePatternFlyTheme();
112
114
  const api = useApi(costManagementSlimApiRef);
113
115
  const [groupBy, setGroupBy] = useState("project");
114
116
  const [overheadDistribution, setOverheadDistribution] = useState("distribute");
@@ -1 +1 @@
1
- {"version":3,"file":"OpenShiftPage.esm.js","sources":["../../../src/pages/openshift/OpenShiftPage.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useMemo, useState, useCallback, useRef } from 'react';\nimport type { ExportFormat } from '@red-hat-developer-hub/plugin-cost-management-common/clients';\nimport {\n Table,\n TableColumn,\n InfoCard,\n ResponseErrorPanel,\n} from '@backstage/core-components';\nimport Typography from '@material-ui/core/Typography';\nimport { BasePage } from '../../components/BasePage';\nimport { PageLayout } from '../../components/PageLayout';\nimport { Filters } from './components/Filters';\nimport { Divider, useTheme } from '@material-ui/core';\nimport { PageHeader } from './components/PageHeader';\nimport { TableToolbar } from './components/TableToolbar';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { costManagementSlimApiRef } from '../../apis';\nimport useAsync from 'react-use/lib/useAsync';\nimport { CURRENCY_SYMBOLS } from '../../constants/currencies';\nimport { DownloadIconButton } from './components/DownloadIconButton';\n\nconst formatCurrency = (value: number, currencyCode: string): string => {\n const symbol = CURRENCY_SYMBOLS[currencyCode] || currencyCode;\n return `${symbol}${value.toLocaleString('en-US', {\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n })}`;\n};\n\ninterface ProjectCost {\n id: string;\n projectName: string;\n clusterId?: string;\n cost: number;\n costPercentage: number;\n monthOverMonthChange: number;\n monthOverMonthValue: number;\n includesOverhead: boolean;\n previousPeriodCost: number;\n infrastructureCost: number;\n infrastructureCostPercentage: number;\n supplementaryCost: number;\n supplementaryCostPercentage: number;\n}\n\n/**\n * Generates date range text based on time range selection\n * @param timeRange - 'month-to-date' or 'previous-month'\n * @returns Formatted string like \"December 1-3\" or \"November 1-30\"\n */\nfunction getDateRangeText(timeRange: string): string {\n const now = new Date();\n const currentMonth = now.getMonth();\n const currentYear = now.getFullYear();\n const currentDay = now.getDate();\n\n if (timeRange === 'month-to-date') {\n // Current month: MONTH 1-<CURRENT_DAY>\n const monthName = now.toLocaleString('en-US', { month: 'long' });\n return `${monthName} 1-${currentDay}`;\n }\n // Previous month: PREVIOUS_MONTH 1-<LAST_DAY>\n const prevMonth = currentMonth === 0 ? 11 : currentMonth - 1;\n const prevYear = currentMonth === 0 ? currentYear - 1 : currentYear;\n const prevMonthDate = new Date(prevYear, prevMonth + 1, 0); // Last day of previous month\n const lastDay = prevMonthDate.getDate();\n const monthName = prevMonthDate.toLocaleString('en-US', { month: 'long' });\n return `${monthName} 1-${lastDay}`;\n}\n\n/**\n * Configuration for building query parameters\n */\ninterface QueryParamsConfig {\n groupBy: string;\n selectedTag: string;\n overheadDistribution: string;\n timeRange: string;\n currency: string;\n showPlatformSum: boolean;\n filterBy: string;\n filterValue: string;\n filterOperation: string;\n selectedTagKey: string;\n selectedTagValue: string;\n sortField: string | null;\n sortDirection: 'asc' | 'desc';\n}\n\n/**\n * Options for building query parameters\n */\ninterface BuildQueryParamsOptions {\n /** Pagination limit - omit for download (uses 0) */\n limit?: number;\n /** Pagination offset - omit for download */\n offset?: number;\n /** Specific item name to filter by (for row-level download) */\n specificItemName?: string;\n}\n\n/**\n * Builds query parameters for cost management API requests\n * Shared between data fetching and download functionality\n */\nfunction buildCostManagementQueryParams(\n config: QueryParamsConfig,\n options: BuildQueryParamsOptions = {},\n): Record<string, string | number> {\n const {\n groupBy,\n selectedTag,\n overheadDistribution,\n timeRange,\n currency,\n showPlatformSum,\n filterBy,\n filterValue,\n filterOperation,\n selectedTagKey,\n selectedTagValue,\n sortField,\n sortDirection,\n } = config;\n\n const { limit, offset, specificItemName } = options;\n\n // Build group by parameter\n const groupByParam =\n groupBy === 'tag' ? `group_by[tag:${selectedTag}]` : `group_by[${groupBy}]`;\n\n // Determine delta parameter\n const deltaParam =\n groupBy === 'project' && overheadDistribution === 'distribute'\n ? 'distributed_cost'\n : 'cost';\n\n const timeScopeValue = timeRange === 'month-to-date' ? -1 : -2;\n\n const queryParams: Record<string, string | number> = {\n currency,\n delta: deltaParam,\n 'filter[resolution]': 'monthly',\n 'filter[time_scope_units]': 'month',\n 'filter[time_scope_value]': timeScopeValue,\n };\n\n // Add pagination if provided\n if (limit !== undefined) {\n queryParams['filter[limit]'] = limit;\n }\n if (offset !== undefined) {\n queryParams['filter[offset]'] = offset;\n }\n\n // Add category parameter when showPlatformSum is enabled\n if (showPlatformSum) {\n queryParams.category = 'Platform';\n }\n\n queryParams[groupByParam] = '*';\n\n // Handle filtering\n if (specificItemName) {\n // Filter for specific item (row-level download)\n queryParams[`filter[${groupBy}]`] = specificItemName;\n } else if (filterBy === 'tag' && selectedTagKey && selectedTagValue) {\n // Tag filtering\n if (filterOperation === 'exact') {\n queryParams[`filter[exact:tag:${selectedTagKey}]`] = selectedTagValue;\n } else if (filterOperation === 'excludes') {\n queryParams[`exclude[tag:${selectedTagKey}]`] = selectedTagValue;\n } else {\n queryParams[`filter[tag:${selectedTagKey}]`] = selectedTagValue;\n }\n } else if (filterValue) {\n // Regular filtering\n if (filterOperation === 'exact') {\n queryParams[`filter[exact:${filterBy}]`] = filterValue;\n } else if (filterOperation === 'excludes') {\n queryParams[`exclude[${filterBy}]`] = filterValue;\n } else {\n queryParams[`filter[${filterBy}]`] = filterValue;\n }\n }\n\n // Add sorting\n let apiSortField: string;\n if (sortField) {\n if (sortField === 'cost') {\n apiSortField = deltaParam;\n } else if (sortField === 'projectName') {\n apiSortField = groupBy;\n } else {\n apiSortField = deltaParam;\n }\n queryParams[`order_by[${apiSortField}]`] = sortDirection;\n } else {\n queryParams[`order_by[${deltaParam}]`] = 'desc';\n }\n\n return queryParams;\n}\n\n/** @public */\nexport function OpenShiftPage() {\n const api = useApi(costManagementSlimApiRef);\n const [groupBy, setGroupBy] = useState('project');\n const [overheadDistribution, setOverheadDistribution] =\n useState('distribute');\n const [timeRange, setTimeRange] = useState('month-to-date');\n const [currency, setCurrency] = useState('USD');\n const [filterBy, setFilterBy] = useState('project');\n const [filterOperation, setFilterOperation] = useState('includes');\n const [filterValue, setFilterValue] = useState('');\n const [showPlatformSum, setShowPlatformSum] = useState(false);\n const [selectedRows, setSelectedRows] = useState<Set<string>>(new Set());\n const [currentPage, setCurrentPage] = useState(0);\n const [pageSize, setPageSize] = useState(5);\n const [sortField, setSortField] = useState<string | null>(null);\n const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('desc');\n const [tags, setTags] = useState<string[]>([]);\n const [selectedTag, setSelectedTag] = useState<string>('');\n const [selectedTagKey, setSelectedTagKey] = useState<string>('');\n const [selectedTagValue, setSelectedTagValue] = useState<string>('');\n const [showMonthOverMonthChange, setShowMonthOverMonthChange] =\n useState(true);\n const [showInfrastructureCost, setShowInfrastructureCost] = useState(false);\n const [showSupplementaryCost, setShowSupplementaryCost] = useState(false);\n const [isDownloading, setIsDownloading] = useState(false);\n const theme = useTheme();\n const isDarkMode = (theme.palette as any).mode === 'dark';\n\n // Ref to store display data for use in download handlers\n const displayDataRef = useRef<typeof displayData | null>(null);\n\n // Fetch tags on first load\n useAsync(async () => {\n try {\n const timeScopeValue = timeRange === 'month-to-date' ? -1 : -2;\n const response = await api.getOpenShiftTags(timeScopeValue);\n const tagsData = await response.json();\n setTags(tagsData.data || []);\n } catch {\n // Silently fail if tags can't be loaded\n setTags([]);\n }\n }, [api, timeRange]);\n\n // Build config object for query params builder (memoized to prevent unnecessary re-renders)\n const queryParamsConfig: QueryParamsConfig = useMemo(\n () => ({\n groupBy,\n selectedTag,\n overheadDistribution,\n timeRange,\n currency,\n showPlatformSum,\n filterBy,\n filterValue,\n filterOperation,\n selectedTagKey,\n selectedTagValue,\n sortField,\n sortDirection,\n }),\n [\n groupBy,\n selectedTag,\n overheadDistribution,\n timeRange,\n currency,\n showPlatformSum,\n filterBy,\n filterValue,\n filterOperation,\n selectedTagKey,\n selectedTagValue,\n sortField,\n sortDirection,\n ],\n );\n\n const {\n value: costData,\n loading,\n error,\n } = useAsync(async () => {\n // Don't make API call if groupBy is 'tag' but no tag is selected\n if (groupBy === 'tag' && !selectedTag) {\n return null;\n }\n\n const offset = currentPage * pageSize;\n const queryParams = buildCostManagementQueryParams(queryParamsConfig, {\n limit: pageSize,\n offset,\n });\n\n const response = await api.getCostManagementReport({\n query: queryParams,\n });\n return response.json();\n }, [\n currency,\n overheadDistribution,\n timeRange,\n groupBy,\n filterBy,\n filterValue,\n filterOperation,\n showPlatformSum,\n api,\n currentPage,\n pageSize,\n sortField,\n sortDirection,\n selectedTag,\n selectedTagKey,\n selectedTagValue,\n ]);\n\n const displayData = useMemo(() => {\n // If costData is null, return empty structure to keep table visible during loading\n if (!costData) {\n const today = new Date();\n const month =\n timeRange === 'previous-month'\n ? new Date(\n today.getFullYear(),\n today.getMonth() - 1,\n 1,\n ).toLocaleString('en-US', { month: 'long' })\n : today.toLocaleString('en-US', { month: 'long' });\n const endDate =\n timeRange === 'previous-month'\n ? new Date(today.getFullYear(), today.getMonth(), 0)\n .getDate()\n .toString()\n : today.getDate().toString();\n\n return {\n totalCost: 0,\n month,\n endDate,\n currencyCode: currency,\n projects: [],\n };\n }\n\n const arrayKey = `${groupBy}s` as keyof (typeof costData.data)[0];\n const groupedArray = costData.data?.[0]?.[arrayKey] as\n | Array<{ [key: string]: unknown; values: unknown[] }>\n | undefined;\n\n const projects =\n groupedArray?.map((item, index) => {\n const value =\n (item.values?.[0] as {\n cost?: {\n distributed?: { value?: number };\n total?: { value?: number };\n network_unattributed_distributed?: { value?: number };\n worker_unallocated_distributed?: { value?: number };\n platform_distributed?: { value?: number };\n storage_unattributed_distributed?: { value?: number };\n };\n infrastructure?: {\n total?: { value?: number };\n };\n supplementary?: {\n total?: { value?: number };\n };\n delta_percent?: number;\n delta_value?: number;\n }) || {};\n\n // For clusters, prefer values[0].clusters[0] (human-readable) over item.cluster (UUID)\n let itemName: string;\n let clusterId: string | undefined;\n if (groupBy === 'cluster') {\n const valueItem = item.values?.[0] as\n | { clusters?: string[]; cluster?: string }\n | undefined;\n const clustersArray = valueItem?.clusters;\n itemName =\n clustersArray && clustersArray.length > 0\n ? clustersArray[0]\n : (item.cluster as string) || 'Unknown';\n // Store the cluster UUID for display\n clusterId = (item.cluster as string) || undefined;\n } else {\n const nameField = groupBy as keyof typeof item;\n itemName = (item[nameField] as string) || 'Unknown';\n }\n\n const costField =\n groupBy === 'project' && overheadDistribution === 'distribute'\n ? 'distributed'\n : 'total';\n const costValue =\n value?.cost?.[costField as keyof typeof value.cost]?.value || 0;\n\n const deltaPercent = value?.delta_percent || 0;\n const deltaValue = value?.delta_value || 0;\n\n const infrastructureValue = value?.infrastructure?.total?.value || 0;\n const supplementaryValue = value?.supplementary?.total?.value || 0;\n\n return {\n id: `${index}`,\n projectName: itemName,\n clusterId,\n cost: costValue,\n costPercentage: 0,\n monthOverMonthChange: deltaPercent,\n monthOverMonthValue: Math.abs(deltaValue),\n includesOverhead:\n value?.cost?.network_unattributed_distributed?.value !== 0 ||\n value?.cost?.worker_unallocated_distributed?.value !== 0 ||\n value?.cost?.platform_distributed?.value !== 0 ||\n value?.cost?.storage_unattributed_distributed?.value !== 0,\n previousPeriodCost: costValue + Math.abs(deltaValue),\n infrastructureCost: infrastructureValue,\n infrastructureCostPercentage: 0,\n supplementaryCost: supplementaryValue,\n supplementaryCostPercentage: 0,\n };\n }) || [];\n\n const totalCost = costData.meta?.total?.cost?.total?.value || 0;\n const totalInfrastructureCost =\n costData.meta?.total?.infrastructure?.total?.value || 0;\n const totalSupplementaryCost =\n costData.meta?.total?.supplementary?.total?.value || 0;\n\n const currencyCode = costData.meta?.currency || currency;\n\n const projectsWithPercentage = projects.map(p => ({\n ...p,\n costPercentage: totalCost > 0 ? (p.cost / totalCost) * 100 : 0,\n infrastructureCostPercentage:\n totalInfrastructureCost > 0\n ? (p.infrastructureCost / totalInfrastructureCost) * 100\n : 0,\n supplementaryCostPercentage:\n totalSupplementaryCost > 0\n ? (p.supplementaryCost / totalSupplementaryCost) * 100\n : 0,\n }));\n\n let month: string;\n let endDate: string;\n\n if (timeRange === 'previous-month') {\n const today = new Date();\n const previousMonth = new Date(\n today.getFullYear(),\n today.getMonth() - 1,\n 1,\n );\n month = previousMonth.toLocaleString('en-US', { month: 'long' });\n const lastDayOfPreviousMonth = new Date(\n today.getFullYear(),\n today.getMonth(),\n 0,\n ).getDate();\n endDate = lastDayOfPreviousMonth.toString();\n } else {\n const today = new Date();\n month = today.toLocaleString('en-US', { month: 'long' });\n endDate = today.getDate().toString();\n }\n\n return {\n totalCost,\n month,\n endDate,\n currencyCode,\n projects: projectsWithPercentage,\n };\n }, [costData, currency, groupBy, overheadDistribution, timeRange]);\n\n // Update ref when displayData changes\n displayDataRef.current = displayData;\n\n /**\n * Builds query parameters for download request\n * @param specificItemName - Optional: specific item name to filter by (for row-level download)\n */\n const buildDownloadQueryParams = useCallback(\n (specificItemName?: string): Record<string, string | number> => {\n return buildCostManagementQueryParams(queryParamsConfig, {\n specificItemName,\n });\n },\n [queryParamsConfig],\n );\n\n /**\n * Handles download for header buttons (all data based on current filters)\n */\n const handleHeaderDownload = useCallback(\n async (format: ExportFormat) => {\n if (isDownloading) return;\n\n setIsDownloading(true);\n try {\n const queryParams = buildDownloadQueryParams();\n await api.downloadCostManagementReport({\n query: queryParams,\n format,\n });\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error(`Failed to download ${format}:`, err);\n } finally {\n setIsDownloading(false);\n }\n },\n [api, buildDownloadQueryParams, isDownloading],\n );\n\n /**\n * Handles download for row-level buttons (specific item)\n */\n const handleRowDownload = useCallback(\n async (itemName: string, format: ExportFormat) => {\n if (isDownloading) return;\n\n setIsDownloading(true);\n try {\n const queryParams = buildDownloadQueryParams(itemName);\n await api.downloadCostManagementReport({\n query: queryParams,\n format,\n });\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error(`Failed to download ${format} for ${itemName}:`, err);\n } finally {\n setIsDownloading(false);\n }\n },\n [api, buildDownloadQueryParams, isDownloading],\n );\n\n const handleRowSelect = useCallback(\n (rowId: string, isSelected: boolean) => {\n const newSelectedRows = new Set(selectedRows);\n if (isSelected) {\n newSelectedRows.add(rowId);\n } else {\n newSelectedRows.delete(rowId);\n }\n setSelectedRows(newSelectedRows);\n },\n [selectedRows],\n );\n\n const handleSelectAll = useCallback(\n (isSelected: boolean) => {\n if (isSelected && displayData) {\n setSelectedRows(\n new Set(displayData.projects.map(project => project.id)),\n );\n } else {\n setSelectedRows(new Set());\n }\n },\n [displayData],\n );\n\n const handlePageChange = useCallback((page: number, newPageSize: number) => {\n setCurrentPage(page);\n setPageSize(newPageSize);\n }, []);\n\n const handleRowsPerPageChange = useCallback((newPageSize: number) => {\n setPageSize(newPageSize);\n setCurrentPage(0);\n }, []);\n\n const totalCount = costData?.meta?.count || 0;\n\n const isAllSelected =\n displayData !== null &&\n selectedRows.size === displayData.projects.length &&\n displayData.projects.length > 0;\n const isIndeterminate =\n displayData !== null &&\n selectedRows.size > 0 &&\n selectedRows.size < displayData.projects.length;\n\n const columns = useMemo<TableColumn<ProjectCost>[]>(() => {\n const getChangeColor = (change: number) => {\n if (change < 0) return '#d32f2f';\n if (isDarkMode) return '#4BB543';\n return '#2e7d32';\n };\n\n const cols: TableColumn<ProjectCost>[] = [\n {\n title: (\n <div style={{ marginLeft: 0, paddingLeft: 0 }}>\n <input\n type=\"checkbox\"\n checked={isAllSelected}\n ref={input => {\n if (input) input.indeterminate = isIndeterminate;\n }}\n onChange={e => {\n e.stopPropagation();\n handleSelectAll(e.target.checked);\n }}\n style={{\n width: '18px',\n height: '18px',\n cursor: 'pointer',\n margin: 0,\n padding: 0,\n }}\n />\n </div>\n ),\n field: 'checkbox',\n sorting: false,\n width: '40px',\n cellStyle: {\n paddingLeft: '4px',\n paddingRight: '4px',\n },\n headerStyle: {\n paddingLeft: '4px',\n paddingRight: '4px',\n },\n render: data => (\n <div style={{ paddingRight: '4px' }}>\n <input\n type=\"checkbox\"\n checked={selectedRows.has(data.id)}\n onChange={e => handleRowSelect(data.id, e.target.checked)}\n style={{\n width: '18px',\n height: '18px',\n cursor: 'pointer',\n margin: 0,\n padding: 0,\n }}\n />\n </div>\n ),\n },\n {\n title: (\n <Typography variant=\"body2\" style={{ fontWeight: 'bold' }}>\n {groupBy.charAt(0).toLocaleUpperCase('en-US') + groupBy.slice(1)}{' '}\n name\n </Typography>\n ),\n field: 'projectName',\n cellStyle: { minWidth: 350 },\n headerStyle: { minWidth: 350 },\n render: data => (\n <div>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '8px',\n }}\n >\n <Typography variant=\"body2\">{data.projectName}</Typography>\n {groupBy === 'project' && data.includesOverhead && (\n <Typography\n variant=\"caption\"\n style={{\n padding: '2px 6px',\n backgroundColor: '#F5F5F5',\n border: '1px solid #D2D2D2',\n borderRadius: '16px',\n color: 'black',\n whiteSpace: 'nowrap',\n }}\n >\n Includes overhead\n </Typography>\n )}\n </div>\n {groupBy === 'cluster' && data.clusterId && (\n <Typography\n variant=\"caption\"\n style={{ color: '#666', display: 'block', marginTop: 10 }}\n >\n {data.clusterId}\n </Typography>\n )}\n </div>\n ),\n },\n ];\n\n if (showMonthOverMonthChange) {\n cols.push({\n title: 'Month over month change',\n field: 'monthOverMonthChange',\n sorting: false,\n render: data => (\n <div>\n <div\n style={{\n color: getChangeColor(data.monthOverMonthChange),\n }}\n >\n {Math.abs(data.monthOverMonthChange).toFixed(2)}%\n {data.monthOverMonthChange > 0 ? ' ▲' : ' ▼'}\n </div>\n <div style={{ fontSize: '0.75rem', color: '#666' }}>\n {formatCurrency(\n data.monthOverMonthValue,\n displayData?.currencyCode || '',\n )}{' '}\n for {getDateRangeText(timeRange)}\n </div>\n </div>\n ),\n });\n }\n\n cols.push({\n title: 'Cost',\n field: 'cost',\n render: data => (\n <div>\n <div>\n {formatCurrency(data.cost, displayData?.currencyCode || '')}\n </div>\n <div style={{ fontSize: '0.75rem', color: '#666' }}>\n {data.costPercentage.toFixed(2)}% of cost\n </div>\n </div>\n ),\n });\n\n if (showInfrastructureCost) {\n cols.push({\n title: 'Infrastructure cost',\n field: 'infrastructureCost',\n render: data => (\n <div>\n <div>\n {formatCurrency(\n data.infrastructureCost,\n displayData?.currencyCode || '',\n )}\n </div>\n <div style={{ fontSize: '0.75rem', color: '#666' }}>\n {data.infrastructureCostPercentage.toFixed(2)}% of cost\n </div>\n </div>\n ),\n });\n }\n\n if (showSupplementaryCost) {\n cols.push({\n title: 'Supplementary cost',\n field: 'supplementaryCost',\n render: data => (\n <div>\n <div>\n {formatCurrency(\n data.supplementaryCost,\n displayData?.currencyCode || '',\n )}\n </div>\n <div style={{ fontSize: '0.75rem', color: '#666' }}>\n {data.supplementaryCostPercentage.toFixed(2)}% of cost\n </div>\n </div>\n ),\n });\n }\n\n cols.push({\n title: 'Actions',\n field: 'actions',\n sorting: false,\n render: data => (\n <div style={{ display: 'flex', gap: '8px' }}>\n <DownloadIconButton\n label=\"CSV\"\n variant={isDarkMode ? 'white' : 'black'}\n onClick={() => handleRowDownload(data.projectName, 'csv')}\n disabled={isDownloading}\n />\n <DownloadIconButton\n label=\"JSON\"\n variant={isDarkMode ? 'white' : 'black'}\n onClick={() => handleRowDownload(data.projectName, 'json')}\n disabled={isDownloading}\n />\n </div>\n ),\n });\n\n return cols;\n }, [\n handleRowSelect,\n handleRowDownload,\n isAllSelected,\n isIndeterminate,\n isDownloading,\n selectedRows,\n handleSelectAll,\n displayData?.currencyCode,\n groupBy,\n showMonthOverMonthChange,\n showInfrastructureCost,\n showSupplementaryCost,\n timeRange,\n isDarkMode,\n ]);\n\n const handleOrderChange = useCallback(\n (orderBy: number, orderDirection: 'asc' | 'desc') => {\n // If orderBy is -1, it means \"no sorting\" - ignore it to prevent removing sorting\n if (orderBy === -1) {\n return;\n }\n\n const column = columns[orderBy];\n if (\n column?.field &&\n column.field !== 'actions' &&\n column.sorting !== false\n ) {\n const newField = column.field as string;\n setSortField(newField);\n setSortDirection(orderDirection);\n\n setCurrentPage(0);\n }\n },\n [columns],\n );\n\n if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n return (\n <BasePage pageTitle=\"\" withContentPadding>\n <PageHeader\n totalCost={displayData.totalCost}\n month={displayData.month}\n endDate={displayData.endDate}\n currencyCode={displayData.currencyCode}\n customStyle={{ marginTop: '-24px' }}\n />\n\n <Divider\n style={{\n marginBottom: 24,\n marginLeft: '-24px',\n marginRight: '-24px',\n width: 'calc(100% + 48px)',\n }}\n />\n\n <PageLayout>\n <PageLayout.Filters>\n <Filters\n groupBy={groupBy}\n overheadDistribution={overheadDistribution}\n timeRange={timeRange}\n currency={currency}\n filterBy={filterBy}\n filterOperation={filterOperation}\n filterValue={filterValue}\n tags={tags}\n onGroupByChange={value => {\n setGroupBy(value);\n setCurrentPage(0);\n if (value !== 'tag') {\n setSelectedTag('');\n }\n // Reset showPlatformSum when groupBy changes away from 'project'\n if (value !== 'project') {\n setShowPlatformSum(false);\n }\n // Sync filterBy with groupBy and reset filter value\n setFilterBy(value);\n setFilterValue('');\n // Reset tag-related filter fields\n setSelectedTagKey('');\n setSelectedTagValue('');\n }}\n selectedTag={selectedTag}\n onSelectedTagChange={value => {\n setSelectedTag(value);\n setCurrentPage(0);\n }}\n onOverheadDistributionChange={value => {\n setOverheadDistribution(value);\n setCurrentPage(0);\n }}\n onTimeRangeChange={value => {\n setTimeRange(value);\n setCurrentPage(0);\n }}\n onCurrencyChange={value => {\n setCurrency(value);\n setCurrentPage(0);\n }}\n onFilterByChange={value => {\n setFilterBy(value);\n setCurrentPage(0);\n // Clear tag-related selections when filterBy changes away from 'tag'\n if (value !== 'tag') {\n setSelectedTagKey('');\n setSelectedTagValue('');\n }\n }}\n onFilterOperationChange={value => {\n setFilterOperation(value);\n setCurrentPage(0);\n }}\n onFilterValueChange={value => {\n setFilterValue(value);\n setCurrentPage(0);\n }}\n selectedTagKey={selectedTagKey}\n selectedTagValue={selectedTagValue}\n onSelectedTagKeyChange={value => {\n setSelectedTagKey(value);\n setSelectedTagValue('');\n setCurrentPage(0);\n }}\n onSelectedTagValueChange={value => {\n setSelectedTagValue(value);\n setCurrentPage(0);\n }}\n />\n </PageLayout.Filters>\n <PageLayout.Table>\n <div style={{ flex: 1 }}>\n <InfoCard>\n <Table<ProjectCost>\n data={displayData?.projects || []}\n isLoading={loading}\n components={{\n Toolbar: () => (\n <TableToolbar\n showPlatformSum={showPlatformSum}\n setShowPlatformSum={setShowPlatformSum}\n projectsCount={displayData?.projects?.length || 0}\n groupBy={groupBy}\n showMonthOverMonthChange={showMonthOverMonthChange}\n setShowMonthOverMonthChange={setShowMonthOverMonthChange}\n showInfrastructureCost={showInfrastructureCost}\n setShowInfrastructureCost={setShowInfrastructureCost}\n showSupplementaryCost={showSupplementaryCost}\n setShowSupplementaryCost={setShowSupplementaryCost}\n onDownloadCsv={() => handleHeaderDownload('csv')}\n onDownloadJson={() => handleHeaderDownload('json')}\n isDownloading={isDownloading}\n />\n ),\n }}\n columns={columns}\n options={{\n paging: true,\n pageSize: pageSize,\n pageSizeOptions: [5, 10, 25, 50],\n search: false,\n sorting: true,\n padding: 'dense',\n thirdSortClick: false,\n }}\n totalCount={totalCount}\n page={currentPage}\n onPageChange={handlePageChange}\n onRowsPerPageChange={handleRowsPerPageChange}\n onOrderChange={handleOrderChange}\n style={{ outline: 'none' }}\n localization={{\n pagination: {\n labelRowsPerPage: 'rows',\n },\n }}\n />\n </InfoCard>\n </div>\n </PageLayout.Table>\n </PageLayout>\n </BasePage>\n );\n}\nOpenShiftPage.displayName = 'OpenShiftPage';\n"],"names":["monthName","month","endDate"],"mappings":"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"}
1
+ {"version":3,"file":"OpenShiftPage.esm.js","sources":["../../../src/pages/openshift/OpenShiftPage.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useMemo, useState, useCallback, useRef } from 'react';\nimport type { ExportFormat } from '@red-hat-developer-hub/plugin-cost-management-common/clients';\nimport {\n Table,\n TableColumn,\n InfoCard,\n ResponseErrorPanel,\n} from '@backstage/core-components';\nimport Typography from '@material-ui/core/Typography';\nimport { BasePage } from '../../components/BasePage';\nimport { PageLayout } from '../../components/PageLayout';\nimport { Filters } from './components/Filters';\nimport { Divider, useTheme } from '@material-ui/core';\nimport { PageHeader } from './components/PageHeader';\nimport { TableToolbar } from './components/TableToolbar';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { costManagementSlimApiRef } from '../../apis';\nimport { usePatternFlyTheme } from '../../hooks/usePatternFlyTheme';\nimport useAsync from 'react-use/lib/useAsync';\nimport { CURRENCY_SYMBOLS } from '../../constants/currencies';\nimport { DownloadIconButton } from './components/DownloadIconButton';\n\nconst formatCurrency = (value: number, currencyCode: string): string => {\n const symbol = CURRENCY_SYMBOLS[currencyCode] || currencyCode;\n return `${symbol}${value.toLocaleString('en-US', {\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n })}`;\n};\n\ninterface ProjectCost {\n id: string;\n projectName: string;\n clusterId?: string;\n cost: number;\n costPercentage: number;\n monthOverMonthChange: number;\n monthOverMonthValue: number;\n includesOverhead: boolean;\n previousPeriodCost: number;\n infrastructureCost: number;\n infrastructureCostPercentage: number;\n supplementaryCost: number;\n supplementaryCostPercentage: number;\n}\n\n/**\n * Generates date range text based on time range selection\n * @param timeRange - 'month-to-date' or 'previous-month'\n * @returns Formatted string like \"December 1-3\" or \"November 1-30\"\n */\nfunction getDateRangeText(timeRange: string): string {\n const now = new Date();\n const currentMonth = now.getMonth();\n const currentYear = now.getFullYear();\n const currentDay = now.getDate();\n\n if (timeRange === 'month-to-date') {\n // Current month: MONTH 1-<CURRENT_DAY>\n const monthName = now.toLocaleString('en-US', { month: 'long' });\n return `${monthName} 1-${currentDay}`;\n }\n // Previous month: PREVIOUS_MONTH 1-<LAST_DAY>\n const prevMonth = currentMonth === 0 ? 11 : currentMonth - 1;\n const prevYear = currentMonth === 0 ? currentYear - 1 : currentYear;\n const prevMonthDate = new Date(prevYear, prevMonth + 1, 0); // Last day of previous month\n const lastDay = prevMonthDate.getDate();\n const monthName = prevMonthDate.toLocaleString('en-US', { month: 'long' });\n return `${monthName} 1-${lastDay}`;\n}\n\n/**\n * Configuration for building query parameters\n */\ninterface QueryParamsConfig {\n groupBy: string;\n selectedTag: string;\n overheadDistribution: string;\n timeRange: string;\n currency: string;\n showPlatformSum: boolean;\n filterBy: string;\n filterValue: string;\n filterOperation: string;\n selectedTagKey: string;\n selectedTagValue: string;\n sortField: string | null;\n sortDirection: 'asc' | 'desc';\n}\n\n/**\n * Options for building query parameters\n */\ninterface BuildQueryParamsOptions {\n /** Pagination limit - omit for download (uses 0) */\n limit?: number;\n /** Pagination offset - omit for download */\n offset?: number;\n /** Specific item name to filter by (for row-level download) */\n specificItemName?: string;\n}\n\n/**\n * Builds query parameters for cost management API requests\n * Shared between data fetching and download functionality\n */\nfunction buildCostManagementQueryParams(\n config: QueryParamsConfig,\n options: BuildQueryParamsOptions = {},\n): Record<string, string | number> {\n const {\n groupBy,\n selectedTag,\n overheadDistribution,\n timeRange,\n currency,\n showPlatformSum,\n filterBy,\n filterValue,\n filterOperation,\n selectedTagKey,\n selectedTagValue,\n sortField,\n sortDirection,\n } = config;\n\n const { limit, offset, specificItemName } = options;\n\n // Build group by parameter\n const groupByParam =\n groupBy === 'tag' ? `group_by[tag:${selectedTag}]` : `group_by[${groupBy}]`;\n\n // Determine delta parameter\n const deltaParam =\n groupBy === 'project' && overheadDistribution === 'distribute'\n ? 'distributed_cost'\n : 'cost';\n\n const timeScopeValue = timeRange === 'month-to-date' ? -1 : -2;\n\n const queryParams: Record<string, string | number> = {\n currency,\n delta: deltaParam,\n 'filter[resolution]': 'monthly',\n 'filter[time_scope_units]': 'month',\n 'filter[time_scope_value]': timeScopeValue,\n };\n\n // Add pagination if provided\n if (limit !== undefined) {\n queryParams['filter[limit]'] = limit;\n }\n if (offset !== undefined) {\n queryParams['filter[offset]'] = offset;\n }\n\n // Add category parameter when showPlatformSum is enabled\n if (showPlatformSum) {\n queryParams.category = 'Platform';\n }\n\n queryParams[groupByParam] = '*';\n\n // Handle filtering\n if (specificItemName) {\n // Filter for specific item (row-level download)\n queryParams[`filter[${groupBy}]`] = specificItemName;\n } else if (filterBy === 'tag' && selectedTagKey && selectedTagValue) {\n // Tag filtering\n if (filterOperation === 'exact') {\n queryParams[`filter[exact:tag:${selectedTagKey}]`] = selectedTagValue;\n } else if (filterOperation === 'excludes') {\n queryParams[`exclude[tag:${selectedTagKey}]`] = selectedTagValue;\n } else {\n queryParams[`filter[tag:${selectedTagKey}]`] = selectedTagValue;\n }\n } else if (filterValue) {\n // Regular filtering\n if (filterOperation === 'exact') {\n queryParams[`filter[exact:${filterBy}]`] = filterValue;\n } else if (filterOperation === 'excludes') {\n queryParams[`exclude[${filterBy}]`] = filterValue;\n } else {\n queryParams[`filter[${filterBy}]`] = filterValue;\n }\n }\n\n // Add sorting\n let apiSortField: string;\n if (sortField) {\n if (sortField === 'cost') {\n apiSortField = deltaParam;\n } else if (sortField === 'projectName') {\n apiSortField = groupBy;\n } else {\n apiSortField = deltaParam;\n }\n queryParams[`order_by[${apiSortField}]`] = sortDirection;\n } else {\n queryParams[`order_by[${deltaParam}]`] = 'desc';\n }\n\n return queryParams;\n}\n\n/** @public */\nexport function OpenShiftPage() {\n usePatternFlyTheme();\n const api = useApi(costManagementSlimApiRef);\n const [groupBy, setGroupBy] = useState('project');\n const [overheadDistribution, setOverheadDistribution] =\n useState('distribute');\n const [timeRange, setTimeRange] = useState('month-to-date');\n const [currency, setCurrency] = useState('USD');\n const [filterBy, setFilterBy] = useState('project');\n const [filterOperation, setFilterOperation] = useState('includes');\n const [filterValue, setFilterValue] = useState('');\n const [showPlatformSum, setShowPlatformSum] = useState(false);\n const [selectedRows, setSelectedRows] = useState<Set<string>>(new Set());\n const [currentPage, setCurrentPage] = useState(0);\n const [pageSize, setPageSize] = useState(5);\n const [sortField, setSortField] = useState<string | null>(null);\n const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('desc');\n const [tags, setTags] = useState<string[]>([]);\n const [selectedTag, setSelectedTag] = useState<string>('');\n const [selectedTagKey, setSelectedTagKey] = useState<string>('');\n const [selectedTagValue, setSelectedTagValue] = useState<string>('');\n const [showMonthOverMonthChange, setShowMonthOverMonthChange] =\n useState(true);\n const [showInfrastructureCost, setShowInfrastructureCost] = useState(false);\n const [showSupplementaryCost, setShowSupplementaryCost] = useState(false);\n const [isDownloading, setIsDownloading] = useState(false);\n const theme = useTheme();\n const isDarkMode = (theme.palette as any).mode === 'dark';\n\n // Ref to store display data for use in download handlers\n const displayDataRef = useRef<typeof displayData | null>(null);\n\n // Fetch tags on first load\n useAsync(async () => {\n try {\n const timeScopeValue = timeRange === 'month-to-date' ? -1 : -2;\n const response = await api.getOpenShiftTags(timeScopeValue);\n const tagsData = await response.json();\n setTags(tagsData.data || []);\n } catch {\n // Silently fail if tags can't be loaded\n setTags([]);\n }\n }, [api, timeRange]);\n\n // Build config object for query params builder (memoized to prevent unnecessary re-renders)\n const queryParamsConfig: QueryParamsConfig = useMemo(\n () => ({\n groupBy,\n selectedTag,\n overheadDistribution,\n timeRange,\n currency,\n showPlatformSum,\n filterBy,\n filterValue,\n filterOperation,\n selectedTagKey,\n selectedTagValue,\n sortField,\n sortDirection,\n }),\n [\n groupBy,\n selectedTag,\n overheadDistribution,\n timeRange,\n currency,\n showPlatformSum,\n filterBy,\n filterValue,\n filterOperation,\n selectedTagKey,\n selectedTagValue,\n sortField,\n sortDirection,\n ],\n );\n\n const {\n value: costData,\n loading,\n error,\n } = useAsync(async () => {\n // Don't make API call if groupBy is 'tag' but no tag is selected\n if (groupBy === 'tag' && !selectedTag) {\n return null;\n }\n\n const offset = currentPage * pageSize;\n const queryParams = buildCostManagementQueryParams(queryParamsConfig, {\n limit: pageSize,\n offset,\n });\n\n const response = await api.getCostManagementReport({\n query: queryParams,\n });\n return response.json();\n }, [\n currency,\n overheadDistribution,\n timeRange,\n groupBy,\n filterBy,\n filterValue,\n filterOperation,\n showPlatformSum,\n api,\n currentPage,\n pageSize,\n sortField,\n sortDirection,\n selectedTag,\n selectedTagKey,\n selectedTagValue,\n ]);\n\n const displayData = useMemo(() => {\n // If costData is null, return empty structure to keep table visible during loading\n if (!costData) {\n const today = new Date();\n const month =\n timeRange === 'previous-month'\n ? new Date(\n today.getFullYear(),\n today.getMonth() - 1,\n 1,\n ).toLocaleString('en-US', { month: 'long' })\n : today.toLocaleString('en-US', { month: 'long' });\n const endDate =\n timeRange === 'previous-month'\n ? new Date(today.getFullYear(), today.getMonth(), 0)\n .getDate()\n .toString()\n : today.getDate().toString();\n\n return {\n totalCost: 0,\n month,\n endDate,\n currencyCode: currency,\n projects: [],\n };\n }\n\n const arrayKey = `${groupBy}s` as keyof (typeof costData.data)[0];\n const groupedArray = costData.data?.[0]?.[arrayKey] as\n | Array<{ [key: string]: unknown; values: unknown[] }>\n | undefined;\n\n const projects =\n groupedArray?.map((item, index) => {\n const value =\n (item.values?.[0] as {\n cost?: {\n distributed?: { value?: number };\n total?: { value?: number };\n network_unattributed_distributed?: { value?: number };\n worker_unallocated_distributed?: { value?: number };\n platform_distributed?: { value?: number };\n storage_unattributed_distributed?: { value?: number };\n };\n infrastructure?: {\n total?: { value?: number };\n };\n supplementary?: {\n total?: { value?: number };\n };\n delta_percent?: number;\n delta_value?: number;\n }) || {};\n\n // For clusters, prefer values[0].clusters[0] (human-readable) over item.cluster (UUID)\n let itemName: string;\n let clusterId: string | undefined;\n if (groupBy === 'cluster') {\n const valueItem = item.values?.[0] as\n | { clusters?: string[]; cluster?: string }\n | undefined;\n const clustersArray = valueItem?.clusters;\n itemName =\n clustersArray && clustersArray.length > 0\n ? clustersArray[0]\n : (item.cluster as string) || 'Unknown';\n // Store the cluster UUID for display\n clusterId = (item.cluster as string) || undefined;\n } else {\n const nameField = groupBy as keyof typeof item;\n itemName = (item[nameField] as string) || 'Unknown';\n }\n\n const costField =\n groupBy === 'project' && overheadDistribution === 'distribute'\n ? 'distributed'\n : 'total';\n const costValue =\n value?.cost?.[costField as keyof typeof value.cost]?.value || 0;\n\n const deltaPercent = value?.delta_percent || 0;\n const deltaValue = value?.delta_value || 0;\n\n const infrastructureValue = value?.infrastructure?.total?.value || 0;\n const supplementaryValue = value?.supplementary?.total?.value || 0;\n\n return {\n id: `${index}`,\n projectName: itemName,\n clusterId,\n cost: costValue,\n costPercentage: 0,\n monthOverMonthChange: deltaPercent,\n monthOverMonthValue: Math.abs(deltaValue),\n includesOverhead:\n value?.cost?.network_unattributed_distributed?.value !== 0 ||\n value?.cost?.worker_unallocated_distributed?.value !== 0 ||\n value?.cost?.platform_distributed?.value !== 0 ||\n value?.cost?.storage_unattributed_distributed?.value !== 0,\n previousPeriodCost: costValue + Math.abs(deltaValue),\n infrastructureCost: infrastructureValue,\n infrastructureCostPercentage: 0,\n supplementaryCost: supplementaryValue,\n supplementaryCostPercentage: 0,\n };\n }) || [];\n\n const totalCost = costData.meta?.total?.cost?.total?.value || 0;\n const totalInfrastructureCost =\n costData.meta?.total?.infrastructure?.total?.value || 0;\n const totalSupplementaryCost =\n costData.meta?.total?.supplementary?.total?.value || 0;\n\n const currencyCode = costData.meta?.currency || currency;\n\n const projectsWithPercentage = projects.map(p => ({\n ...p,\n costPercentage: totalCost > 0 ? (p.cost / totalCost) * 100 : 0,\n infrastructureCostPercentage:\n totalInfrastructureCost > 0\n ? (p.infrastructureCost / totalInfrastructureCost) * 100\n : 0,\n supplementaryCostPercentage:\n totalSupplementaryCost > 0\n ? (p.supplementaryCost / totalSupplementaryCost) * 100\n : 0,\n }));\n\n let month: string;\n let endDate: string;\n\n if (timeRange === 'previous-month') {\n const today = new Date();\n const previousMonth = new Date(\n today.getFullYear(),\n today.getMonth() - 1,\n 1,\n );\n month = previousMonth.toLocaleString('en-US', { month: 'long' });\n const lastDayOfPreviousMonth = new Date(\n today.getFullYear(),\n today.getMonth(),\n 0,\n ).getDate();\n endDate = lastDayOfPreviousMonth.toString();\n } else {\n const today = new Date();\n month = today.toLocaleString('en-US', { month: 'long' });\n endDate = today.getDate().toString();\n }\n\n return {\n totalCost,\n month,\n endDate,\n currencyCode,\n projects: projectsWithPercentage,\n };\n }, [costData, currency, groupBy, overheadDistribution, timeRange]);\n\n // Update ref when displayData changes\n displayDataRef.current = displayData;\n\n /**\n * Builds query parameters for download request\n * @param specificItemName - Optional: specific item name to filter by (for row-level download)\n */\n const buildDownloadQueryParams = useCallback(\n (specificItemName?: string): Record<string, string | number> => {\n return buildCostManagementQueryParams(queryParamsConfig, {\n specificItemName,\n });\n },\n [queryParamsConfig],\n );\n\n /**\n * Handles download for header buttons (all data based on current filters)\n */\n const handleHeaderDownload = useCallback(\n async (format: ExportFormat) => {\n if (isDownloading) return;\n\n setIsDownloading(true);\n try {\n const queryParams = buildDownloadQueryParams();\n await api.downloadCostManagementReport({\n query: queryParams,\n format,\n });\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error(`Failed to download ${format}:`, err);\n } finally {\n setIsDownloading(false);\n }\n },\n [api, buildDownloadQueryParams, isDownloading],\n );\n\n /**\n * Handles download for row-level buttons (specific item)\n */\n const handleRowDownload = useCallback(\n async (itemName: string, format: ExportFormat) => {\n if (isDownloading) return;\n\n setIsDownloading(true);\n try {\n const queryParams = buildDownloadQueryParams(itemName);\n await api.downloadCostManagementReport({\n query: queryParams,\n format,\n });\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error(`Failed to download ${format} for ${itemName}:`, err);\n } finally {\n setIsDownloading(false);\n }\n },\n [api, buildDownloadQueryParams, isDownloading],\n );\n\n const handleRowSelect = useCallback(\n (rowId: string, isSelected: boolean) => {\n const newSelectedRows = new Set(selectedRows);\n if (isSelected) {\n newSelectedRows.add(rowId);\n } else {\n newSelectedRows.delete(rowId);\n }\n setSelectedRows(newSelectedRows);\n },\n [selectedRows],\n );\n\n const handleSelectAll = useCallback(\n (isSelected: boolean) => {\n if (isSelected && displayData) {\n setSelectedRows(\n new Set(displayData.projects.map(project => project.id)),\n );\n } else {\n setSelectedRows(new Set());\n }\n },\n [displayData],\n );\n\n const handlePageChange = useCallback((page: number, newPageSize: number) => {\n setCurrentPage(page);\n setPageSize(newPageSize);\n }, []);\n\n const handleRowsPerPageChange = useCallback((newPageSize: number) => {\n setPageSize(newPageSize);\n setCurrentPage(0);\n }, []);\n\n const totalCount = costData?.meta?.count || 0;\n\n const isAllSelected =\n displayData !== null &&\n selectedRows.size === displayData.projects.length &&\n displayData.projects.length > 0;\n const isIndeterminate =\n displayData !== null &&\n selectedRows.size > 0 &&\n selectedRows.size < displayData.projects.length;\n\n const columns = useMemo<TableColumn<ProjectCost>[]>(() => {\n const getChangeColor = (change: number) => {\n if (change < 0) return '#d32f2f';\n if (isDarkMode) return '#4BB543';\n return '#2e7d32';\n };\n\n const cols: TableColumn<ProjectCost>[] = [\n {\n title: (\n <div style={{ marginLeft: 0, paddingLeft: 0 }}>\n <input\n type=\"checkbox\"\n checked={isAllSelected}\n ref={input => {\n if (input) input.indeterminate = isIndeterminate;\n }}\n onChange={e => {\n e.stopPropagation();\n handleSelectAll(e.target.checked);\n }}\n style={{\n width: '18px',\n height: '18px',\n cursor: 'pointer',\n margin: 0,\n padding: 0,\n }}\n />\n </div>\n ),\n field: 'checkbox',\n sorting: false,\n width: '40px',\n cellStyle: {\n paddingLeft: '4px',\n paddingRight: '4px',\n },\n headerStyle: {\n paddingLeft: '4px',\n paddingRight: '4px',\n },\n render: data => (\n <div style={{ paddingRight: '4px' }}>\n <input\n type=\"checkbox\"\n checked={selectedRows.has(data.id)}\n onChange={e => handleRowSelect(data.id, e.target.checked)}\n style={{\n width: '18px',\n height: '18px',\n cursor: 'pointer',\n margin: 0,\n padding: 0,\n }}\n />\n </div>\n ),\n },\n {\n title: (\n <Typography variant=\"body2\" style={{ fontWeight: 'bold' }}>\n {groupBy.charAt(0).toLocaleUpperCase('en-US') + groupBy.slice(1)}{' '}\n name\n </Typography>\n ),\n field: 'projectName',\n cellStyle: { minWidth: 350 },\n headerStyle: { minWidth: 350 },\n render: data => (\n <div>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '8px',\n }}\n >\n <Typography variant=\"body2\">{data.projectName}</Typography>\n {groupBy === 'project' && data.includesOverhead && (\n <Typography\n variant=\"caption\"\n style={{\n padding: '2px 6px',\n backgroundColor: '#F5F5F5',\n border: '1px solid #D2D2D2',\n borderRadius: '16px',\n color: 'black',\n whiteSpace: 'nowrap',\n }}\n >\n Includes overhead\n </Typography>\n )}\n </div>\n {groupBy === 'cluster' && data.clusterId && (\n <Typography\n variant=\"caption\"\n style={{ color: '#666', display: 'block', marginTop: 10 }}\n >\n {data.clusterId}\n </Typography>\n )}\n </div>\n ),\n },\n ];\n\n if (showMonthOverMonthChange) {\n cols.push({\n title: 'Month over month change',\n field: 'monthOverMonthChange',\n sorting: false,\n render: data => (\n <div>\n <div\n style={{\n color: getChangeColor(data.monthOverMonthChange),\n }}\n >\n {Math.abs(data.monthOverMonthChange).toFixed(2)}%\n {data.monthOverMonthChange > 0 ? ' ▲' : ' ▼'}\n </div>\n <div style={{ fontSize: '0.75rem', color: '#666' }}>\n {formatCurrency(\n data.monthOverMonthValue,\n displayData?.currencyCode || '',\n )}{' '}\n for {getDateRangeText(timeRange)}\n </div>\n </div>\n ),\n });\n }\n\n cols.push({\n title: 'Cost',\n field: 'cost',\n render: data => (\n <div>\n <div>\n {formatCurrency(data.cost, displayData?.currencyCode || '')}\n </div>\n <div style={{ fontSize: '0.75rem', color: '#666' }}>\n {data.costPercentage.toFixed(2)}% of cost\n </div>\n </div>\n ),\n });\n\n if (showInfrastructureCost) {\n cols.push({\n title: 'Infrastructure cost',\n field: 'infrastructureCost',\n render: data => (\n <div>\n <div>\n {formatCurrency(\n data.infrastructureCost,\n displayData?.currencyCode || '',\n )}\n </div>\n <div style={{ fontSize: '0.75rem', color: '#666' }}>\n {data.infrastructureCostPercentage.toFixed(2)}% of cost\n </div>\n </div>\n ),\n });\n }\n\n if (showSupplementaryCost) {\n cols.push({\n title: 'Supplementary cost',\n field: 'supplementaryCost',\n render: data => (\n <div>\n <div>\n {formatCurrency(\n data.supplementaryCost,\n displayData?.currencyCode || '',\n )}\n </div>\n <div style={{ fontSize: '0.75rem', color: '#666' }}>\n {data.supplementaryCostPercentage.toFixed(2)}% of cost\n </div>\n </div>\n ),\n });\n }\n\n cols.push({\n title: 'Actions',\n field: 'actions',\n sorting: false,\n render: data => (\n <div style={{ display: 'flex', gap: '8px' }}>\n <DownloadIconButton\n label=\"CSV\"\n variant={isDarkMode ? 'white' : 'black'}\n onClick={() => handleRowDownload(data.projectName, 'csv')}\n disabled={isDownloading}\n />\n <DownloadIconButton\n label=\"JSON\"\n variant={isDarkMode ? 'white' : 'black'}\n onClick={() => handleRowDownload(data.projectName, 'json')}\n disabled={isDownloading}\n />\n </div>\n ),\n });\n\n return cols;\n }, [\n handleRowSelect,\n handleRowDownload,\n isAllSelected,\n isIndeterminate,\n isDownloading,\n selectedRows,\n handleSelectAll,\n displayData?.currencyCode,\n groupBy,\n showMonthOverMonthChange,\n showInfrastructureCost,\n showSupplementaryCost,\n timeRange,\n isDarkMode,\n ]);\n\n const handleOrderChange = useCallback(\n (orderBy: number, orderDirection: 'asc' | 'desc') => {\n // If orderBy is -1, it means \"no sorting\" - ignore it to prevent removing sorting\n if (orderBy === -1) {\n return;\n }\n\n const column = columns[orderBy];\n if (\n column?.field &&\n column.field !== 'actions' &&\n column.sorting !== false\n ) {\n const newField = column.field as string;\n setSortField(newField);\n setSortDirection(orderDirection);\n\n setCurrentPage(0);\n }\n },\n [columns],\n );\n\n if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n return (\n <BasePage pageTitle=\"\" withContentPadding>\n <PageHeader\n totalCost={displayData.totalCost}\n month={displayData.month}\n endDate={displayData.endDate}\n currencyCode={displayData.currencyCode}\n customStyle={{ marginTop: '-24px' }}\n />\n\n <Divider\n style={{\n marginBottom: 24,\n marginLeft: '-24px',\n marginRight: '-24px',\n width: 'calc(100% + 48px)',\n }}\n />\n\n <PageLayout>\n <PageLayout.Filters>\n <Filters\n groupBy={groupBy}\n overheadDistribution={overheadDistribution}\n timeRange={timeRange}\n currency={currency}\n filterBy={filterBy}\n filterOperation={filterOperation}\n filterValue={filterValue}\n tags={tags}\n onGroupByChange={value => {\n setGroupBy(value);\n setCurrentPage(0);\n if (value !== 'tag') {\n setSelectedTag('');\n }\n // Reset showPlatformSum when groupBy changes away from 'project'\n if (value !== 'project') {\n setShowPlatformSum(false);\n }\n // Sync filterBy with groupBy and reset filter value\n setFilterBy(value);\n setFilterValue('');\n // Reset tag-related filter fields\n setSelectedTagKey('');\n setSelectedTagValue('');\n }}\n selectedTag={selectedTag}\n onSelectedTagChange={value => {\n setSelectedTag(value);\n setCurrentPage(0);\n }}\n onOverheadDistributionChange={value => {\n setOverheadDistribution(value);\n setCurrentPage(0);\n }}\n onTimeRangeChange={value => {\n setTimeRange(value);\n setCurrentPage(0);\n }}\n onCurrencyChange={value => {\n setCurrency(value);\n setCurrentPage(0);\n }}\n onFilterByChange={value => {\n setFilterBy(value);\n setCurrentPage(0);\n // Clear tag-related selections when filterBy changes away from 'tag'\n if (value !== 'tag') {\n setSelectedTagKey('');\n setSelectedTagValue('');\n }\n }}\n onFilterOperationChange={value => {\n setFilterOperation(value);\n setCurrentPage(0);\n }}\n onFilterValueChange={value => {\n setFilterValue(value);\n setCurrentPage(0);\n }}\n selectedTagKey={selectedTagKey}\n selectedTagValue={selectedTagValue}\n onSelectedTagKeyChange={value => {\n setSelectedTagKey(value);\n setSelectedTagValue('');\n setCurrentPage(0);\n }}\n onSelectedTagValueChange={value => {\n setSelectedTagValue(value);\n setCurrentPage(0);\n }}\n />\n </PageLayout.Filters>\n <PageLayout.Table>\n <div style={{ flex: 1 }}>\n <InfoCard>\n <Table<ProjectCost>\n data={displayData?.projects || []}\n isLoading={loading}\n components={{\n Toolbar: () => (\n <TableToolbar\n showPlatformSum={showPlatformSum}\n setShowPlatformSum={setShowPlatformSum}\n projectsCount={displayData?.projects?.length || 0}\n groupBy={groupBy}\n showMonthOverMonthChange={showMonthOverMonthChange}\n setShowMonthOverMonthChange={setShowMonthOverMonthChange}\n showInfrastructureCost={showInfrastructureCost}\n setShowInfrastructureCost={setShowInfrastructureCost}\n showSupplementaryCost={showSupplementaryCost}\n setShowSupplementaryCost={setShowSupplementaryCost}\n onDownloadCsv={() => handleHeaderDownload('csv')}\n onDownloadJson={() => handleHeaderDownload('json')}\n isDownloading={isDownloading}\n />\n ),\n }}\n columns={columns}\n options={{\n paging: true,\n pageSize: pageSize,\n pageSizeOptions: [5, 10, 25, 50],\n search: false,\n sorting: true,\n padding: 'dense',\n thirdSortClick: false,\n }}\n totalCount={totalCount}\n page={currentPage}\n onPageChange={handlePageChange}\n onRowsPerPageChange={handleRowsPerPageChange}\n onOrderChange={handleOrderChange}\n style={{ outline: 'none' }}\n localization={{\n pagination: {\n labelRowsPerPage: 'rows',\n },\n }}\n />\n </InfoCard>\n </div>\n </PageLayout.Table>\n </PageLayout>\n </BasePage>\n );\n}\nOpenShiftPage.displayName = 'OpenShiftPage';\n"],"names":["monthName","month","endDate"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@red-hat-developer-hub/plugin-cost-management",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "backstage": {
5
5
  "pluginId": "cost-management",
6
6
  "pluginPackages": [
@@ -8,12 +8,17 @@
8
8
  "@red-hat-developer-hub/plugin-cost-management-backend",
9
9
  "@red-hat-developer-hub/plugin-cost-management-common"
10
10
  ],
11
- "role": "frontend-plugin"
11
+ "role": "frontend-plugin",
12
+ "features": {
13
+ "./alpha": "@backstage/FrontendPlugin"
14
+ }
12
15
  },
13
16
  "configSchema": "config.schema.json",
14
17
  "dependencies": {
15
18
  "@backstage/core-components": "^0.18.13",
16
19
  "@backstage/core-plugin-api": "^1.12.9",
20
+ "@backstage/frontend-plugin-api": "^0.18.0",
21
+ "@backstage/plugin-app-react": "^0.2.6",
17
22
  "@backstage/plugin-permission-common": "^0.9.10",
18
23
  "@backstage/plugin-permission-react": "^0.5.4",
19
24
  "@backstage/theme": "^0.7.3",
@@ -23,7 +28,7 @@
23
28
  "@material-ui/lab": "4.0.0-alpha.61",
24
29
  "@patternfly/react-charts": "^8.3.0",
25
30
  "@patternfly/react-tokens": "^6.1.0",
26
- "@red-hat-developer-hub/plugin-cost-management-common": "^2.3.0",
31
+ "@red-hat-developer-hub/plugin-cost-management-common": "^2.4.0",
27
32
  "date-fns": "^3.6.0",
28
33
  "lodash": "^4.18.1",
29
34
  "react-intl": "^6.6.8",
@@ -49,6 +54,8 @@
49
54
  "@backstage/cli": "^0.36.5",
50
55
  "@backstage/core-app-api": "^1.20.4",
51
56
  "@backstage/dev-utils": "^1.1.26",
57
+ "@backstage/frontend-defaults": "^0.5.5",
58
+ "@backstage/frontend-test-utils": "^0.6.3",
52
59
  "@backstage/plugin-search-react": "^1.11.7",
53
60
  "@backstage/test-utils": "^1.7.21",
54
61
  "@testing-library/dom": "^10.0.0",
@@ -66,6 +73,12 @@
66
73
  "types": "./dist/index.d.ts",
67
74
  "default": "./dist/index.esm.js"
68
75
  },
76
+ "./alpha": {
77
+ "backstage": "@backstage/FrontendPlugin",
78
+ "import": "./dist/alpha.esm.js",
79
+ "types": "./dist/alpha.d.ts",
80
+ "default": "./dist/alpha.esm.js"
81
+ },
69
82
  "./package.json": "./package.json"
70
83
  },
71
84
  "files": [
@@ -95,12 +108,16 @@
95
108
  "postpack": "backstage-cli package postpack",
96
109
  "prepack": "backstage-cli package prepack",
97
110
  "start": "backstage-cli package start",
111
+ "start:legacy": "backstage-cli package start --entrypoint=dev/legacy.tsx",
98
112
  "test": "backstage-cli package test"
99
113
  },
100
114
  "sideEffects": false,
101
115
  "types": "./dist/index.d.ts",
102
116
  "typesVersions": {
103
117
  "*": {
118
+ "alpha": [
119
+ "dist/alpha.d.ts"
120
+ ],
104
121
  "package.json": [
105
122
  "package.json"
106
123
  ]