diff --git a/package.json b/package.json index c0f3e199..aa3ec792 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "embla-carousel-react": "7.1.0", "http-status-codes": "^2.2.0", "immer": "^10.0.2", + "jq-web": "^0.5.1", "js-cookie": "^3.0.5", "just-compare": "^2.3.0", "lodash": "^4.17.21", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2b2251ce..06a90fe9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,19 +16,19 @@ importers: version: 11.11.1(@types/react@18.2.14)(react@18.2.0) '@mantine/carousel': specifier: ^7.8.1 - version: 7.8.1(@mantine/core@7.8.1)(@mantine/hooks@7.8.1)(embla-carousel-react@7.1.0)(react-dom@18.2.0)(react@18.2.0) + version: 7.8.1(@mantine/core@7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@mantine/hooks@7.8.1(react@18.2.0))(embla-carousel-react@7.1.0(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mantine/charts': specifier: ^7.8.1 - version: 7.8.1(@mantine/core@7.8.1)(@mantine/hooks@7.8.1)(react-dom@18.2.0)(react@18.2.0)(recharts@2.12.7) + version: 7.8.1(@mantine/core@7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@mantine/hooks@7.8.1(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(recharts@2.12.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0)) '@mantine/code-highlight': specifier: ^7.8.1 - version: 7.8.1(@mantine/core@7.8.1)(@mantine/hooks@7.8.1)(react-dom@18.2.0)(react@18.2.0) + version: 7.8.1(@mantine/core@7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@mantine/hooks@7.8.1(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mantine/core': specifier: ^7.8.1 - version: 7.8.1(@mantine/hooks@7.8.1)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0) + version: 7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mantine/dates': specifier: ^7.8.1 - version: 7.8.1(@mantine/core@7.8.1)(@mantine/hooks@7.8.1)(dayjs@1.11.10)(react-dom@18.2.0)(react@18.2.0) + version: 7.8.1(@mantine/core@7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@mantine/hooks@7.8.1(react@18.2.0))(dayjs@1.11.10)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mantine/form': specifier: ^7.8.1 version: 7.8.1(react@18.2.0) @@ -37,10 +37,10 @@ importers: version: 7.8.1(react@18.2.0) '@mantine/notifications': specifier: ^7.8.1 - version: 7.8.1(@mantine/core@7.8.1)(@mantine/hooks@7.8.1)(react-dom@18.2.0)(react@18.2.0) + version: 7.8.1(@mantine/core@7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@mantine/hooks@7.8.1(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@monaco-editor/react': specifier: ^4.5.1 - version: 4.5.1(monaco-editor@0.48.0)(react-dom@18.2.0)(react@18.2.0) + version: 4.5.1(monaco-editor@0.48.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@tabler/icons-react': specifier: ^3.3.0 version: 3.3.0(react@18.2.0) @@ -62,6 +62,9 @@ importers: immer: specifier: ^10.0.2 version: 10.0.2 + jq-web: + specifier: ^0.5.1 + version: 0.5.1 js-cookie: specifier: ^3.0.5 version: 3.0.5 @@ -91,7 +94,7 @@ importers: version: 18.2.0 react-beautiful-dnd: specifier: ^13.1.1 - version: 13.1.1(react-dom@18.2.0)(react@18.2.0) + version: 13.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-dom: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) @@ -100,19 +103,19 @@ importers: version: 4.0.10(react@18.2.0) react-query: specifier: ^3.39.3 - version: 3.39.3(react-dom@18.2.0)(react@18.2.0) + version: 3.39.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-querybuilder: specifier: ^6.5.5 version: 6.5.5(react@18.2.0) react-resizable-panels: specifier: ^0.0.53 - version: 0.0.53(react-dom@18.2.0)(react@18.2.0) + version: 0.0.53(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-router-dom: specifier: ^6.14.0 - version: 6.14.0(react-dom@18.2.0)(react@18.2.0) + version: 6.14.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-window: specifier: ^1.8.9 - version: 1.8.9(react-dom@18.2.0)(react@18.2.0) + version: 1.8.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) devDependencies: '@types/lodash': specifier: ^4.17.0 @@ -137,13 +140,13 @@ importers: version: 1.8.5 '@typescript-eslint/eslint-plugin': specifier: ^5.60.1 - version: 5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.43.0)(typescript@5.1.6) + version: 5.60.1(@typescript-eslint/parser@5.60.1(eslint@8.43.0)(typescript@5.1.6))(eslint@8.43.0)(typescript@5.1.6) '@typescript-eslint/parser': specifier: ^5.60.1 version: 5.60.1(eslint@8.43.0)(typescript@5.1.6) '@vitejs/plugin-react-swc': specifier: ^3.3.2 - version: 3.3.2(vite@4.3.9) + version: 3.3.2(vite@4.3.9(@types/node@20.3.2)(sugarss@4.0.1(postcss@8.4.33))) eslint: specifier: ^8.43.0 version: 8.43.0 @@ -152,10 +155,10 @@ importers: version: 8.8.0(eslint@8.43.0) eslint-plugin-import: specifier: ^2.27.5 - version: 2.27.5(@typescript-eslint/parser@5.60.1)(eslint@8.43.0) + version: 2.27.5(@typescript-eslint/parser@5.60.1(eslint@8.43.0)(typescript@5.1.6))(eslint@8.43.0) eslint-plugin-prettier: specifier: ^4.2.1 - version: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.43.0)(prettier@2.8.8) + version: 4.2.1(eslint-config-prettier@8.8.0(eslint@8.43.0))(eslint@8.43.0)(prettier@2.8.8) eslint-plugin-react: specifier: ^7.32.2 version: 7.32.2(eslint@8.43.0) @@ -185,7 +188,7 @@ importers: version: 5.1.6 vite: specifier: ^4.3.9 - version: 4.3.9(@types/node@20.3.2) + version: 4.3.9(@types/node@20.3.2)(sugarss@4.0.1(postcss@8.4.33)) packages: @@ -1547,6 +1550,9 @@ packages: peerDependencies: ws: '*' + jq-web@0.5.1: + resolution: {integrity: sha512-3Fa3E6g3U1O1j46ljy0EM10yRr4txzILga8J7bqOG8F89gZ6Lilz82WG9z6TItWpYEO0YGa4W8yFGj+NMM1xqQ==} + js-base64@3.7.5: resolution: {integrity: sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==} @@ -2467,9 +2473,10 @@ snapshots: '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0) '@emotion/utils': 1.2.1 '@emotion/weak-memoize': 0.3.1 - '@types/react': 18.2.14 hoist-non-react-statics: 3.3.2 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.14 '@emotion/serialize@1.1.2': dependencies: @@ -2589,15 +2596,15 @@ snapshots: '@floating-ui/core': 1.6.0 '@floating-ui/utils': 0.2.1 - '@floating-ui/react-dom@2.0.8(react-dom@18.2.0)(react@18.2.0)': + '@floating-ui/react-dom@2.0.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@floating-ui/dom': 1.6.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@floating-ui/react@0.26.12(react-dom@18.2.0)(react@18.2.0)': + '@floating-ui/react@0.26.12(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@floating-ui/react-dom': 2.0.8(react-dom@18.2.0)(react@18.2.0) + '@floating-ui/react-dom': 2.0.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@floating-ui/utils': 0.2.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -2617,48 +2624,48 @@ snapshots: '@humanwhocodes/object-schema@1.2.1': {} - '@mantine/carousel@7.8.1(@mantine/core@7.8.1)(@mantine/hooks@7.8.1)(embla-carousel-react@7.1.0)(react-dom@18.2.0)(react@18.2.0)': + '@mantine/carousel@7.8.1(@mantine/core@7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@mantine/hooks@7.8.1(react@18.2.0))(embla-carousel-react@7.1.0(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@mantine/core': 7.8.1(@mantine/hooks@7.8.1)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0) + '@mantine/core': 7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mantine/hooks': 7.8.1(react@18.2.0) embla-carousel-react: 7.1.0(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@mantine/charts@7.8.1(@mantine/core@7.8.1)(@mantine/hooks@7.8.1)(react-dom@18.2.0)(react@18.2.0)(recharts@2.12.7)': + '@mantine/charts@7.8.1(@mantine/core@7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@mantine/hooks@7.8.1(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(recharts@2.12.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0))': dependencies: - '@mantine/core': 7.8.1(@mantine/hooks@7.8.1)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0) + '@mantine/core': 7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mantine/hooks': 7.8.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - recharts: 2.12.7(react-dom@18.2.0)(react@18.2.0) + recharts: 2.12.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@mantine/code-highlight@7.8.1(@mantine/core@7.8.1)(@mantine/hooks@7.8.1)(react-dom@18.2.0)(react@18.2.0)': + '@mantine/code-highlight@7.8.1(@mantine/core@7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@mantine/hooks@7.8.1(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@mantine/core': 7.8.1(@mantine/hooks@7.8.1)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0) + '@mantine/core': 7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mantine/hooks': 7.8.1(react@18.2.0) clsx: 2.1.0 highlight.js: 11.9.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@mantine/core@7.8.1(@mantine/hooks@7.8.1)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)': + '@mantine/core@7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@floating-ui/react': 0.26.12(react-dom@18.2.0)(react@18.2.0) + '@floating-ui/react': 0.26.12(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mantine/hooks': 7.8.1(react@18.2.0) clsx: 2.1.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-number-format: 5.3.1(react-dom@18.2.0)(react@18.2.0) + react-number-format: 5.3.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-remove-scroll: 2.5.7(@types/react@18.2.14)(react@18.2.0) react-textarea-autosize: 8.5.3(@types/react@18.2.14)(react@18.2.0) type-fest: 4.16.0 transitivePeerDependencies: - '@types/react' - '@mantine/dates@7.8.1(@mantine/core@7.8.1)(@mantine/hooks@7.8.1)(dayjs@1.11.10)(react-dom@18.2.0)(react@18.2.0)': + '@mantine/dates@7.8.1(@mantine/core@7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@mantine/hooks@7.8.1(react@18.2.0))(dayjs@1.11.10)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@mantine/core': 7.8.1(@mantine/hooks@7.8.1)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0) + '@mantine/core': 7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mantine/hooks': 7.8.1(react@18.2.0) clsx: 2.1.0 dayjs: 1.11.10 @@ -2675,14 +2682,14 @@ snapshots: dependencies: react: 18.2.0 - '@mantine/notifications@7.8.1(@mantine/core@7.8.1)(@mantine/hooks@7.8.1)(react-dom@18.2.0)(react@18.2.0)': + '@mantine/notifications@7.8.1(@mantine/core@7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@mantine/hooks@7.8.1(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@mantine/core': 7.8.1(@mantine/hooks@7.8.1)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0) + '@mantine/core': 7.8.1(@mantine/hooks@7.8.1(react@18.2.0))(@types/react@18.2.14)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mantine/hooks': 7.8.1(react@18.2.0) '@mantine/store': 7.8.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-transition-group: 4.4.5(react-dom@18.2.0)(react@18.2.0) + react-transition-group: 4.4.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mantine/store@7.8.1(react@18.2.0)': dependencies: @@ -2693,7 +2700,7 @@ snapshots: monaco-editor: 0.48.0 state-local: 1.0.7 - '@monaco-editor/react@4.5.1(monaco-editor@0.48.0)(react-dom@18.2.0)(react@18.2.0)': + '@monaco-editor/react@4.5.1(monaco-editor@0.48.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@monaco-editor/loader': 1.3.3(monaco-editor@0.48.0) monaco-editor: 0.48.0 @@ -2871,7 +2878,7 @@ snapshots: '@types/semver@7.5.0': {} - '@typescript-eslint/eslint-plugin@5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.43.0)(typescript@5.1.6)': + '@typescript-eslint/eslint-plugin@5.60.1(@typescript-eslint/parser@5.60.1(eslint@8.43.0)(typescript@5.1.6))(eslint@8.43.0)(typescript@5.1.6)': dependencies: '@eslint-community/regexpp': 4.5.1 '@typescript-eslint/parser': 5.60.1(eslint@8.43.0)(typescript@5.1.6) @@ -2885,6 +2892,7 @@ snapshots: natural-compare-lite: 1.4.0 semver: 7.5.1 tsutils: 3.21.0(typescript@5.1.6) + optionalDependencies: typescript: 5.1.6 transitivePeerDependencies: - supports-color @@ -2896,6 +2904,7 @@ snapshots: '@typescript-eslint/typescript-estree': 5.60.1(typescript@5.1.6) debug: 4.3.4 eslint: 8.43.0 + optionalDependencies: typescript: 5.1.6 transitivePeerDependencies: - supports-color @@ -2912,6 +2921,7 @@ snapshots: debug: 4.3.4 eslint: 8.43.0 tsutils: 3.21.0(typescript@5.1.6) + optionalDependencies: typescript: 5.1.6 transitivePeerDependencies: - supports-color @@ -2927,6 +2937,7 @@ snapshots: is-glob: 4.0.3 semver: 7.5.1 tsutils: 3.21.0(typescript@5.1.6) + optionalDependencies: typescript: 5.1.6 transitivePeerDependencies: - supports-color @@ -2951,10 +2962,10 @@ snapshots: '@typescript-eslint/types': 5.60.1 eslint-visitor-keys: 3.4.1 - '@vitejs/plugin-react-swc@3.3.2(vite@4.3.9)': + '@vitejs/plugin-react-swc@3.3.2(vite@4.3.9(@types/node@20.3.2)(sugarss@4.0.1(postcss@8.4.33)))': dependencies: '@swc/core': 1.3.67 - vite: 4.3.9(@types/node@20.3.2) + vite: 4.3.9(@types/node@20.3.2)(sugarss@4.0.1(postcss@8.4.33)) transitivePeerDependencies: - '@swc/helpers' @@ -3354,18 +3365,18 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@5.60.1)(eslint-import-resolver-node@0.3.7)(eslint@8.43.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@5.60.1(eslint@8.43.0)(typescript@5.1.6))(eslint-import-resolver-node@0.3.7)(eslint@8.43.0): dependencies: - '@typescript-eslint/parser': 5.60.1(eslint@8.43.0)(typescript@5.1.6) debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 5.60.1(eslint@8.43.0)(typescript@5.1.6) eslint: 8.43.0 eslint-import-resolver-node: 0.3.7 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.60.1)(eslint@8.43.0): + eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.60.1(eslint@8.43.0)(typescript@5.1.6))(eslint@8.43.0): dependencies: - '@typescript-eslint/parser': 5.60.1(eslint@8.43.0)(typescript@5.1.6) array-includes: 3.1.6 array.prototype.flat: 1.3.1 array.prototype.flatmap: 1.3.1 @@ -3373,7 +3384,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.43.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.60.1)(eslint-import-resolver-node@0.3.7)(eslint@8.43.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.60.1(eslint@8.43.0)(typescript@5.1.6))(eslint-import-resolver-node@0.3.7)(eslint@8.43.0) has: 1.0.3 is-core-module: 2.12.1 is-glob: 4.0.3 @@ -3382,17 +3393,20 @@ snapshots: resolve: 1.22.2 semver: 6.3.0 tsconfig-paths: 3.14.2 + optionalDependencies: + '@typescript-eslint/parser': 5.60.1(eslint@8.43.0)(typescript@5.1.6) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.8.0)(eslint@8.43.0)(prettier@2.8.8): + eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.8.0(eslint@8.43.0))(eslint@8.43.0)(prettier@2.8.8): dependencies: eslint: 8.43.0 - eslint-config-prettier: 8.8.0(eslint@8.43.0) prettier: 2.8.8 prettier-linter-helpers: 1.0.0 + optionalDependencies: + eslint-config-prettier: 8.8.0(eslint@8.43.0) eslint-plugin-react-hooks@4.6.0(eslint@8.43.0): dependencies: @@ -3798,6 +3812,8 @@ snapshots: dependencies: ws: 8.17.0 + jq-web@0.5.1: {} + js-base64@3.7.5: {} js-cookie@3.0.5: {} @@ -4132,7 +4148,7 @@ snapshots: raf-schd@4.0.3: {} - react-beautiful-dnd@13.1.1(react-dom@18.2.0)(react@18.2.0): + react-beautiful-dnd@13.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.21.5 css-box-model: 1.2.1 @@ -4140,7 +4156,7 @@ snapshots: raf-schd: 4.0.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-redux: 7.2.9(react-dom@18.2.0)(react@18.2.0) + react-redux: 7.2.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) redux: 4.2.1 use-memo-one: 1.1.3(react@18.2.0) transitivePeerDependencies: @@ -4161,18 +4177,19 @@ snapshots: react-is@17.0.2: {} - react-number-format@5.3.1(react-dom@18.2.0)(react@18.2.0): + react-number-format@5.3.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-query@3.39.3(react-dom@18.2.0)(react@18.2.0): + react-query@3.39.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.21.5 broadcast-channel: 3.7.0 match-sorter: 6.3.1 react: 18.2.0 + optionalDependencies: react-dom: 18.2.0(react@18.2.0) react-querybuilder@6.5.5(react@18.2.0): @@ -4181,7 +4198,7 @@ snapshots: immer: 10.0.3 react: 18.2.0 - react-redux@7.2.9(react-dom@18.2.0)(react@18.2.0): + react-redux@7.2.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.21.5 '@types/react-redux': 7.1.25 @@ -4189,32 +4206,35 @@ snapshots: loose-envify: 1.4.0 prop-types: 15.8.1 react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) react-is: 17.0.2 + optionalDependencies: + react-dom: 18.2.0(react@18.2.0) react-remove-scroll-bar@2.3.4(@types/react@18.2.14)(react@18.2.0): dependencies: - '@types/react': 18.2.14 react: 18.2.0 react-style-singleton: 2.2.1(@types/react@18.2.14)(react@18.2.0) tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.14 react-remove-scroll@2.5.7(@types/react@18.2.14)(react@18.2.0): dependencies: - '@types/react': 18.2.14 react: 18.2.0 react-remove-scroll-bar: 2.3.4(@types/react@18.2.14)(react@18.2.0) react-style-singleton: 2.2.1(@types/react@18.2.14)(react@18.2.0) tslib: 2.6.2 use-callback-ref: 1.3.0(@types/react@18.2.14)(react@18.2.0) use-sidecar: 1.1.2(@types/react@18.2.14)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.14 - react-resizable-panels@0.0.53(react-dom@18.2.0)(react@18.2.0): + react-resizable-panels@0.0.53(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-router-dom@6.14.0(react-dom@18.2.0)(react@18.2.0): + react-router-dom@6.14.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@remix-run/router': 1.7.0 react: 18.2.0 @@ -4226,21 +4246,22 @@ snapshots: '@remix-run/router': 1.7.0 react: 18.2.0 - react-smooth@4.0.1(react-dom@18.2.0)(react@18.2.0): + react-smooth@4.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: fast-equals: 5.0.1 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-transition-group: 4.4.5(react-dom@18.2.0)(react@18.2.0) + react-transition-group: 4.4.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-style-singleton@2.2.1(@types/react@18.2.14)(react@18.2.0): dependencies: - '@types/react': 18.2.14 get-nonce: 1.0.1 invariant: 2.2.4 react: 18.2.0 tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.14 react-textarea-autosize@8.5.3(@types/react@18.2.14)(react@18.2.0): dependencies: @@ -4251,7 +4272,7 @@ snapshots: transitivePeerDependencies: - '@types/react' - react-transition-group@4.4.5(react-dom@18.2.0)(react@18.2.0): + react-transition-group@4.4.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.21.5 dom-helpers: 5.2.1 @@ -4260,7 +4281,7 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-window@1.8.9(react-dom@18.2.0)(react@18.2.0): + react-window@1.8.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.21.5 memoize-one: 5.2.1 @@ -4275,7 +4296,7 @@ snapshots: dependencies: decimal.js-light: 2.5.1 - recharts@2.12.7(react-dom@18.2.0)(react@18.2.0): + recharts@2.12.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: clsx: 2.1.1 eventemitter3: 4.0.7 @@ -4283,7 +4304,7 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-is: 16.13.1 - react-smooth: 4.0.1(react-dom@18.2.0)(react@18.2.0) + react-smooth: 4.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) recharts-scale: 0.4.5 tiny-invariant: 1.3.3 victory-vendor: 36.9.2 @@ -4507,9 +4528,10 @@ snapshots: use-callback-ref@1.3.0(@types/react@18.2.14)(react@18.2.0): dependencies: - '@types/react': 18.2.14 react: 18.2.0 tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.14 use-composed-ref@1.3.0(react@18.2.0): dependencies: @@ -4517,14 +4539,16 @@ snapshots: use-isomorphic-layout-effect@1.1.2(@types/react@18.2.14)(react@18.2.0): dependencies: - '@types/react': 18.2.14 react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.14 use-latest@1.2.1(@types/react@18.2.14)(react@18.2.0): dependencies: - '@types/react': 18.2.14 react: 18.2.0 use-isomorphic-layout-effect: 1.1.2(@types/react@18.2.14)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.14 use-memo-one@1.1.3(react@18.2.0): dependencies: @@ -4532,10 +4556,11 @@ snapshots: use-sidecar@1.1.2(@types/react@18.2.14)(react@18.2.0): dependencies: - '@types/react': 18.2.14 detect-node-es: 1.1.0 react: 18.2.0 tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.2.14 util-deprecate@1.0.2: {} @@ -4556,14 +4581,15 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite@4.3.9(@types/node@20.3.2): + vite@4.3.9(@types/node@20.3.2)(sugarss@4.0.1(postcss@8.4.33)): dependencies: - '@types/node': 20.3.2 esbuild: 0.17.19 postcss: 8.4.33 rollup: 3.23.0 optionalDependencies: + '@types/node': 20.3.2 fsevents: 2.3.3 + sugarss: 4.0.1(postcss@8.4.33) which-boxed-primitive@1.0.2: dependencies: diff --git a/src/constants/theme.ts b/src/constants/theme.ts index 973f6e51..4d91ad67 100644 --- a/src/constants/theme.ts +++ b/src/constants/theme.ts @@ -7,4 +7,5 @@ export const LOGS_SECONDARY_TOOLBAR_HEIGHT = 68; export const STREAM_PRIMARY_TOOLBAR_CONTAINER_HEIGHT = 48; export const STREAM_PRIMARY_TOOLBAR_HEIGHT = 26; export const STREAM_SECONDARY_TOOLBAR_HRIGHT = 70; -export const SECONDARY_SIDEBAR_WIDTH = 50; \ No newline at end of file +export const SECONDARY_SIDEBAR_WIDTH = 50; +export const JSON_VIEW_TOOLBAR_HEIGHT = 50; \ No newline at end of file diff --git a/src/hooks/useQueryLogs.ts b/src/hooks/useQueryLogs.ts index 700a6194..11797eee 100644 --- a/src/hooks/useQueryLogs.ts +++ b/src/hooks/useQueryLogs.ts @@ -3,12 +3,13 @@ import { getQueryLogs, getQueryResult } from '@/api/query'; import { StatusCodes } from 'http-status-codes'; import useMountedState from './useMountedState'; import { useCallback, useEffect, useRef } from 'react'; -import { useLogsStore, logsStoreReducers, LOAD_LIMIT } from '@/pages/Stream/providers/LogsProvider'; +import { useLogsStore, logsStoreReducers, LOAD_LIMIT, isJqSearch } from '@/pages/Stream/providers/LogsProvider'; import { useAppStore } from '@/layouts/MainLayout/providers/AppProvider'; import { useQueryResult } from './useQueryResult'; import _ from 'lodash'; import { useStreamStore } from '@/pages/Stream/providers/StreamProvider'; import { AxiosError } from 'axios'; +import jqSearch from '@/utils/jqSearch'; const { setData, setTotalCount } = logsStoreReducers; @@ -46,7 +47,7 @@ export const useQueryLogs = () => { const [ { timeRange, - tableOpts: { currentOffset }, + tableOpts: { currentOffset, instantSearchValue }, custQuerySearchState, }, setLogsStore, @@ -93,7 +94,8 @@ export const useQueryLogs = () => { const data = logsQueryRes.data; if (logsQueryRes.status === StatusCodes.OK) { - return setLogsStore((store) => setData(store, data, schema)); + const jqFilteredData = isJqSearch(instantSearchValue) ? await jqSearch(data, instantSearchValue) : []; + return setLogsStore((store) => setData(store, data, schema, jqFilteredData)); } if (typeof data === 'string' && data.includes('Stream is not initialized yet')) { return setLogsStore((store) => setData(store, [], schema)); diff --git a/src/jq-web.d.ts b/src/jq-web.d.ts new file mode 100644 index 00000000..9e8114d0 --- /dev/null +++ b/src/jq-web.d.ts @@ -0,0 +1,13 @@ +declare module 'jq-web' { + interface JQWeb { + json( + records: { + [key: string]: any; // Use `any` if the values can be of any type. Replace `any` with a specific type if needed. + }, + filter: string, + ): Promise; + } + + const jq: JQWeb; + export default jq; +} \ No newline at end of file diff --git a/src/pages/Stream/Views/Explore/Footer.tsx b/src/pages/Stream/Views/Explore/Footer.tsx new file mode 100644 index 00000000..17af5075 --- /dev/null +++ b/src/pages/Stream/Views/Explore/Footer.tsx @@ -0,0 +1,214 @@ +import { FC, useCallback } from "react"; +import { useLogsStore, logsStoreReducers, LOAD_LIMIT, LOG_QUERY_LIMITS } from "../../providers/LogsProvider"; +import { useAppStore } from "@/layouts/MainLayout/providers/AppProvider"; +import { usePagination } from "@mantine/hooks"; +import { downloadDataAsCSV, downloadDataAsJson } from "@/utils/exportHelpers"; +import { Box, Center, Group, Loader, Menu, Pagination, px, Stack, Tooltip } from "@mantine/core"; +import _ from "lodash"; +import { Text } from "@mantine/core"; +import { HumanizeNumber } from "@/utils/formatBytes"; +import IconButton from "@/components/Button/IconButton"; +import { IconDownload, IconSelector } from "@tabler/icons-react"; +import useMountedState from "@/hooks/useMountedState"; +import classes from '../../styles/Footer.module.css' + +const {setPageAndPageData, setCurrentPage, setCurrentOffset, makeExportData} = logsStoreReducers; + +const TotalCount = (props: { totalCount: number }) => { + return ( + + {HumanizeNumber(props.totalCount)} + + ); +}; + +const renderExportIcon = () => ; + +const TotalLogsCount = (props: { hasTableLoaded: boolean; isFetchingCount: boolean; isTableEmpty: boolean }) => { + const [{ totalCount, perPage, pageData }] = useLogsStore((store) => store.tableOpts); + const displayedCount = _.size(pageData); + const showingCount = displayedCount < perPage ? displayedCount : perPage; + if (typeof totalCount !== 'number' || typeof displayedCount !== 'number') return ; + return ( + + {props.hasTableLoaded ? ( + props.isFetchingCount ? ( + + ) : ( + <> + {`Showing ${showingCount} out of`} + + records + + ) + ) : props.isTableEmpty ? null : ( + + )} + + ); +}; + + +const LimitControl: FC = () => { + const [opened, setOpened] = useMountedState(false); + const [perPage, setLogsStore] = useLogsStore((store) => store.tableOpts.perPage); + + const toggle = () => { + setOpened(!opened); + }; + + const onSelect = (limit: number) => { + if (perPage !== limit) { + setLogsStore((store) => setPageAndPageData(store, 1, limit)); + } + }; + + return ( + + +
+ + + {perPage} + + + +
+ + {LOG_QUERY_LIMITS.map((limit) => { + return ( + onSelect(limit)}> +
+ {limit} +
+
+ ); + })} +
+
+
+ ); +}; + +const Footer = (props: { loaded: boolean; isLoading: boolean; hasNoData: boolean }) => { + const [tableOpts, setLogsStore] = useLogsStore((store) => store.tableOpts); + const [filteredData] = useLogsStore((store) => store.data.filteredData); + const { totalPages, currentOffset, currentPage, perPage, headers, totalCount } = tableOpts; + const onPageChange = useCallback((page: number) => { + setLogsStore((store) => setPageAndPageData(store, page)); + }, []); + const [currentStream] = useAppStore((store) => store.currentStream); + const pagination = usePagination({ total: totalPages ?? 1, initialPage: 1, onChange: onPageChange }); + const onChangeOffset = useCallback( + (key: 'prev' | 'next') => { + if (key === 'prev') { + const targetOffset = currentOffset - LOAD_LIMIT; + if (currentOffset < 0) return; + + if (targetOffset === 0 && currentOffset > 0) { + // hack to initiate fetch + setLogsStore((store) => setCurrentPage(store, 0)); + } + setLogsStore((store) => setCurrentOffset(store, targetOffset)); + } else { + const targetOffset = currentOffset + LOAD_LIMIT; + setLogsStore((store) => setCurrentOffset(store, targetOffset)); + } + }, + [currentOffset], + ); + + const exportHandler = useCallback( + (fileType: string | null) => { + const filename = `${currentStream}-logs`; + if (fileType === 'CSV') { + downloadDataAsCSV(makeExportData(filteredData, headers, 'CSV'), filename); + } else if (fileType === 'JSON') { + downloadDataAsJson(makeExportData(filteredData, headers, 'JSON'), filename); + } + }, + [currentStream, filteredData, headers], + ); + + return ( + + + + + + {props.loaded ? ( + { + pagination.setPage(page); + }} + size="sm"> + + { + currentOffset !== 0 && onChangeOffset('prev'); + }} + disabled={currentOffset === 0} + /> + + {pagination.range.map((page, index) => { + if (page === 'dots') { + return ; + } else { + return ( + { + pagination.setPage(page); + }}> + {(perPage ? page + currentOffset / perPage : page) ?? 1} + + ); + } + })} + + { + onChangeOffset('next'); + }} + disabled={!(currentOffset + LOAD_LIMIT < totalCount)} + /> + + + ) : null} + + + {props.loaded && ( + + +
+ +
+
+ + exportHandler('CSV')} style={{ padding: '0.5rem 2.25rem 0.5rem 0.75rem' }}> + CSV + + exportHandler('JSON')} style={{ padding: '0.5rem 2.25rem 0.5rem 0.75rem' }}> + JSON + + +
+ )} + +
+
+ ); +}; + +export default Footer; \ No newline at end of file diff --git a/src/pages/Stream/Views/Explore/JSONView.tsx b/src/pages/Stream/Views/Explore/JSONView.tsx new file mode 100644 index 00000000..b6d3ff9e --- /dev/null +++ b/src/pages/Stream/Views/Explore/JSONView.tsx @@ -0,0 +1,222 @@ +import { Box, Loader, Stack, Text, TextInput } from '@mantine/core'; +import { ChangeEvent, ReactNode, useCallback, useRef, useState } from 'react'; +import classes from '../../styles/JSONView.module.css'; +import EmptyBox from '@/components/Empty'; +import { ErrorView, LoadingView } from './LoadingViews'; +import Footer from './Footer'; +import { useAppStore } from '@/layouts/MainLayout/providers/AppProvider'; +import { + PRIMARY_HEADER_HEIGHT, + STREAM_PRIMARY_TOOLBAR_CONTAINER_HEIGHT, + STREAM_SECONDARY_TOOLBAR_HRIGHT, +} from '@/constants/theme'; +import { columnsToSkip, useLogsStore, logsStoreReducers, isJqSearch } from '../../providers/LogsProvider'; +import { Log } from '@/@types/parseable/api/query'; +import _ from 'lodash'; +import jqSearch from '@/utils/jqSearch'; +import { IconCheck, IconCopy, IconSearch } from '@tabler/icons-react'; + +const { setInstantSearchValue, applyInstantSearch, applyJqSearch } = logsStoreReducers; + +const Item = (props: { header: string | null; value: string; highlight: boolean }) => { + return ( + + {props.header && {props.header}: } + + {props.value}{' '} + + + ); +}; + +const CopyIcon = (props: { log: Log }) => { + const copyIconRef = useRef(null); + const copiedIconRef = useRef(null); + + const onCopy = async () => { + if (copyIconRef.current && copiedIconRef.current) { + copyIconRef.current.style.display = 'none'; + copiedIconRef.current.style.display = 'flex'; + } + await navigator.clipboard.writeText(JSON.stringify(props.log, null, 2)); + setTimeout(() => { + if (copyIconRef.current && copiedIconRef.current) { + copiedIconRef.current.style.display = 'none'; + copyIconRef.current.style.display = 'flex'; + } + }, 1500); + }; + + return ( + + + + + + + + + ); +}; + +const Row = (props: { + log: Log; + headers: string[]; + searchValue: string; + disableHighlight: boolean; + shouldHighlight: (val: number | string | Date | null) => boolean; +}) => { + const { log, headers, disableHighlight, shouldHighlight } = props; + + return ( + + + {_.isObject(log) ? ( + _.map(headers, (header, index) => ( + + )) + ) : ( + + )} + + + + ); +}; + +const JsonRows = (props: { isSearching: boolean }) => { + const [{ pageData, headers, instantSearchValue }] = useLogsStore((store) => store.tableOpts); + const sanitizedHeaders = _.without(headers, ...columnsToSkip); + const disableHighlight = props.isSearching || _.isEmpty(instantSearchValue) || isJqSearch(instantSearchValue); + const regExp = disableHighlight ? null : new RegExp(instantSearchValue, 'i'); + + const shouldHighlight = useCallback( + (val: number | string | Date | null) => { + return !!regExp?.test(_.toString(val)); + }, + [regExp], + ); + + return ( + + {_.map(pageData, (d, index) => ( + + ))} + + ); +}; + +const Toolbar = (props: { isSearching: boolean; setSearching: React.Dispatch> }) => { + const { isSearching, setSearching } = props; + const [searchValue, setLogsStore] = useLogsStore((store) => store.tableOpts.instantSearchValue); + const [{ rawData, filteredData }] = useLogsStore((store) => store.data); + + const debouncedSearch = useCallback( + _.debounce(async (val: string) => { + const isJq = isJqSearch(val); + if (isJq) { + const jqResult = await jqSearch(rawData, val); + setLogsStore((store) => applyJqSearch(store, jqResult)); + } else { + setLogsStore(applyInstantSearch); + } + setSearching(false); + }, 1000), + [rawData], + ); + + const onChange = useCallback((e: ChangeEvent) => { + setLogsStore((store) => setInstantSearchValue(store, e.target.value)); + debouncedSearch(e.target.value); + setSearching(true); + }, []); + + if (_.isEmpty(rawData)) return null; + + return ( + + : } + placeholder="Search loaded data with text or jq. For jq input try `jq .[]`" + value={searchValue} + onChange={onChange} + style={{ '--input-left-section-width': '2rem', '--input-right-section-width': '6rem' }} + rightSection={ + !_.isEmpty(searchValue) && + !isSearching && ( + + {_.size(filteredData)} Matches + + ) + } + /> + + ); +}; + +const TableContainer = (props: { children: ReactNode }) => { + return {props.children}; +}; + +const JsonView = (props: { + isFetchingCount: boolean; + errorMessage: string | null; + hasNoData: boolean; + showTable: boolean; +}) => { + const [maximized] = useAppStore((store) => store.maximized); + + const { isFetchingCount, errorMessage, hasNoData, showTable } = props; + const [isSearching, setSearching] = useState(false); + const primaryHeaderHeight = !maximized + ? PRIMARY_HEADER_HEIGHT + STREAM_PRIMARY_TOOLBAR_CONTAINER_HEIGHT + STREAM_SECONDARY_TOOLBAR_HRIGHT + : 0; + + return ( + + + {!errorMessage ? ( + showTable ? ( + + + + + + + + + + ) : hasNoData ? ( + <> + + + ) : ( + + ) + ) : ( + + )} +