diff --git a/src/renderer/components/+workloads-pods/pods.tsx b/src/renderer/components/+workloads-pods/pods.tsx index 147353f6d6..820d0d1e8d 100644 --- a/src/renderer/components/+workloads-pods/pods.tsx +++ b/src/renderer/components/+workloads-pods/pods.tsx @@ -3,15 +3,15 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import "./pods.scss"; +// import "./pods.scss"; -import React, { Fragment } from "react"; -import { observer } from "mobx-react"; +import React, { Fragment, HTMLProps } from "react"; +import { disposeOnUnmount, observer } from "mobx-react"; import { Link } from "react-router-dom"; import { KubeObjectListLayout } from "../kube-object-list-layout"; import type { NodeApi, Pod } from "../../../common/k8s-api/endpoints"; import { StatusBrick } from "../status-brick"; -import { cssNames, getConvertedParts, object, stopPropagation } from "../../utils"; +import { cssNames, Disposer, getConvertedParts, object, stopPropagation } from "../../utils"; import startCase from "lodash/startCase"; import kebabCase from "lodash/kebabCase"; import type { ApiManager } from "../../../common/k8s-api/api-manager"; @@ -28,6 +28,10 @@ import type { PodStore } from "./store"; import nodeApiInjectable from "../../../common/k8s-api/endpoints/node.api.injectable"; import eventStoreInjectable from "../+events/store.injectable"; import podStoreInjectable from "./store.injectable"; +import { List } from "../list/list"; +import { createColumnHelper, getCoreRowModel } from '@tanstack/react-table' +import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable"; +import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api"; enum columnId { name = "name", @@ -47,10 +51,26 @@ interface Dependencies { eventStore: EventStore; podStore: PodStore; nodeApi: NodeApi; + subscribeToStores: SubscribeStores; } +const columnHelper = createColumnHelper() + @observer class NonInjectedPods extends React.Component { + componentDidMount() { + const { podStore, eventStore, subscribeToStores } = this.props; + const stores = Array.from(new Set([podStore, eventStore])); + + const reactions: Disposer[] = []; + + reactions.push( + subscribeToStores(stores), + ); + + disposeOnUnmount(this, reactions); + } + renderState(name: string, ready: boolean, key: string, data: Partial> | undefined) { return data && ( <> @@ -99,7 +119,142 @@ class NonInjectedPods extends React.Component { )); } + renderControlledBy(pod: Pod) { + const { apiManager, getDetailsUrl } = this.props; + + return pod.getOwnerRefs().map(ref => { + const { kind, name } = ref; + const detailsLink = getDetailsUrl(apiManager.lookupApiLink(ref, pod)); + + return ( + + + {kind} + + + ); + }) + } + + renderNodeName(pod: Pod) { + const { getDetailsUrl, nodeApi } = this.props; + + return pod.getNodeName() ? ( + + + {pod.getNodeName()} + + + ) : "" + } + render() { + const { podStore } = this.props; + + const columns = [ + columnHelper.display({ + id: "select", + header: ({ table }) => ( + + ), + cell: ({ row }) => ( +
+ +
+ ), + }), + columnHelper.accessor(row => row.getName(), { + id: "name", + header: "Name", + cell: info => info.getValue(), + }), + columnHelper.display({ + id: "warning", + cell: props => , + }), + columnHelper.accessor(row => row.getNs(), { + id: "namespace", + header: "Namespace", + cell: info => info.getValue(), + }), + columnHelper.accessor(row => this.renderContainersStatus(row), { + id: "containers", + header: "Containers", + cell: info => info.getValue(), + }), + columnHelper.accessor(row => row.getRestartsCount(), { + id: "restarts", + header: "Restarts", + cell: info => info.getValue(), + }), + columnHelper.accessor(row => this.renderControlledBy(row), { + id: "controlledBy", + header: "Controlled By", + cell: info => info.getValue(), + }), + columnHelper.accessor(row => this.renderNodeName(row), { + id: "node", + header: "Node", + cell: info => info.getValue(), + }), + columnHelper.accessor(row => row.getQosClass(), { + id: "qos", + header: "QoS", + cell: info => info.getValue(), + }), + columnHelper.accessor(row => , { + id: "age", + header: "Age", + cell: info => info.renderValue(), + }), + columnHelper.accessor(row => row.getStatusMessage(), { + id: "status", + header: "Status", + cell: info => info.getValue(), + }), + ] + + return ( + + pod.getSearchFields(), + pod => pod.getStatusMessage(), + pod => pod.status?.podIP || "", + pod => pod.getNodeName() || "", + ]} + getCoreRowModel={getCoreRowModel()} + /> + + ); + } + + render1() { const { apiManager, getDetailsUrl, podStore, eventStore, nodeApi } = this.props; return ( @@ -201,5 +356,30 @@ export const Pods = withInjectables(NonInjectedPods, { nodeApi: di.inject(nodeApiInjectable), eventStore: di.inject(eventStoreInjectable), podStore: di.inject(podStoreInjectable), + subscribeToStores: di.inject(subscribeStoresInjectable), }), }); + +function IndeterminateCheckbox({ + indeterminate, + className = '', + ...rest +}: { indeterminate?: boolean } & HTMLProps) { + const ref = React.useRef(null!) + + React.useEffect(() => { + if (typeof indeterminate === 'boolean') { + ref.current.indeterminate = !rest.checked && indeterminate + } + }, [ref, indeterminate]) + + return ( + + ) +} \ No newline at end of file diff --git a/src/renderer/components/list/list.tsx b/src/renderer/components/list/list.tsx index dfdc042de2..83bbdd2024 100644 --- a/src/renderer/components/list/list.tsx +++ b/src/renderer/components/list/list.tsx @@ -4,26 +4,28 @@ */ import styles from "./list.module.scss"; +import themeStyles from "./table-theme.module.scss"; + import React, { useState } from "react"; import { SearchInput } from "../input"; +import type { TableOptions } from '@tanstack/react-table' +import { getCoreRowModel } from '@tanstack/react-table' -import type { UseTableOptions } from "react-table"; -import { ReactTable } from "../table/react-table"; +import { Table } from "../table/react-table"; -export type SearchFilter = (item: T) => string | number; +export type SearchFilter = (item: T) => string; -export interface ListProps extends UseTableOptions { - items: T[]; +export interface ListProps extends TableOptions { filters: SearchFilter[]; title?: React.ReactNode; } -export function List({ columns, data, title, items, filters }: ListProps) { +export function List({ columns, data, title, filters }: ListProps) { const [search, setSearch] = useState(""); const query = search.toLowerCase(); const filteredData = data.filter((item, index) => ( - filters.some(getText => String(getText(items[index])).toLowerCase().includes(query)) + filters.some(getText => String(getText(data[index])).toLowerCase().includes(query)) )); return ( @@ -41,7 +43,12 @@ export function List({ columns, data, title, items, filters }: ListProps) /> - + {filteredData.length == 0 && (
No data found
)}