diff --git a/package-lock.json b/package-lock.json index 240597fd72..fd114df3b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "@flanksource/flanksource-ui", - "version": "1.0.707", + "version": "1.0.711", "dependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@clerk/nextjs": "^5.2.2", @@ -43,7 +43,7 @@ "ansi-to-html": "^0.7.2", "axios": "^1.6.2", "casbin.js": "^0.5.0", - "clsx": "^1.1.1", + "clsx": "^2.1.1", "d3-hierarchy": "^3.1.2", "d3-shape": "^3.1.0", "dayjs": "^1.10.7", @@ -58,6 +58,7 @@ "jotai-location": "^0.5.2", "jsonpath-plus": "^7.0.0", "lodash": "^4.17.21", + "mantine-react-table": "^1.3.4", "monaco-editor": "0.48.0", "monaco-themes": "0.4.4", "monaco-yaml": "5.1.1", @@ -4413,6 +4414,116 @@ "dev": true, "peer": true }, + "node_modules/@mantine/core": { + "version": "6.0.22", + "resolved": "https://registry.npmjs.org/@mantine/core/-/core-6.0.22.tgz", + "integrity": "sha512-6kv0eY7n565fyjgS20qUYeCSxg3f1TJ5vurzbP1HHtFXXKSY0bYoqqDoHipFCt6NxsPQGeiC6cC0c/IWIlxoKQ==", + "peer": true, + "dependencies": { + "@floating-ui/react": "^0.19.1", + "@mantine/styles": "6.0.22", + "@mantine/utils": "6.0.22", + "@radix-ui/react-scroll-area": "1.0.2", + "react-remove-scroll": "^2.5.5", + "react-textarea-autosize": "8.3.4" + }, + "peerDependencies": { + "@mantine/hooks": "6.0.22", + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@mantine/core/node_modules/@floating-ui/react": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.19.2.tgz", + "integrity": "sha512-JyNk4A0Ezirq8FlXECvRtQOX/iBe5Ize0W/pLkrZjfHW9GUV7Xnq6zm6fyZuQzaHHqEnVizmvlA96e1/CkZv+w==", + "peer": true, + "dependencies": { + "@floating-ui/react-dom": "^1.3.0", + "aria-hidden": "^1.1.3", + "tabbable": "^6.0.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@mantine/core/node_modules/@floating-ui/react-dom": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-1.3.0.tgz", + "integrity": "sha512-htwHm67Ji5E/pROEAr7f8IKFShuiCKHwUC/UY4vC3I5jiSvGFAYnSYiZO5MlGmads+QqvUkR9ANHEguGrDv72g==", + "peer": true, + "dependencies": { + "@floating-ui/dom": "^1.2.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@mantine/dates": { + "version": "6.0.22", + "resolved": "https://registry.npmjs.org/@mantine/dates/-/dates-6.0.22.tgz", + "integrity": "sha512-RwZzaRtyCdwXWrszjoDFUrYdy2s6sAZgXZzp+ytp0KJDm63+H+4ri1Qkv7bWKVBgrTP7alsxCIGHV2weEOZKog==", + "peer": true, + "dependencies": { + "@mantine/utils": "6.0.22" + }, + "peerDependencies": { + "@mantine/core": "6.0.22", + "@mantine/hooks": "6.0.22", + "dayjs": ">=1.0.0", + "react": ">=16.8.0" + } + }, + "node_modules/@mantine/hooks": { + "version": "6.0.22", + "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-6.0.22.tgz", + "integrity": "sha512-e10//QTN2sAmC4Ryeu5X5L/TsxnrjXMOaGq3dxFPIPsCSwLzyxqySfjzVViWmoPWAj0Ak9MvE2MHFjzmOpA80w==", + "peer": true, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@mantine/styles": { + "version": "6.0.22", + "resolved": "https://registry.npmjs.org/@mantine/styles/-/styles-6.0.22.tgz", + "integrity": "sha512-Rud/IQp2EFYDiP4csRy2XBrho/Ct+W2/b+XbvCRTeQTmpFy/NfAKm/TWJa5zPvuv/iLTjGkVos9SHw/DteESpQ==", + "peer": true, + "dependencies": { + "clsx": "1.1.1", + "csstype": "3.0.9" + }, + "peerDependencies": { + "@emotion/react": ">=11.9.0", + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@mantine/styles/node_modules/clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@mantine/styles/node_modules/csstype": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz", + "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==", + "peer": true + }, + "node_modules/@mantine/utils": { + "version": "6.0.22", + "resolved": "https://registry.npmjs.org/@mantine/utils/-/utils-6.0.22.tgz", + "integrity": "sha512-RSKlNZvxhMCkOFZ6slbYvZYbWjHUM+PxDQnupIOxIdsTZQQjx/BFfrfJ7kQFOP+g7MtpOds8weAetEs5obwMOQ==", + "peer": true, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/@mdx-js/react": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-2.3.0.tgz", @@ -5325,6 +5436,45 @@ } } }, + "node_modules/@radix-ui/react-presence": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.0.tgz", + "integrity": "sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-presence/node_modules/@radix-ui/react-compose-refs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz", + "integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-presence/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz", + "integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, "node_modules/@radix-ui/react-primitive": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz", @@ -5381,6 +5531,133 @@ } } }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.0.2.tgz", + "integrity": "sha512-k8VseTxI26kcKJaX0HPwkvlNBPTs56JRdYzcZ/vzrNUkDlvXBy8sMc7WvCpYzZkHgb+hd72VW9MqkqecGtuNgg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/number": "1.0.0", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-direction": "1.0.0", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/number": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.0.tgz", + "integrity": "sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/primitive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz", + "integrity": "sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-compose-refs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz", + "integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-context": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz", + "integrity": "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-direction": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.0.tgz", + "integrity": "sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.1.tgz", + "integrity": "sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-slot": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.1.tgz", + "integrity": "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz", + "integrity": "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz", + "integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, "node_modules/@radix-ui/react-select": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-1.2.2.tgz", @@ -11961,6 +12238,32 @@ "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==", "dev": true }, + "node_modules/@tabler/icons": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.11.0.tgz", + "integrity": "sha512-/vZinJNvCYhdAB+RUsyCpanSPuOEKHHIZi4Uu0Bw7ilewHnQhCWUPrT704uHCRli2ROl7spADPmWzAqOganA5A==", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + } + }, + "node_modules/@tabler/icons-react": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.11.0.tgz", + "integrity": "sha512-xHNBi9mns1slvqos+7LkP3ube4CjWrANMbxMaorzwzO9J/+y1sAEG/sN8CV8FmtpYW/9/gDR+OWCjjLLg0RmAw==", + "peer": true, + "dependencies": { + "@tabler/icons": "3.11.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + }, + "peerDependencies": { + "react": ">= 16" + } + }, "node_modules/@tailwindcss/forms": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz", @@ -15926,9 +16229,9 @@ } }, "node_modules/clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "engines": { "node": ">=6" } @@ -17613,8 +17916,7 @@ "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", - "dev": true + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" }, "node_modules/detect-package-manager": { "version": "2.0.1", @@ -20713,7 +21015,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", - "dev": true, "engines": { "node": ">=6" } @@ -26476,6 +26777,87 @@ "tmpl": "1.0.5" } }, + "node_modules/mantine-react-table": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/mantine-react-table/-/mantine-react-table-1.3.4.tgz", + "integrity": "sha512-rD0CaeC4RCU7k/ZKvfj5ijFFMd4clGpeg/EwMcogYFioZjj8aNfD78osTNNYr90AnOAFGnd7ZnderLK89+W1ZQ==", + "dependencies": { + "@tanstack/match-sorter-utils": "8.8.4", + "@tanstack/react-table": "8.10.6", + "@tanstack/react-virtual": "3.0.0-beta.63" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kevinvandy" + }, + "peerDependencies": { + "@emotion/react": ">=11", + "@mantine/core": "^6.0", + "@mantine/dates": "^6.0", + "@mantine/hooks": "^6.0", + "@tabler/icons-react": ">=2.23", + "react": ">=18.0", + "react-dom": ">=18.0" + } + }, + "node_modules/mantine-react-table/node_modules/@tanstack/react-table": { + "version": "8.10.6", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.10.6.tgz", + "integrity": "sha512-D0VEfkIYnIKdy6SHiBNEaMc4SxO+MV7ojaPhRu8jP933/gbMi367+Wul2LxkdovJ5cq6awm0L1+jgxdS/unzIg==", + "dependencies": { + "@tanstack/table-core": "8.10.6" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/mantine-react-table/node_modules/@tanstack/react-virtual": { + "version": "3.0.0-beta.63", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.0.0-beta.63.tgz", + "integrity": "sha512-n4aaZs3g9U2oZjFp8dAeT1C2g4rr/3lbCo2qWbD9NquajKnGx7R+EfLBAHJ6pVMmfsTMZ0XCBwkIs7U74R/s0A==", + "dependencies": { + "@tanstack/virtual-core": "3.0.0-beta.63" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/mantine-react-table/node_modules/@tanstack/table-core": { + "version": "8.10.6", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.10.6.tgz", + "integrity": "sha512-9t8brthhAmCBIjzk7fCDa/kPKoLQTtA31l9Ir76jYxciTlHU61r/6gYm69XF9cbg9n88gVL5y7rNpeJ2dc1AFA==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/mantine-react-table/node_modules/@tanstack/virtual-core": { + "version": "3.0.0-beta.63", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.0.0-beta.63.tgz", + "integrity": "sha512-KhhfRYSoQpl0y+2axEw+PJZd/e/9p87PDpPompxcXnweNpt9ZHCT/HuNx7MKM9PVY/xzg9xJSWxwnSCrO+d6PQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/map-obj": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", @@ -34539,7 +34921,6 @@ "version": "2.5.5", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz", "integrity": "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==", - "dev": true, "dependencies": { "react-remove-scroll-bar": "^2.3.3", "react-style-singleton": "^2.2.1", @@ -34561,10 +34942,9 @@ } }, "node_modules/react-remove-scroll-bar": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz", - "integrity": "sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==", - "dev": true, + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz", + "integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==", "dependencies": { "react-style-singleton": "^2.2.1", "tslib": "^2.0.0" @@ -36792,7 +37172,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", - "dev": true, "dependencies": { "get-nonce": "^1.0.0", "invariant": "^2.2.4", @@ -36823,10 +37202,24 @@ "react": "^16.8.3 || ^17.0.0-0 || ^18.0.0" } }, + "node_modules/react-textarea-autosize": { + "version": "8.3.4", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "use-composed-ref": "^1.3.0", + "use-latest": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-tooltip": { "version": "5.26.3", "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.26.3.tgz", - "integrity": "sha512-MpYAws8CEHUd/RC4GaDCdoceph/T4KHM5vS5Dbk8FOmLMvvIht2ymP2htWdrke7K6lqPO8rz8+bnwWUIXeDlzg==", "dependencies": { "@floating-ui/dom": "^1.6.1", "classnames": "^2.3.0" @@ -41600,9 +41993,9 @@ } }, "node_modules/type-fest": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.8.2.tgz", - "integrity": "sha512-mcvrCjixA5166hSrUoJgGb9gBQN4loMYyj9zxuMs/66ibHNEFd5JXMw37YVDx58L4/QID9jIzdTBB4mDwDJ6KQ==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.22.0.tgz", + "integrity": "sha512-hxMO1k4ip1uTVGgPbs1hVpYyhz2P91A6tQyH2H9POx3U6T3MdhIcfY8L2hRu/LRmzPFdfduOS0RIDjFlP2urPw==", "engines": { "node": ">=16" }, @@ -42014,7 +42407,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.0.tgz", "integrity": "sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==", - "dev": true, "dependencies": { "tslib": "^2.0.0" }, @@ -42031,6 +42423,15 @@ } } }, + "node_modules/use-composed-ref": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz", + "integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==", + "peer": true, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/use-isomorphic-layout-effect": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", @@ -42044,6 +42445,23 @@ } } }, + "node_modules/use-latest": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz", + "integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==", + "peer": true, + "dependencies": { + "use-isomorphic-layout-effect": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-resize-observer": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-9.1.0.tgz", @@ -42061,7 +42479,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", - "dev": true, "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" diff --git a/package.json b/package.json index a88c98a75d..0a2efddade 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "ansi-to-html": "^0.7.2", "axios": "^1.6.2", "casbin.js": "^0.5.0", - "clsx": "^1.1.1", + "clsx": "^2.1.1", "d3-hierarchy": "^3.1.2", "d3-shape": "^3.1.0", "dayjs": "^1.10.7", @@ -58,6 +58,7 @@ "jotai-location": "^0.5.2", "jsonpath-plus": "^7.0.0", "lodash": "^4.17.21", + "mantine-react-table": "^1.3.4", "monaco-editor": "0.48.0", "monaco-themes": "0.4.4", "monaco-yaml": "5.1.1", diff --git a/src/components/SchemaResourcePage/SchemaResourceList.tsx b/src/components/SchemaResourcePage/SchemaResourceList.tsx index 85b103d49e..af54c62281 100644 --- a/src/components/SchemaResourcePage/SchemaResourceList.tsx +++ b/src/components/SchemaResourcePage/SchemaResourceList.tsx @@ -1,18 +1,8 @@ -import clsx from "clsx"; -import { useMemo, useState } from "react"; -import { Link, useNavigate } from "react-router-dom"; +import { useCallback } from "react"; +import { useNavigate } from "react-router-dom"; import { SchemaResourceWithJobStatus } from "../../api/schemaResources"; -import { tables } from "../../context/UserAccessContext/permissions"; -import { Age } from "../../ui/Age"; -import { Avatar } from "../../ui/Avatar"; -import Popover from "../../ui/Popover/Popover"; -import TableSkeletonLoader from "../../ui/SkeletonLoader/TableSkeletonLoader"; -import { TagItem, TagList } from "../../ui/Tags/TagList"; -import AgentBadge from "../Agents/AgentBadge"; -import { InfoMessage } from "../InfoMessage"; -import JobHistoryStatusColumn from "../JobsHistory/JobHistoryStatusColumn"; -import { JobsHistoryDetails } from "../JobsHistory/JobsHistoryDetails"; -import ConfigScrapperIcon from "./ConfigScrapperIcon"; +import ResourceTable from "../Settings/ResourceTable"; +import { SchemaResourceType } from "./resourceTypes"; interface Props { items: SchemaResourceWithJobStatus[]; @@ -27,249 +17,23 @@ export function SchemaResourceList({ table, isLoading }: Props) { - return ( -
-
- - - - Name - Source Config - Agent - {table === "canaries" && Schedule} - {table === "topologies" && namespace} - Job Status - Last Run - Last Failed - Tags - Created At - Updated At - Created By - - - - {items.map((item) => ( - - ))} - -
- {items.length === 0 && ( -
- {isLoading ? ( - - ) : ( - - )} -
- )} -
-
- ); -} - -interface CellProps { - children: React.ReactNode; - className?: string; - colSpan?: number; -} - -function HCell({ - children, - className = "px-3 py-3 text-gray-500 font-medium text-xs text-left", - colSpan -}: CellProps) { - return ( - - {children} - - ); -} - -function Cell({ children, className, colSpan }: CellProps) { - return ( - - {children} - - ); -} - -function SchemaResourceListItem({ - name, - created_at, - updated_at, - id, - source, - baseUrl, - created_by, - table, - schedule, - job_status, - namespace, - agent, - spec, - job_details, - job_name, - last_runtime, - job_last_failed, - labels -}: SchemaResourceWithJobStatus & { - baseUrl: string; - table: string; -}) { const navigate = useNavigate(); - const navigateToDetails = (id: string) => navigate(`${baseUrl}/${id}`); - const [isJobDetailsModalOpen, setIsJobDetailsModalOpen] = useState(false); - - const tags = useMemo(() => { - return Object.entries(labels ?? {}).map(([key, value]) => ({ - key, - value - })); - }, [labels]); - const isJobDetailsEmpty = - !job_details || Object.keys(job_details).length === 0; + const onRowClick = useCallback( + (row: SchemaResourceWithJobStatus) => { + navigate(`${baseUrl}/${row.id}`); + }, + [baseUrl, navigate] + ); return ( - navigateToDetails(id)} - > - -
- {table === tables.config_scrapers && ( - - )} -
- {name} - -
-
-
- - {source && source === "KubernetesCRD" ? ( - { - e.stopPropagation(); - }} - > - - {namespace ? <>{namespace}/ : ""} - {name} - - - ) : ( - Link - )} - - {agent?.name} - {table === "canaries" && {schedule}} - {table === "topologies" && {namespace}} - - -
{ - e.stopPropagation(); - e.preventDefault(); - }} - > - { - setIsJobDetailsModalOpen(true); - }} - /> - {!isJobDetailsEmpty && ( - <> - - - - - )} -
-
- - - - - - - - {tags.length > 0 && ( - -
- -
- {tags.length > 1 && ( -
- +{tags.length - 1} more -
- )} - - } - title="Tags" - placement="left" - menuClass="top-8" - > -
-
- -
-
-
- )} -
- - - - - - - - {created_by && } - - +
+ +
); } diff --git a/src/components/SchemaResourcePage/index.tsx b/src/components/SchemaResourcePage/index.tsx index a6eaeb53fb..0cfac16550 100644 --- a/src/components/SchemaResourcePage/index.tsx +++ b/src/components/SchemaResourcePage/index.tsx @@ -47,13 +47,16 @@ export function SchemaResourcePage({ contentClass="flex flex-col h-full p-6" >
- - {Boolean(error) && } + {error ? ( + + ) : ( + + )}
diff --git a/src/components/Settings/ResourceTable.tsx b/src/components/Settings/ResourceTable.tsx new file mode 100644 index 0000000000..016d1e2435 --- /dev/null +++ b/src/components/Settings/ResourceTable.tsx @@ -0,0 +1,376 @@ +import { SchemaResourceWithJobStatus } from "@flanksource-ui/api/schemaResources"; +import { tables } from "@flanksource-ui/context/UserAccessContext/permissions"; +import { Avatar } from "@flanksource-ui/ui/Avatar"; +import useReactTablePaginationState from "@flanksource-ui/ui/DataTable/Hooks/useReactTablePaginationState"; +import useReactTableSortState from "@flanksource-ui/ui/DataTable/Hooks/useReactTableSortState"; +import { MRTDateCell } from "@flanksource-ui/ui/MRTDataTable/Cells/MRTDateCells"; +import Popover from "@flanksource-ui/ui/Popover/Popover"; +import { TagItem, TagList } from "@flanksource-ui/ui/Tags/TagList"; +import { + MantineReactTable, + MRT_ColumnDef, + MRT_Row, + useMantineReactTable +} from "mantine-react-table"; +import { useMemo, useState } from "react"; +import { Link } from "react-router-dom"; +import AgentBadge from "../Agents/AgentBadge"; +import JobHistoryStatusColumn from "../JobsHistory/JobHistoryStatusColumn"; +import { JobsHistoryDetails } from "../JobsHistory/JobsHistoryDetails"; +import ConfigScrapperIcon from "../SchemaResourcePage/ConfigScrapperIcon"; +import { SchemaResourceType } from "../SchemaResourcePage/resourceTypes"; + +function MRTJobHistoryStatusColumn({ + row +}: { + row: MRT_Row< + SchemaResourceWithJobStatus & { + table: SchemaResourceType["table"]; + } + >; +}) { + const { job_details, job_status, name, job_name } = row.original; + + const [isJobDetailsModalOpen, setIsJobDetailsModalOpen] = useState(false); + + const isJobDetailsEmpty = + !job_details || Object.keys(job_details).length === 0; + + return ( +
{ + e.stopPropagation(); + e.preventDefault(); + }} + > + { + setIsJobDetailsModalOpen(true); + }} + /> + {!isJobDetailsEmpty && ( + <> + + + + + )} +
+ ); +} + +function DataTableTagsColumn({ + row +}: { + row: MRT_Row< + SchemaResourceWithJobStatus & { + table: SchemaResourceType["table"]; + } + >; +}) { + const { labels } = row.original; + + const tags = useMemo(() => { + return Object.entries(labels ?? {}).map(([key, value]) => ({ + key, + value + })); + }, [labels]); + + return ( + // eslint-disable-next-line react/jsx-no-useless-fragment + <> + {tags.length > 0 && ( + +
+ +
+ {tags.length > 1 && ( +
+ +{tags.length - 1} more +
+ )} + + } + title="Tags" + placement="left" + menuClass="top-8" + > +
+
+ +
+
+
+ )} + + ); +} + +const columns: MRT_ColumnDef< + SchemaResourceWithJobStatus & { + table: SchemaResourceType["table"]; + } +>[] = [ + { + accessorKey: "name", + enableResizing: true, + header: "Name", + minSize: 100, + Cell: ({ row }) => { + const { agent, name, spec, table } = row.original; + + return ( +
+ {table === tables.config_scrapers && ( + + )} +
+ {name} + +
+
+ ); + } + }, + { + header: "Source", + accessorKey: "sourceConfig", + enableResizing: true, + minSize: 50, + maxSize: 120, + Cell: ({ row }) => { + const { source, id, name, namespace } = row.original; + + return source && source === "KubernetesCRD" ? ( + { + e.stopPropagation(); + }} + > + + {namespace ? <>{namespace}/ : ""} + {name} + + + ) : ( + Link + ); + } + }, + { + header: "Agent", + accessorKey: "agent", + enableResizing: true, + Cell: ({ row }) => { + return row.original.name; + } + }, + { + header: "Schedule", + accessorKey: "schedule", + enableResizing: false, + size: 100 + }, + { + header: "Namespace", + accessorKey: "namespace", + enableResizing: true, + size: 150 + }, + { + accessorKey: "jobStatus", + header: "Job Status", + enableResizing: true, + Cell: ({ row }) => + }, + { + accessorKey: "last_runtime", + header: "Last Run", + enableResizing: false, + Cell: MRTDateCell, + size: 120 + }, + { + accessorKey: "job_last_failed", + header: "Last Failed", + enableResizing: false, + Cell: MRTDateCell, + size: 140 + }, + { + header: "Tags", + accessorKey: "tags", + enableResizing: true, + enableSorting: false, + Cell: ({ row }) => , + minSize: 250 + }, + { + header: "Created", + accessorKey: "created_at", + enableResizing: false, + Cell: MRTDateCell, + size: 120 + }, + { + header: "Updated", + accessorKey: "updated_at", + enableResizing: false, + Cell: MRTDateCell, + size: 120 + }, + { + header: "Created By", + accessorKey: "created_by", + enableResizing: false, + enableSorting: false, + size: 120, + Cell: ({ row, column }) => { + const { created_by } = row.original; + if (!created_by) { + return null; + } + return ; + } + } +]; + +/** + * + * Columns that are permanently hidden for each table, regardless of user + * settings or preferences, and cannot be shown for that table. + * + */ +const permanentlyHiddenColumnsForTableMap: Record< + SchemaResourceType["table"], + string[] +> = { + topologies: ["schedule"], + connections: ["schedule", "namespace"], + logging_backends: ["schedule", "namespace"], + notifications: ["schedule", "namespace"], + properties: ["schedule", "namespace"], + canaries: ["namespace"], + config_scrapers: ["schedule", "namespace"], + incident_rules: ["schedule", "namespace"], + teams: ["schedule", "namespace"] +}; + +type ResourceTableProps = { + data: SchemaResourceWithJobStatus[]; + onRowClick: (row: SchemaResourceWithJobStatus) => void; + table: SchemaResourceType["table"]; + isLoading?: boolean; + enableServerSidePagination?: boolean; +}; + +export default function ResourceTable({ + data, + onRowClick, + table: sqlTable, + isLoading = false +}: ResourceTableProps) { + const { pageIndex, pageSize, setPageIndex } = useReactTablePaginationState(); + const [sortState, setSortState] = useReactTableSortState(); + + const columnsDerived = useMemo(() => { + return columns.filter( + (column) => + !permanentlyHiddenColumnsForTableMap[sqlTable].includes( + column.accessorKey! + ) + ); + }, [sqlTable]); + + const dataWithTable = useMemo( + () => data.map((row) => ({ ...row, table: sqlTable })), + [data, sqlTable] + ); + + const table = useMantineReactTable({ + data: dataWithTable, + columns: columnsDerived, + enableGlobalFilter: false, + enableFilters: false, + enableHiding: true, + enableSelectAll: false, + enableFullScreenToggle: false, + layoutMode: "grid", + enableColumnResizing: true, + enableStickyHeader: true, + enableTableFooter: true, + enableStickyFooter: true, + // For performance reasons, we set the columnResizeMode to "onEnd" instead + // of "onChange" to avoid re-rendering the table on every column resize. + columnResizeMode: "onEnd", + enableDensityToggle: false, + onPaginationChange: setPageIndex, + onSortingChange: setSortState, + mantineTableBodyRowProps: ({ row }) => ({ + onClick: () => onRowClick(row.original), + sx: { cursor: "pointer", maxHeight: "100%", overflowY: "auto" } + }), + mantinePaperProps: { + sx: { + flex: "1 1 0", + display: "flex", + "flex-flow": "column" + } + }, + mantineTableContainerProps: { + sx: { + // height:'100%' + flex: "1 1 0" + } + }, + state: { + isLoading, + density: "xs", + // temporary + isFullScreen: false, + pagination: { + pageIndex, + pageSize: pageSize + }, + sorting: sortState + }, + initialState: { + pagination: { + pageIndex: 0, + pageSize: 50 + } + }, + mantinePaginationProps: { + rowsPerPageOptions: ["50", "100", "200"] + } + }); + + return ; +} diff --git a/src/ui/DataTable/Hooks/useReactTablePaginationState.tsx b/src/ui/DataTable/Hooks/useReactTablePaginationState.tsx new file mode 100644 index 0000000000..3e987de8a8 --- /dev/null +++ b/src/ui/DataTable/Hooks/useReactTablePaginationState.tsx @@ -0,0 +1,35 @@ +import { OnChangeFn, PaginationState } from "@tanstack/react-table"; +import { useCallback } from "react"; +import { useSearchParams } from "react-router-dom"; + +export default function useReactTablePaginationState() { + const [params, setParams] = useSearchParams({ + pageIndex: "0", + pageSize: "50" + }); + + const pageIndex = parseInt(params.get("pageIndex") ?? "0", 10); + const pageSize = parseInt(params.get("pageSize") ?? "50", 10); + + const setPageIndex: OnChangeFn = useCallback( + (param) => { + const updated = + typeof param === "function" + ? param({ + pageIndex: pageIndex, + pageSize: pageSize + }) + : param; + params.set("pageIndex", updated.pageIndex.toString()); + params.set("pageSize", updated.pageSize.toString()); + setParams(params); + }, + [pageIndex, pageSize, params, setParams] + ); + + return { + pageIndex, + setPageIndex, + pageSize + }; +} diff --git a/src/ui/MRTDataTable/Cells/MRTDateCells.tsx b/src/ui/MRTDataTable/Cells/MRTDateCells.tsx new file mode 100644 index 0000000000..93f208b69d --- /dev/null +++ b/src/ui/MRTDataTable/Cells/MRTDateCells.tsx @@ -0,0 +1,14 @@ +import { Age } from "@flanksource-ui/ui/Age"; +import { MRTCellProps } from "../MRTCellProps"; + +export function MRTDateCell>({ + row, + column +}: MRTCellProps) { + const dateString = row?.getValue(column.id); + return ( +
+ +
+ ); +} diff --git a/src/ui/MRTDataTable/MRTCellProps.ts b/src/ui/MRTDataTable/MRTCellProps.ts new file mode 100644 index 0000000000..8f7587d42a --- /dev/null +++ b/src/ui/MRTDataTable/MRTCellProps.ts @@ -0,0 +1,16 @@ +import { + MRT_Cell, + MRT_Column, + MRT_Row, + MRT_TableInstance +} from "mantine-react-table"; +import { ReactNode, RefObject } from "react"; + +export type MRTCellProps = {}> = { + cell: MRT_Cell; + renderedCellValue: number | string | ReactNode; + column: MRT_Column; + row: MRT_Row; + rowRef?: RefObject; + table: MRT_TableInstance; +};