diff --git a/heureka/ui/package-lock.json b/heureka/ui/package-lock.json index 84a06667..005729cf 100644 --- a/heureka/ui/package-lock.json +++ b/heureka/ui/package-lock.json @@ -8,6 +8,15 @@ "name": "heureka", "version": "2.3.0", "license": "Apache-2.0", +<<<<<<< HEAD +======= + "dependencies": { + "@cloudoperators/juno-communicator": "^2.2.11", + "@cloudoperators/juno-messages-provider": "^0.1.17", + "@cloudoperators/juno-ui-components": "^2.15.4", + "@cloudoperators/juno-url-state-provider-v1": "^1.3.2" + }, +>>>>>>> 01cf4521 (feat(heureka) : Add components view (#263)) "devDependencies": { "@babel/core": "^7.20.2", "@babel/preset-env": "^7.20.2", @@ -29,9 +38,13 @@ "immer": "^10.0.0", "jest": "^29.3.1", "jest-environment-jsdom": "^29.3.1", +<<<<<<< HEAD "juno-ui-components": "https://assets.juno.global.cloud.sap/libs/juno-ui-components@2.13.8/package.tgz", "luxon": "^3.0.0", "messages-provider": "https://assets.juno.global.cloud.sap/libs/messages-provider@0.1.12/package.tgz", +======= + "luxon": "^3.4.4", +>>>>>>> 01cf4521 (feat(heureka) : Add components view (#263)) "postcss": "^8.4.21", "postcss-url": "^10.1.3", "prop-types": "^15.8.1", @@ -1899,6 +1912,57 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, +<<<<<<< HEAD +======= + "node_modules/@cloudoperators/juno-communicator": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/@cloudoperators/juno-communicator/-/juno-communicator-2.2.11.tgz", + "integrity": "sha512-dDoqKw3nZuuNMkdmwYDG/l7Uw7a4rDF3RtteuEW9yUhMypocsGmbcgRhaZjUWpL21OPbFDVNi58r3+KO7IN2Ug==", + "engines": { + "node": ">=20.0.0 <21.0.0", + "npm": ">=10.0.0 <11.0.0" + } + }, + "node_modules/@cloudoperators/juno-messages-provider": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/@cloudoperators/juno-messages-provider/-/juno-messages-provider-0.1.17.tgz", + "integrity": "sha512-ZECrpMVr3jx25YdcyayFUSXMHDRp9hjDLLbUSvQqcJLxtscpE14WEqGffelAMfr0Q6AqOi0DlEoSMVFlh7fYZw==", + "dependencies": { + "@cloudoperators/juno-ui-components": "*" + }, + "engines": { + "node": ">=20.0.0 <21.0.0", + "npm": ">=10.0.0 <11.0.0" + }, + "peerDependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "zustand": "^4.5.2" + } + }, + "node_modules/@cloudoperators/juno-ui-components": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/@cloudoperators/juno-ui-components/-/juno-ui-components-2.15.4.tgz", + "integrity": "sha512-lyziFGjtasxqiiZ86Yfn9EtJFtZ/72So1GmCsMdZCOt3WQnv/TcvQMnXCHe5Zg1fXZ/qNQWIac5rH6YbVS75yg==", + "engines": { + "node": ">=20.0.0 <21.0.0", + "npm": ">=10.0.0 <11.0.0" + }, + "peerDependencies": { + "prop-types": "15.8.1", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, + "node_modules/@cloudoperators/juno-url-state-provider-v1": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@cloudoperators/juno-url-state-provider-v1/-/juno-url-state-provider-v1-1.3.2.tgz", + "integrity": "sha512-DVFzP/5actNs6fkfA93U7jUm9rY0/kPzFWrfGof6SGvhNx+WffQ9BBGQA/p9S7M3brgwxtxgHBnRvTDyA7fMDA==", + "dependencies": { + "juri": "^1.0.3" + } + }, +>>>>>>> 01cf4521 (feat(heureka) : Add components view (#263)) "node_modules/@esbuild/aix-ppc64": { "version": "0.19.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", diff --git a/heureka/ui/package.json b/heureka/ui/package.json index a55c2efa..b2406d40 100644 --- a/heureka/ui/package.json +++ b/heureka/ui/package.json @@ -31,9 +31,13 @@ "immer": "^10.0.0", "jest": "^29.3.1", "jest-environment-jsdom": "^29.3.1", +<<<<<<< HEAD "juno-ui-components": "https://assets.juno.global.cloud.sap/libs/juno-ui-components@2.13.8/package.tgz", "luxon": "^3.0.0", "messages-provider": "https://assets.juno.global.cloud.sap/libs/messages-provider@0.1.12/package.tgz", +======= + "luxon": "^3.4.4", +>>>>>>> 01cf4521 (feat(heureka) : Add components view (#263)) "postcss": "^8.4.21", "postcss-url": "^10.1.3", "prop-types": "^15.8.1", diff --git a/heureka/ui/src/components/components/ComponentsList.jsx b/heureka/ui/src/components/components/ComponentsList.jsx new file mode 100644 index 00000000..dffd5757 --- /dev/null +++ b/heureka/ui/src/components/components/ComponentsList.jsx @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from "react" +import { + DataGrid, + DataGridRow, + DataGridHeadCell, + DataGridCell, +} from "@cloudoperators/juno-ui-components" +import HintNotFound from "../shared/HintNotFound" +import HintLoading from "../shared/HintLoading" +import ComponentsListItem from "./ComponentsListItem" + +const ComponentsList = ({ components, isLoading }) => { + return ( + + + Name + Type + Total Number of Versions + + {isLoading && !components ? ( + + ) : ( + <> + {components?.length > 0 ? ( + <> + {components.map((item, index) => ( + + ))} + + ) : ( + + + + + + )} + + )} + + ) +} + +export default ComponentsList diff --git a/heureka/ui/src/components/components/ComponentsListController.jsx b/heureka/ui/src/components/components/ComponentsListController.jsx new file mode 100644 index 00000000..445c5ddd --- /dev/null +++ b/heureka/ui/src/components/components/ComponentsListController.jsx @@ -0,0 +1,96 @@ +/* + * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useMemo, useState } from "react" +import { useQuery } from "@tanstack/react-query" +import { + useQueryClientFnReady, + useQueryOptions, + useActions, +} from "../StoreProvider" +import ComponentsList from "./ComponentsList" +import { + Pagination, + Container, + Stack, +} from "@cloudoperators/juno-ui-components" + +const ComponentsListController = () => { + const queryClientFnReady = useQueryClientFnReady() + const queryOptions = useQueryOptions("components") + const { setQueryOptions } = useActions() + + const { isLoading, isFetching, isError, data, error } = useQuery({ + queryKey: [`components`, queryOptions], + enabled: !!queryClientFnReady, + }) + + const [currentPage, setCurrentPage] = useState(1) // State for current page + + const components = useMemo(() => { + if (!data) return null + return data?.Components?.edges + }, [data]) + + const pageInfo = useMemo(() => { + if (!data) return null + return data?.Components?.pageInfo + }, [data]) + + const totalPages = useMemo(() => { + if (!data?.Components?.pageInfo?.pages) return 0 + return data?.Components?.pageInfo?.pages.length + }, [data?.Components?.pageInfo]) + const onPaginationChanged = (newPage) => { + setCurrentPage(newPage) // Update currentPage + if (!data?.Components?.pageInfo?.pages) return + const pages = data?.Components?.pageInfo?.pages + const currentPageIndex = pages?.findIndex( + (page) => page?.pageNumber === parseInt(newPage) + ) + if (currentPageIndex > -1) { + const after = pages[currentPageIndex]?.after + setQueryOptions("components", { + ...queryOptions, + after: `${after}`, + }) + } + } + + const onPressNext = () => { + onPaginationChanged(parseInt(currentPage) + 1) + } + const onPressPrevious = () => { + onPaginationChanged(parseInt(currentPage) - 1) + } + const onKeyPress = (oKey) => { + if (oKey.code === "Enter") { + onPaginationChanged(parseInt(oKey.currentTarget.value)) + } + } + + return ( + <> + + + + + + + + ) +} + +export default ComponentsListController diff --git a/heureka/ui/src/components/components/ComponentsListItem.jsx b/heureka/ui/src/components/components/ComponentsListItem.jsx new file mode 100644 index 00000000..da4ed811 --- /dev/null +++ b/heureka/ui/src/components/components/ComponentsListItem.jsx @@ -0,0 +1,19 @@ +/* + * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from "react" +import { DataGridRow, DataGridCell } from "@cloudoperators/juno-ui-components" + +const ComponentsListItem = ({ item }) => { + return ( + + {item?.node?.name} + {item?.node?.type} + {item?.node?.componentVersions?.totalCount} + + ) +} + +export default ComponentsListItem diff --git a/heureka/ui/src/components/components/ComponentsTab.jsx b/heureka/ui/src/components/components/ComponentsTab.jsx new file mode 100644 index 00000000..581a4caf --- /dev/null +++ b/heureka/ui/src/components/components/ComponentsTab.jsx @@ -0,0 +1,19 @@ +/* + * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from "react" +import ComponentsListController from "./ComponentsListController" +import Filters from "../filters/Filters" + +const ComponentsTab = () => { + return ( + <> + + + + ) +} + +export default ComponentsTab diff --git a/heureka/ui/src/components/issues/IssuesList.jsx b/heureka/ui/src/components/issues/IssuesList.jsx index 5a7d62a4..0a1709ae 100644 --- a/heureka/ui/src/components/issues/IssuesList.jsx +++ b/heureka/ui/src/components/issues/IssuesList.jsx @@ -16,10 +16,12 @@ import IssuesListItem from "./IssuesListItem" const IssuesList = ({ issues, isLoading }) => { return ( - + Primary Name - Secondary Name + Type + {/* Secondary Name */} + Remediation Date Status Severity Component Name @@ -40,7 +42,7 @@ const IssuesList = ({ issues, isLoading }) => { ) : ( - + diff --git a/heureka/ui/src/components/issues/IssuesListController.jsx b/heureka/ui/src/components/issues/IssuesListController.jsx index ada0c09f..0ce51aca 100644 --- a/heureka/ui/src/components/issues/IssuesListController.jsx +++ b/heureka/ui/src/components/issues/IssuesListController.jsx @@ -11,7 +11,11 @@ import { useActions, } from "../StoreProvider" import IssuesList from "./IssuesList" -import { Pagination } from "juno-ui-components" +import { + Container, + Pagination, + Stack, +} from "@cloudoperators/juno-ui-components" const IssuesListController = () => { const queryClientFnReady = useQueryClientFnReady() @@ -69,18 +73,22 @@ const IssuesListController = () => { return ( <> - - + + + + + + ) } diff --git a/heureka/ui/src/components/issues/IssuesListItem.jsx b/heureka/ui/src/components/issues/IssuesListItem.jsx index 1b92eb5d..0fad95d8 100644 --- a/heureka/ui/src/components/issues/IssuesListItem.jsx +++ b/heureka/ui/src/components/issues/IssuesListItem.jsx @@ -6,17 +6,24 @@ import React from "react" import { DataGridRow, DataGridCell } from "juno-ui-components" import { listOfCommaSeparatedObjs } from "../shared/Helper" +import { DateTime } from "luxon" const IssuesListItem = ({ item }) => { + const formatDate = (dateStr) => { + const dateObj = DateTime.fromISO(dateStr) + return dateObj.toFormat("yyyy.MM.dd.HH:mm:ss") + } return ( {item?.node?.issue?.primaryName} - + {item?.node?.issue?.type} + {/* {listOfCommaSeparatedObjs( item?.node?.effectiveIssueVariants, "secondaryName" - )} - + )} + */} + {formatDate(item?.node?.remediationDate)} {item?.node?.status} {item?.node?.severity?.value} diff --git a/heureka/ui/src/components/services/ServicesListController.jsx b/heureka/ui/src/components/services/ServicesListController.jsx index aa506c00..5d1c70e3 100644 --- a/heureka/ui/src/components/services/ServicesListController.jsx +++ b/heureka/ui/src/components/services/ServicesListController.jsx @@ -13,7 +13,11 @@ import { useFilteredServices, useEndpoint, } from "../StoreProvider" -import { Pagination } from "@cloudoperators/juno-ui-components" +import { + Pagination, + Container, + Stack, +} from "@cloudoperators/juno-ui-components" import ServicesList from "./ServicesList" import { Messages, @@ -93,18 +97,22 @@ const ServicesListController = () => { return ( <> - - + + + + + + ) } diff --git a/heureka/ui/src/components/tabs/TabContext.jsx b/heureka/ui/src/components/tabs/TabContext.jsx index b50c95d4..a21d18c2 100644 --- a/heureka/ui/src/components/tabs/TabContext.jsx +++ b/heureka/ui/src/components/tabs/TabContext.jsx @@ -10,6 +10,7 @@ import { useActions, useActiveTab } from "../StoreProvider" import ServicesTab from "../services/ServicesTab" import IssuesTab from "../issues/IssuesTab" +import ComponentsTab from "../components/ComponentsTab" const TAB_CONFIG = [ { @@ -24,6 +25,12 @@ const TAB_CONFIG = [ icon: "autoAwesomeMotion", component: IssuesTab, }, + { + label: "Components", + value: "components", + icon: "autoAwesomeMotion", + component: ComponentsTab, + }, ] const TabContext = () => { diff --git a/heureka/ui/src/hooks/useQueryClientFn.js b/heureka/ui/src/hooks/useQueryClientFn.js index 3cc7ebad..0e95699e 100644 --- a/heureka/ui/src/hooks/useQueryClientFn.js +++ b/heureka/ui/src/hooks/useQueryClientFn.js @@ -10,6 +10,7 @@ import { request } from "graphql-request" import sevicesQuery from "../lib/queries/services" import issueMatchesQuery from "../lib/queries/issueMatches" import ServiceFilterQuery from "../lib/queries/serviceFilters" +import componentsQuery from "../lib/queries/components" // hook to register query defaults that depends on the queryClient and options const useQueryClientFn = () => { @@ -40,6 +41,14 @@ const useQueryClientFn = () => { }, }) + queryClient.setQueryDefaults(["components"], { + queryFn: async ({ queryKey }) => { + const [_key, options] = queryKey + console.log("useQueryClientFn::: queryKey: ", queryKey) + return await request(endpoint, componentsQuery(), options) + }, + }) + queryClient.setQueryDefaults(["serviceFilters"], { queryFn: async ({ queryKey }) => { console.log("useQueryClientFn::: queryKey: ", queryKey) diff --git a/heureka/ui/src/lib/queries/components.js b/heureka/ui/src/lib/queries/components.js new file mode 100644 index 00000000..f39041f0 --- /dev/null +++ b/heureka/ui/src/lib/queries/components.js @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { gql } from "graphql-request" + +// gql +// It is there for convenience so that you can get the tooling support +// like prettier formatting and IDE syntax highlighting. +// You can use gql from graphql-tag if you need it for some reason too. +export default () => gql` + query ($filter: ComponentFilter, $first: Int, $after: String) { + Components(filter: $filter, first: $first, after: $after) { + totalCount + edges { + node { + id + name + type + componentVersions { + totalCount + edges { + node { + id + version + issues { + totalCount + } + componentInstances { + totalCount + edges { + node { + id + } + } + } + } + cursor + } + } + } + cursor + } + pageInfo { + hasNextPage + hasPreviousPage + isValidPage + pageNumber + nextPageAfter + pages { + after + isCurrent + pageNumber + pageCount + } + } + } + } +` diff --git a/heureka/ui/src/lib/store.js b/heureka/ui/src/lib/store.js index 60c94a55..6188797e 100644 --- a/heureka/ui/src/lib/store.js +++ b/heureka/ui/src/lib/store.js @@ -37,6 +37,11 @@ export default (options) => first: 20, }, }, + components: { + queryOptions: { + first: 20, + }, + }, }, filters: { ...initialFiltersState,