diff --git a/examples/next-14/.eslintignore b/examples/next-14/.eslintignore new file mode 100644 index 00000000..94b27951 --- /dev/null +++ b/examples/next-14/.eslintignore @@ -0,0 +1,10 @@ +node_modules +out +.next +static +package.json +package-lock.json +nodemon.json +lib/ +cypress/ +**/__generated__/** \ No newline at end of file diff --git a/examples/next-14/.eslintrc.js b/examples/next-14/.eslintrc.js new file mode 100644 index 00000000..402f382e --- /dev/null +++ b/examples/next-14/.eslintrc.js @@ -0,0 +1,60 @@ +module.exports = { + env: { + browser: true, + es6: true, + node: true, // tells the parser that we are using nodejs + }, + + settings: { + react: { + version: require('./package.json').dependencies.react, + }, + }, + extends: [ + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:cypress/recommended', + 'next', + 'plugin:prettier/recommended', + ], + globals: { + Atomics: 'readonly', + SharedArrayBuffer: 'readonly', + globalThis: 'readonly', + }, + parser: '@babel/eslint-parser', + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + ecmaVersion: 2018, + sourceType: 'module', + }, + plugins: ['react', 'cypress', 'prettier'], + rules: { + '@next/next/no-img-element': 'off', + 'react-hooks/rules-of-hooks': 'warn', + 'react-hooks/exhaustive-deps': 'off', + 'jsx-a11y/alt-text': 'off', + 'valid-typeof': 'warn', + 'no-trailing-spaces': 'error', + 'block-spacing': 'error', + 'brace-style': ['error', '1tbs'], + 'react/react-in-jsx-scope': 'off', + 'no-undef': 'error', + 'react/jsx-uses-vars': [2], + 'react/jsx-no-undef': 'error', + 'no-console': 0, + 'no-unused-vars': 'error', + 'react/jsx-key': 'warn', + 'no-dupe-keys': 'error', + 'react/jsx-filename-extension': [ + 1, + { + extensions: ['.js', '.jsx'], + }, + ], + 'react/prop-types': 'off', + 'prettier/prettier': ['error', { endOfLine: 'lf' }], + }, +}; \ No newline at end of file diff --git a/examples/next-14/.gitignore b/examples/next-14/.gitignore new file mode 100644 index 00000000..fd3dbb57 --- /dev/null +++ b/examples/next-14/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/examples/next-14/.prettierignore b/examples/next-14/.prettierignore new file mode 100644 index 00000000..d17411d6 --- /dev/null +++ b/examples/next-14/.prettierignore @@ -0,0 +1,15 @@ +*.svg +*.ico +*.css + +*/.DS_Store +assets/** +.next +package.json +package-lock.json +public +node_modules +next-env.d.ts +next.config.js +.eslintrc.js +**/__generated__/** \ No newline at end of file diff --git a/examples/next-14/.prettierrc.yml b/examples/next-14/.prettierrc.yml new file mode 100644 index 00000000..d75e5e04 --- /dev/null +++ b/examples/next-14/.prettierrc.yml @@ -0,0 +1,13 @@ +arrowParens: always +bracketSameLine: false +bracketSpacing: true +jsxSingleQuote: false +proseWrap: preserve +quoteProps: as-needed +semi: true +singleQuote: true +tabWidth: 2 +trailingComma: all +printWidth: 100 +useTabs: false +endOfLine: 'lf' diff --git a/examples/next-14/README.md b/examples/next-14/README.md new file mode 100644 index 00000000..5d98b1e5 --- /dev/null +++ b/examples/next-14/README.md @@ -0,0 +1,40 @@ +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. + +[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. + +This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/examples/next-14/bun.lockb b/examples/next-14/bun.lockb new file mode 100755 index 00000000..97a66ce0 Binary files /dev/null and b/examples/next-14/bun.lockb differ diff --git a/examples/next-14/components/BBChart/index.jsx b/examples/next-14/components/BBChart/index.jsx new file mode 100644 index 00000000..f4d7dcf5 --- /dev/null +++ b/examples/next-14/components/BBChart/index.jsx @@ -0,0 +1,18 @@ +import { useEffect, useRef, memo } from 'react'; +import bb from 'billboard.js'; + +function BBChart({ options }) { + const chartRef = useRef(null); + + useEffect(() => { + const chart = bb.generate({ ...options, bindto: chartRef.current }); + + return () => { + chart.destroy(); + }; + }, [options]); + + return
; +} + +export default memo(BBChart); diff --git a/examples/next-14/components/ConnectionWizard/helpers/metrics.js b/examples/next-14/components/ConnectionWizard/helpers/metrics.js new file mode 100644 index 00000000..25403f80 --- /dev/null +++ b/examples/next-14/components/ConnectionWizard/helpers/metrics.js @@ -0,0 +1,280 @@ +import { NOTIFICATION_EVENT_TYPES } from '@/utils/constants/notification'; +import { result } from 'lodash'; +import dataFetch from '@/utils/dataFetch'; +import { ctxUrl } from '@/utils/multi-ctx'; + +export const verifyGrafanaConnection = (grafanaUrl) => { + return new Promise((res, rej) => { + if (grafanaUrl) { + pingGrafana( + (result) => res('Grafana connected !'), + (error) => rej('Grafana not connected ! ' + error), + ); + return; + } + rej('Grafana not connected! ' + 'Url not found'); + }); +}; + +export const pingGrafanaWithNotification = (notify, updateProgress) => { + updateProgress({ showProgress: true }); + const successCb = (result) => { + updateProgress({ showProgress: false }); + if (typeof result !== 'undefined') { + notify({ + message: 'Grafana connected!', + event_type: NOTIFICATION_EVENT_TYPES.SUCCESS, + }); + } + }; + + const errorCb = (error) => { + updateProgress({ showProgress: false }); + notify({ + message: 'Grafana not connected! : ' + error, + event_type: NOTIFICATION_EVENT_TYPES.ERROR, + details: error.toString(), + }); + }; + + pingGrafana(successCb, errorCb); +}; + +export const pingGrafana = (successCb, errorCb) => + dataFetch('/api/telemetry/metrics/grafana/ping', { credentials: 'include' }, successCb, errorCb); + +export const verifyPrometheusConnection = (prometheusUrl) => { + console.log(prometheusUrl); + return new Promise((res, rej) => { + if (prometheusUrl !== '') { + pingPrometheus( + (result) => res('Prometheus connected !'), + (error) => rej('Prometheus not connected ! ' + error), + ); + return; + } else rej('Prometheus not connected! ' + 'Url not found'); + }); +}; + +export const pingPrometheusWithNotification = (notify, updateProgress) => { + updateProgress({ showProgress: true }); + + const successCb = (result) => { + updateProgress({ showProgress: false }); + if (typeof result !== 'undefined') { + notify({ + message: 'Prometheus connected!', + event_type: NOTIFICATION_EVENT_TYPES.SUCCESS, + }); + } + }; + + const errorCb = (error) => { + updateProgress({ showProgress: false }); + notify({ + message: 'Prometheus not connected! : ' + error, + event_type: NOTIFICATION_EVENT_TYPES.ERROR, + details: error.toString(), + }); + }; + + pingPrometheus(successCb, errorCb); +}; + +export const pingPrometheus = (successCb, errorCb) => + dataFetch('/api/telemetry/metrics/ping', { credentials: 'include' }, successCb, errorCb); + +export const fetchPromGrafanaScanData = (ctx) => { + return new Promise((res, rej) => { + dataFetch( + ctxUrl('/api/system/meshsync/grafana', ctx), + { + method: 'GET', + credentials: 'include', + }, + (result) => { + let metricsUrls = { grafana: [], prometheus: [] }; + if (!result) res(metricsUrls); + console.log(); + + if (Array.isArray(result.prometheus)) { + const urls = extractURLFromScanData(result.prometheus); + metricsUrls.prometheus = urls; + } + + if (Array.isArray(result.grafana)) { + const urls = extractURLFromScanData(result.grafana); + metricsUrls.grafana = urls; + } + res(metricsUrls); + }, + (err) => rej('Unable to fetch grafana and prometheus scan data:' + err), + ); + }); +}; + +/** + * extractURLFromScanData scans the ingress urls from the + * mesh scan data and returns an array of the response + * @param {object[]} scannedData + * @returns {string[]} + */ +export const extractURLFromScanData = (data) => { + const result = []; + // scannedData.forEach(data => { + // Add loadbalancer based url + if (Array.isArray(data.status?.loadBalancer?.ingress)) { + data.status.loadBalancer.ingress.forEach((lbdata) => { + let protocol = 'http'; + + // Iterate over ports exposed by the service + if (Array.isArray(data.spec.ports)) { + data.spec.ports.forEach(({ port }) => { + if (port === 443) protocol = 'https'; + + // From kubernetes v1.19 docs + // Hostname is set for load-balancer ingress points that are DNS based (typically AWS load-balancers) + // IP is set for load-balancer ingress points that are IP based (typically GCE or OpenStack load-balancers) + let address = lbdata.ip || lbdata.hostname; + if (address) result.push(`${protocol}://${address}:${port}`); + }); + } + }); + } + + // Add clusterip based url + // As per kubernetes v1.19 api, "None", "" as well as a valid ip is a valid clusterIP + // Looking for valid ipv4 address + if (data.spec.clusterIP?.match(/^((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(\.(?!$)|$)){4}$/g)?.[0]) { + let protocol = 'http'; + if (Array.isArray(data.spec.ports)) { + data.spec.ports.forEach(({ port }) => { + if (port === 443) protocol = 'https'; + result.push(`${protocol}://${data.spec.clusterIP}:${port}`); + }); + } + } + // }) + + return result; +}; + +export const handleGrafanaConfigure = ( + notify, + grafanaURL, + grafanaAPIKey, + updateProgress, + updateGrafanaConfig, +) => { + if ( + grafanaURL === '' || + !( + grafanaURL.toLowerCase().startsWith('http://') || + grafanaURL.toLowerCase().startsWith('https://') + ) + ) { + return; + } + const data = { grafanaURL, grafanaAPIKey }; + const params = Object.keys(data) + .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`) + .join('&'); + + updateProgress({ showProgress: true }); + dataFetch( + '/api/telemetry/metrics/grafana/config', + { + method: 'POST', + credentials: 'include', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + body: params, + }, + (result) => { + updateProgress({ showProgress: false }); + if (typeof result !== 'undefined') { + notify({ + message: 'Grafana was configured!', + event_type: NOTIFICATION_EVENT_TYPES.SUCCESS, + }); + updateGrafanaConfig({ grafana: { grafanaURL, grafanaAPIKey } }); + } + }, + (err) => { + updateProgress({ showProgress: false }); + if (typeof result !== 'undefined') { + notify({ + message: 'Grafana was not configured! :' + err, + event_type: NOTIFICATION_EVENT_TYPES.ERROR, + }); + } + }, + ); +}; + +export const handlePrometheusConfigure = ( + notify, + prometheusURL, + updateProgress, + updatePrometheusConfig, +) => { + if ( + prometheusURL === '' || + !( + prometheusURL.toLowerCase().startsWith('http://') || + prometheusURL.toLowerCase().startsWith('https://') + ) + ) { + return; + } + const data = { prometheusURL }; + const params = Object.keys(data) + .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`) + .join('&'); + + updateProgress({ showProgress: true }); + dataFetch( + '/api/telemetry/metrics/config', + { + method: 'POST', + credentials: 'include', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + body: params, + }, + (result) => { + updateProgress({ showProgress: false }); + if (typeof result !== 'undefined') { + notify({ + message: 'Prometheus was configured!', + event_type: NOTIFICATION_EVENT_TYPES.SUCCESS, + }); + updatePrometheusConfig({ + prometheus: { prometheusURL, selectedPrometheusBoardsConfigs: [] }, + }); + } + }, + (err) => { + updateProgress({ showProgress: false }); + if (typeof result !== 'undefined') { + notify({ + message: 'Prometheus was not configured! :' + err, + event_type: NOTIFICATION_EVENT_TYPES.ERROR, + }); + } + }, + ); +}; + +export const deleteMetricsComponentConfig = (componentName) => (successCb, errorCb) => + dataFetch( + `/api/telemetry/metrics${componentName === 'Grafana' ? '/grafana' : ''}/config`, + { + method: 'DELETE', + credentials: 'include', + }, + successCb, + errorCb, + ); diff --git a/examples/next-14/components/Dashboard/Overview.jsx b/examples/next-14/components/Dashboard/Overview.jsx new file mode 100644 index 00000000..89ecfd52 --- /dev/null +++ b/examples/next-14/components/Dashboard/Overview.jsx @@ -0,0 +1,35 @@ +import { Grid } from '@layer5/sistent'; +import MeshModelGraph from './charts/MeshModelGraph'; +import { styled } from '@mui/material'; +import ConnectionStatsChart from './charts/ConnectionStatsChart'; +import MesheryConfigurationChart from './charts/MesheryConfigurationCharts'; + +const OverviewLayout = styled('div')(({ theme }) => ({ + backgroundColor: theme.palette.mode === 'dark' ? '#202020' : '#FFFFFF', + marginTop: '1rem', +})); + +function Overview() { + return ( + + + + + + + + + + + + + + + + + + + ); +} + +export default Overview; diff --git a/examples/next-14/components/Dashboard/TabPanel.jsx b/examples/next-14/components/Dashboard/TabPanel.jsx new file mode 100644 index 00000000..28af3be7 --- /dev/null +++ b/examples/next-14/components/Dashboard/TabPanel.jsx @@ -0,0 +1,26 @@ +import { Box, Typography } from '@layer5/sistent'; + +// million-ignore +export function TabPanel(props) { + const { children, value, index, ...other } = props; + + return ( + + ); +} + +export default TabPanel; diff --git a/examples/next-14/components/Dashboard/View.jsx b/examples/next-14/components/Dashboard/View.jsx new file mode 100644 index 00000000..54a68c41 --- /dev/null +++ b/examples/next-14/components/Dashboard/View.jsx @@ -0,0 +1,232 @@ +import { ResponsiveDataTable, Typography, Paper } from '@layer5/sistent'; +import { ArrowBack } from '@mui/icons-material'; +import React, { useEffect } from 'react'; +import { ALL_VIEW } from './resources/config'; +import { styled } from '@mui/material/styles'; + +const ParentStyle = styled('div')(() => ({ + position: 'absolute', + top: 0, + right: 0, + bottom: 0, + left: 0, + boxSizing: 'border-box', + display: 'block', + width: '100%', +})); + +const CellStyle = styled('div')(() => ({ + boxSizing: 'border-box', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', +})); + +export function View(props) { + const { setView, resource } = props; + + function RenderDynamicTable(key, value) { + const allKeys = value.reduce((keys, obj) => { + Object.keys(obj).forEach((key) => { + if (!keys.includes(key)) { + keys.push(key); + } + }); + return keys; + }, []); + + const columns = allKeys.map((key) => ({ + name: key, + label: key, + options: { + filter: false, + sort: false, + display: key == 'id' ? false : true, + customBodyRender: function CustomBody(value) { + return ( + <> +
+ + + {typeof value === 'object' && value !== null ? JSON.stringify(value) : value} + + +
+ + ); + }, + }, + })); + + let options = { + filter: false, + download: false, + print: false, + search: false, + viewColumns: false, + selectableRows: 'none', + pagination: false, + responsive: 'standard', + fixedHeader: true, + resizableColumns: true, + }; + + return ( + <> +
+ + {key.toUpperCase()} + + + {}} + columnVisibility={{}} + /> +
+ + ); + } + + const RenderObject = (obj) => { + function ProcessObjForKeyValTable(obj) { + const [processedData, setProcessedData] = React.useState([]); + + function processObj(obj, parentKey = '') { + let rows = []; + let currentGroup = []; + + for (const [key, value] of Object.entries(obj)) { + const currentKey = parentKey ? `${parentKey}.${key}` : key; + + if (Array.isArray(value)) { + // Skip the key if the value is an array + continue; + } else if (typeof value === 'object' && value !== null) { + // For objects, recursively process and add to the current group + currentGroup.push(...processObj(value, currentKey)); + } else { + // For non-objects, add to the rows directly + if (key === 'attribute') { + currentGroup.push(...processObj(JSON.parse(value), currentKey)); + } else if (key === 'id') { + currentGroup.push({ name: currentKey, value: value, hide: true }); + } else { + currentGroup.push({ name: currentKey, value }); + } + } + } + + // Group by the parent key + if (parentKey !== '' && currentGroup.length > 0) { + if (Array.isArray(currentGroup)) { + setProcessedData((prev) => [...prev, { [parentKey]: currentGroup }]); + } + } + + return rows; + } + + useEffect(() => { + processObj(obj); + }, [obj]); + + return ( + <> + {processedData.map((obj, index) => ( +
+ {Object.entries(obj).map(([key, value], innerIndex) => { + const parts = key.split('.'); + const lastPart = parts[parts.length - 1]; + const heading = lastPart.replace('_', ' '); + return value.length == 1 && value[0].hide == true ? null : ( +
+ + {heading} + + +
+ ); + })} +
+ ))} + + ); + } + + const ProcessObjForKeyDataTable = (obj, parentKey = '') => { + let results = []; + for (const [key, value] of Object.entries(obj)) { + const currentKey = parentKey ? `${parentKey}.${key}` : key; + if ( + Array.isArray(value) && + value.length > 0 && + typeof value[0] === 'object' && + value[0] !== null + ) { + results.push(RenderDynamicTable(key, value)); + } + if (typeof value === 'object' && value !== null) { + results.push(ProcessObjForKeyDataTable(value, currentKey)); + } else { + if (key === 'attribute') { + results.push(ProcessObjForKeyDataTable(JSON.parse(value), currentKey)); + } + } + } + return results; + }; + + return ( + <> + {ProcessObjForKeyValTable(obj)} + {ProcessObjForKeyDataTable(obj)} + + ); + }; + + const HeaderComponent = () => { + return ( + <> + + setView(ALL_VIEW)} /> + + + ); + }; + + const ResourceMetrics = () => { + return <>; + }; + + return ( + <> +
+ + +
+ + +
+
+
+ + ); +} + +export default View; diff --git a/examples/next-14/components/Dashboard/charts/ConnectClustersBtn.jsx b/examples/next-14/components/Dashboard/charts/ConnectClustersBtn.jsx new file mode 100644 index 00000000..2ecca104 --- /dev/null +++ b/examples/next-14/components/Dashboard/charts/ConnectClustersBtn.jsx @@ -0,0 +1,16 @@ +import Link from 'next/link'; +import ConnectClustersButton from '@/styles/ConnectClustersButton'; +import { AddIcon } from '@layer5/sistent'; + +export function ConnectClustersBtn() { + return ( + + + + Connect Clusters + + + ); +} + +export default ConnectClustersBtn; diff --git a/examples/next-14/components/Dashboard/charts/ConnectionStatsChart.jsx b/examples/next-14/components/Dashboard/charts/ConnectionStatsChart.jsx new file mode 100644 index 00000000..1e795fb3 --- /dev/null +++ b/examples/next-14/components/Dashboard/charts/ConnectionStatsChart.jsx @@ -0,0 +1,115 @@ +import TextTooltip from '@/components/MesheryMeshInterface/TextTooltip'; +import { useGetAllConnectionStatusQuery } from '@/lib/rtk-query/queries/connection'; +import { Typography, Box, IconButton } from '@layer5/sistent'; +import Link from 'next/link'; +import BBChart from '@/components/BBChart'; +import { donut } from 'billboard.js'; +import { dataToColors } from '@/utils/charts'; +import DashboardSection from '@/styles/DashboardSection'; +import { renderTooltipContent } from '@/components/MesheryMeshInterface/TextTooltip'; +import DashboardInfoOutlined from '@/styles/DashboardInfoOutlined'; +import ConnectClustersBtn from './ConnectClustersBtn'; + +export function ConnectionStatsChart() { + const { data: statusData } = useGetAllConnectionStatusQuery(); + const chartData = + statusData?.connections_status + ?.filter((data) => isValidColumnName(data.status)) + .map((data) => [data.status, data.count]) || []; + + const chartOptions = { + data: { + columns: chartData, + type: donut(), + colors: dataToColors(chartData), + }, + arc: { + cornerRadius: { + ratio: 0.05, + }, + }, + donut: { + title: 'Connections\n by Status', + padAngle: 0.03, + label: { + format: function (value) { + return value; + }, + }, + }, + tooltip: { + format: { + value: function (v) { + return v; + }, + }, + }, + }; + + const url = `https://docs.meshery.io/concepts/logical/connections`; + + return ( + + +
+ + Connections + +
+ + e.stopPropagation()} + > + + + +
+
+ + {chartData.length > 0 ? ( + + ) : ( +
+ + No connections found in your clusters + + +
+ )} +
+
+ + ); +} + +export default ConnectionStatsChart; diff --git a/examples/next-14/components/Dashboard/charts/CreateDesignBtn.jsx b/examples/next-14/components/Dashboard/charts/CreateDesignBtn.jsx new file mode 100644 index 00000000..6f6e30d9 --- /dev/null +++ b/examples/next-14/components/Dashboard/charts/CreateDesignBtn.jsx @@ -0,0 +1,16 @@ +import { AddIcon } from '@layer5/sistent'; +import CreateDesignButton from '@/styles/CreateDesignButton'; +import Link from 'next/link'; + +export function CreateDesignBtn() { + return ( + + + + Create Design + + + ); +} + +export default CreateDesignBtn; diff --git a/examples/next-14/components/Dashboard/charts/MeshModelGraph.jsx b/examples/next-14/components/Dashboard/charts/MeshModelGraph.jsx new file mode 100644 index 00000000..cb9bd8a9 --- /dev/null +++ b/examples/next-14/components/Dashboard/charts/MeshModelGraph.jsx @@ -0,0 +1,244 @@ +import TextTooltip from '@/components/MesheryMeshInterface/TextTooltip'; +import { IconButton, Typography, Grid } from '@layer5/sistent'; +import { useState, useEffect, useMemo, useCallback } from 'react'; +import { + useGetModelCategoriesQuery, + useLazyGetComponentsQuery, + useLazyGetMeshModelsQuery, + useLazyGetModelFromCategoryQuery, + useLazyGetRelationshipsQuery, +} from '@/lib/rtk-query/queries/meshModel'; +import { dataToColors } from '@/utils/charts'; +import BBChart from '@/components/BBChart'; +import { donut, pie } from 'billboard.js'; +import Link from 'next/link'; +import { renderTooltipContent } from '@/components/MesheryMeshInterface/TextTooltip'; +import DashboardSection from '@/styles/DashboardSection'; +import DashboardInfoOutlined from '@/styles/DashboardInfoOutlined'; + +function MeshModelContructs() { + const [getAllModels] = useLazyGetMeshModelsQuery(); + const [getAllComponents] = useLazyGetComponentsQuery(); + const [getAllRelationships] = useLazyGetRelationshipsQuery(); + + // States to hold total counts + const [totalModels, setTotalModels] = useState(0); + const [totalComponents, setTotalComponents] = useState(0); + const [totalRelationships, setTotalRelationships] = useState(0); + + // Fetch data and update state on component mount + const fetchData = useCallback(async () => { + try { + const models = await getAllModels({ + page: 1, + pagesize: 'all', + }); + const components = await getAllComponents({ + page: 1, + pagesize: 'all', + }); + const relationships = await getAllRelationships({ + page: 1, + pagesize: 'all', + }); + + setTotalModels(models.data?.total_count); + setTotalComponents(components.data?.total_count); + setTotalRelationships(relationships.data?.total_count); + } catch (error) { + console.error('Error fetching Mesh Models data:', error); + } + }, [getAllModels, getAllComponents, getAllRelationships]); + + useEffect(() => { + fetchData(); + }, []); + + // Data Cleanup + const data = useMemo(() => { + // TODO: Add Policies + return [ + ['Models', totalModels], + ['Components', totalComponents], + ['Relationships', totalRelationships], + // TODO: Add Policies + ]; + }, [totalModels, totalRelationships, totalComponents]); + + const chartOptions = useMemo( + () => ({ + data: { + columns: data, + type: donut(), + colors: dataToColors(data), + }, + arc: { + cornerRadius: { + ratio: 0.05, + }, + }, + donut: { + title: 'Registered\nCapabilities\nby Type', + padAngle: 0.03, + }, + tooltip: { + format: { + value: function (v) { + return v; + }, + }, + }, + }), + [data], + ); + + const url = `https://docs.meshery.io/concepts/logical/models`; + + return ( + + +
+ + Registry + +
+ + { + e.stopPropagation(); + }} + > + + + +
+
+
+ +
+
+ + ); +} + +function MeshModelCategories() { + const [categoryMap, setCategoryMap] = useState({}); + const { data: categories } = useGetModelCategoriesQuery(); + const [getModelFromCategory] = useLazyGetModelFromCategoryQuery(); + + useEffect(() => { + const fetchModelsForCategories = async () => { + if (categories) { + const updatedCategoryMap = { ...categoryMap }; + for (const category of categories.categories) { + const categoryName = category.name; + if (!updatedCategoryMap[categoryName]) { + const { data: models } = await getModelFromCategory({ + page: 1, + pagesize: 'all', + category: categoryName, + }); + updatedCategoryMap[categoryName] = models?.total_count || 0; + } + } + setCategoryMap(updatedCategoryMap); + } + }; + + fetchModelsForCategories(); + }, [categories]); + + const cleanedData = useMemo( + () => Object.keys(categoryMap).map((key) => [key, categoryMap[key]]), + [categoryMap], + ); + + const chartOptions = useMemo( + () => ({ + data: { + columns: cleanedData, + colors: dataToColors(cleanedData), + type: pie(), + }, + tooltip: { + format: { + value: function (v) { + return `${v} Models`; + }, + }, + }, + legend: { + show: false, + }, + }), + [cleanedData], + ); + + const url = `https://docs.meshery.io/concepts/logical/models`; + return ( + + +
+ + Categories + +
+ + { + e.stopPropagation(); + }} + > + + + +
+
+
+ +
+
+ + ); +} + +export function MeshModelGraph() { + return ( + + + + + + + + + + ); +} + +MeshModelGraph.displayName = 'MeshModelGraph'; +export default MeshModelGraph; diff --git a/examples/next-14/components/Dashboard/charts/MesheryConfigurationCharts.jsx b/examples/next-14/components/Dashboard/charts/MesheryConfigurationCharts.jsx new file mode 100644 index 00000000..9aa40822 --- /dev/null +++ b/examples/next-14/components/Dashboard/charts/MesheryConfigurationCharts.jsx @@ -0,0 +1,133 @@ +import { useEffect, useState } from 'react'; +import { donut } from 'billboard.js'; +import Link from 'next/link'; +import TextTooltip from '@/components/MesheryMeshInterface/TextTooltip'; +import { Box, IconButton, Typography } from '@layer5/sistent'; +import DashboardInfoOutlined from '@/styles/DashboardInfoOutlined'; +import DashboardSection from '@/styles/DashboardSection'; +import BBChart from '@/components/BBChart'; +import { dataToColors } from '@/utils/charts'; +import { useGetPatternsQuery } from '@/lib/rtk-query/queries/design'; +import { useGetFiltersQuery } from '@/lib/rtk-query/queries/filter'; +import { renderTooltipContent } from '@/components/MesheryMeshInterface/TextTooltip'; +import CreateDesignBtn from './CreateDesignBtn'; + +export default function MesheryConfigurationChart() { + // const { notify } = useNotification(); + + const [chartData, setChartData] = useState([]); + + const { data: patternsData, error: patternsError } = useGetPatternsQuery({ + page: 0, + pagesize: 25, + }); + + const { data: filtersData, error: filtersError } = useGetFiltersQuery({ + page: 0, + pagesize: 25, + }); + + useEffect(() => { + if (!patternsError && patternsData?.patterns) { + setChartData((prevData) => [...prevData, ['Designs', patternsData.total_count]]); + } + }, [patternsData, patternsError]); + + useEffect(() => { + if (!filtersError && filtersData?.filters) { + setChartData((prevData) => [...prevData, ['Filters', filtersData.total_count]]); + } + }, [filtersData, filtersError]); + + const chartOptions = { + data: { + columns: chartData, + type: donut(), + colors: dataToColors(chartData), + }, + arc: { + cornerRadius: { + ratio: 0.05, + }, + }, + donut: { + title: 'Content\nby Type', + padAngle: 0.03, + label: { + format: function (value) { + return value; + }, + }, + }, + tooltip: { + format: { + value: function (v) { + return v; + }, + }, + }, + }; + + const url = `https://docs.meshery.io/guides/configuration-management`; + + return ( + + +
+ + Configuration + +
+ + { + e.stopPropagation(); + }} + > + + + +
+
+ + {chartData.length > 0 ? ( + + ) : ( +
+ + No Meshery configuration found + + +
+ )} +
+
+ + ); +} diff --git a/examples/next-14/components/Dashboard/index.jsx b/examples/next-14/components/Dashboard/index.jsx new file mode 100644 index 00000000..e660f679 --- /dev/null +++ b/examples/next-14/components/Dashboard/index.jsx @@ -0,0 +1,173 @@ +import { ResourcesConfig } from './resources/config'; +import TextTooltip from '../MesheryMeshInterface/TextTooltip'; +import { KubernetesIcon } from '@layer5/sistent'; +import MesheryIcon from '../../icons/MesheryIcon'; +import { TabPanel } from './TabPanel'; +import Overview from './Overview'; +import ResourcesSubMenu from './resources/ResourcesSubMenu'; +import ResourcesTable from './resources/ResourcesTable'; +import { withRouter } from 'next/router'; +import { DashboardTab } from '@/styles/DashboardTab'; +import { DashboardTabs } from '@/styles/DashboardTabs'; +import { DashboardLayout } from '@/styles/DashboardLayout'; +import { PaperSquare } from '@/styles/PaperSquare'; +import useDashboardRouter from '@/lib/hooks/useDashboardRouter'; + +const ResourceCategoryTabs = ['Overview', ...Object.keys(ResourcesConfig)]; + +/* +export function Dashboard({ k8sconfig, selectedK8sContexts, updateProgress }) { + const { resourceCategory, changeResourceTab, selectedResource, handleChangeSelectedResource } = + useDashboardRouter(); + + const getResourceCategoryIndex = (resourceCategory) => { + return ResourceCategoryTabs.findIndex((resource) => resource === resourceCategory); + }; + + const getResourceCategory = (index) => { + return ResourceCategoryTabs[index]; + }; + + return ( + + + { + changeResourceTab(getResourceCategory(val)); + }} + > + {ResourceCategoryTabs.map((resource, idx) => { + return ( + + + ) : ( + + ) + } + /> + + ); + })} + + + + + + {Object.keys(ResourcesConfig).map((resource, idx) => ( + + {ResourcesConfig[resource].submenu ? ( + + ) : ( + + )} + + ))} + + ); +} + +export default withRouter(Dashboard); +*/ + +export function Dashboard({ k8sconfig, selectedK8sContexts, updateProgress }) { + const { resourceCategory, changeResourceTab, selectedResource, handleChangeSelectedResource } = + useDashboardRouter(); + + const getResourceCategoryIndex = (resourceCategory) => { + return ResourceCategoryTabs.findIndex((resource) => resource === resourceCategory); + }; + + const getResourceCategory = (index) => { + return ResourceCategoryTabs[index]; + }; + + return ( + + + { + changeResourceTab(getResourceCategory(val)); + }} + > + {ResourceCategoryTabs.map((resource, idx) => { + return ( + + + ) : ( + + ) + } + /> + + ); + })} + + + {Object.keys(ResourcesConfig).map((resource, idx) => ( + + {ResourcesConfig[resource].submenu ? ( + + ) : ( + + )} + + ))} + + ); +} + +export default Dashboard; diff --git a/examples/next-14/components/Dashboard/resources/DefaultTableCell.jsx b/examples/next-14/components/Dashboard/resources/DefaultTableCell.jsx new file mode 100644 index 00000000..a3f83020 --- /dev/null +++ b/examples/next-14/components/Dashboard/resources/DefaultTableCell.jsx @@ -0,0 +1,25 @@ +import { Grid, Tooltip, Typography } from '@layer5/sistent'; +import { TableCell } from '@mui/material'; + +export const DefaultTableCell = ({ columnData, icon, tooltip }) => { + return ( + + + + + {columnData.label} + + {icon ? ( + + + {icon} + + + ) : ( + '' + )} + + + + ); +}; diff --git a/examples/next-14/components/Dashboard/resources/ResourcesSubMenu.jsx b/examples/next-14/components/Dashboard/resources/ResourcesSubMenu.jsx new file mode 100644 index 00000000..63a9a3db --- /dev/null +++ b/examples/next-14/components/Dashboard/resources/ResourcesSubMenu.jsx @@ -0,0 +1,92 @@ +import { Paper, Box, Tab, Tabs, Tooltip } from '@layer5/sistent'; +import TabPanel from '../TabPanel'; +import ResourcesTable from './ResourcesTable'; +import { KubernetesIcon } from '@layer5/sistent'; +import React from 'react'; +import { DashboardLayout } from '@/styles/DashboardLayout'; +import { PaperSquare } from '@/styles/PaperSquare'; +import { DashboardSubMenuTab } from '@/styles/DashboardSubMenuTab'; +import { DashboardTabs } from '@/styles/DashboardTabs'; + +function ResourcesSubMenu(props) { + const { + updateProgress, + k8sConfig, + resource, + selectedK8sContexts, + selectedResource, + handleChangeSelectedResource, + } = props; + + if (!selectedResource) { + handleChangeSelectedResource(Object.keys(resource.tableConfig())[0]); + } + + const TABS = Object.keys(resource.tableConfig()); + + const getResourceCategoryIndex = (resourceCategory) => { + return TABS.findIndex((resource) => resource === resourceCategory); + }; + + const getResourceCategory = (index) => { + return TABS[index]; + }; + + return ( + <> + + + + + handleChangeSelectedResource(getResourceCategory(v))} + variant="scrollable" + scrollButtons="auto" + indicatorColor="primary" + textColor="primary" + centered + > + {TABS.map((key, index) => ( + + + + {resource.tableConfig()[key].name} + + } + /> + + ))} + + + + + {TABS.map((key, index) => ( + + + + ))} + + + ); +} + +export default ResourcesSubMenu; diff --git a/examples/next-14/components/Dashboard/resources/ResourcesTable.jsx b/examples/next-14/components/Dashboard/resources/ResourcesTable.jsx new file mode 100644 index 00000000..95a8fc24 --- /dev/null +++ b/examples/next-14/components/Dashboard/resources/ResourcesTable.jsx @@ -0,0 +1,223 @@ +import { SearchBar, ResponsiveDataTable, useWindowDimensions } from '@layer5/sistent'; +import Slide from '@mui/material/Slide'; +import View from '../View'; +import { useState, useEffect } from 'react'; +import { useSelector } from 'react-redux'; +import { ALL_VIEW } from './config'; +import ToolWrapper from '@/styles/ToolWrapper'; +import CreateButton from '@/styles/CreateButton'; +import SearchAndView from '@/styles/SearchAndView'; +import { useNotification } from '@/lib/hooks/useNotification'; +import { getK8sClusterIdsFromCtxId } from '@/utils/multi-ctx'; + +const ACTION_TYPES = { + FETCH_MESHSYNC_RESOURCES: { + name: 'FETCH_MESHSYNC_RESOURCES', + error_msg: 'Failed to fetch meshsync resources', + }, +}; + +export function ResourcesTable(props) { + const { updateProgress, k8sConfig, resourceConfig, submenu, workloadType, selectedK8sContexts } = + props; + + const { width } = useWindowDimensions(); + const { notify } = useNotification(); + + const connectionMetadataState = useSelector((state) => state.connection.connectionMetadataState); + + const [meshSyncResources, setMeshSyncResources] = useState([]); + const [loading, setLoading] = useState(false); + const [page, setPage] = useState(0); + const [count, setCount] = useState(0); + const [pageSize, setPageSize] = useState(0); + const [search, setSearch] = useState(''); + const [sortOrder, setSortOrder] = useState(''); + const [selectedResource, setSelectedResource] = useState({}); + const [view, setView] = useState(ALL_VIEW); + const [isSearchExpanded, setIsSearchExpanded] = useState(false); + + const switchView = (view, resource) => { + setSelectedResource(resource); + setView(view); + }; + + const tableConfig = submenu + ? resourceConfig(switchView, meshSyncResources, k8sConfig, connectionMetadataState)[ + workloadType + ] + : resourceConfig(switchView, meshSyncResources, k8sConfig, connectionMetadataState); + + const clusterIds = encodeURIComponent( + JSON.stringify(getK8sClusterIdsFromCtxId(selectedK8sContexts, k8sConfig)), + ); + + const getMeshsyncResources = (page, pageSize, search, sortOrder) => { + setLoading(true); + if (!search) search = ''; + if (!sortOrder) sortOrder = ''; + dataFetch( + `/api/system/meshsync/resources?kind=${ + tableConfig.name + }&status=true&spec=true&annotations=true&labels=true&clusterIds=${clusterIds}&page=${page}&pagesize=${pageSize}&search=${encodeURIComponent( + search, + )}&order=${encodeURIComponent(sortOrder)}`, + { + credentials: 'include', + method: 'GET', + }, + (res) => { + setMeshSyncResources(res?.resources || []); + setPage(res?.page || 0); + setCount(res?.total_count || 0); + setPageSize(res?.page_size || 0); + setLoading(false); + }, + handleError(ACTION_TYPES.FETCH_MESHSYNC_RESOURCES), + ); + }; + + const [tableCols, updateCols] = useState(tableConfig.columns); + + useEffect(() => { + updateCols(tableConfig.columns); + if (!loading) { + getMeshsyncResources(page, pageSize, search, sortOrder); + } + }, [page, pageSize, search, sortOrder]); + + const [columnVisibility, setColumnVisibility] = useState(() => { + let showCols = updateVisibleColumns(tableConfig.colViews, width); + // Initialize column visibility based on the original columns' visibility + const initialVisibility = {}; + tableConfig.columns.forEach((col) => { + initialVisibility[col.name] = showCols[col.name]; + }); + return initialVisibility; + }); + + const options = useMemo( + () => ({ + filter: false, + viewColumns: false, + search: false, + responsive: 'standard', + serverSide: true, + selectableRows: false, + count, + rowsPerPage: pageSize, + rowsPerPageOptions: [10, 25, 30], + fixedHeader: true, + page, + print: false, + download: false, + textLabels: { + selectedRows: { + text: `${tableConfig.name}(s) selected`, + }, + }, + enableNestedDataAccess: '.', + onTableChange: (action, tableState) => { + const sortInfo = tableState.announceText ? tableState.announceText.split(' : ') : []; + const columnName = camelcaseToSnakecase(tableConfig.columns[tableState.activeColumn]?.name); + + let order = ''; + if (tableState.activeColumn) { + order = `${columnName} desc`; + } + switch (action) { + case 'changePage': + setPage(tableState.page.toString()); + break; + case 'changeRowsPerPage': + setPageSize(tableState.rowsPerPage.toString()); + break; + case 'sort': + if (sortInfo.length == 2) { + if (sortInfo[1] === 'ascending') { + order = `${columnName} asc`; + } else { + order = `${columnName} desc`; + } + } + if (order !== sortOrder) { + setSortOrder(order); + } + break; + } + }, + }), + [page, pageSize], + ); + + const handleError = (action) => (error) => { + updateProgress({ showProgress: false }); + notify({ + message: `${action.error_msg}: ${error}`, + event_type: EVENT_TYPES.ERROR, + details: error.toString(), + }); + }; + return ( + <> + +
+ +
+
+ + {view === ALL_VIEW && ( +
+ + {/* */} + + { + setSearch(value); + }} + expanded={isSearchExpanded} + setExpanded={setIsSearchExpanded} + placeholder={`Search ${tableConfig.name}...`} + /> + + + + + +
+ )} + + ); +} + +export default ResourcesTable; diff --git a/examples/next-14/components/Dashboard/resources/SortableTableCell.jsx b/examples/next-14/components/Dashboard/resources/SortableTableCell.jsx new file mode 100644 index 00000000..73cef7cc --- /dev/null +++ b/examples/next-14/components/Dashboard/resources/SortableTableCell.jsx @@ -0,0 +1,29 @@ +import { Grid, Tooltip, Typography } from '@layer5/sistent'; +import { TableCell, TableSortLabel } from '@mui/material'; + +export const SortableTableCell = ({ index, columnData, columnMeta, onSort, icon, tooltip }) => { + return ( + + + + +

{columnData.label}

+
+ {icon ? ( + + + {icon} + + + ) : ( + '' + )} +
+ +
+
+ ); +}; diff --git a/examples/next-14/components/Dashboard/resources/config.jsx b/examples/next-14/components/Dashboard/resources/config.jsx new file mode 100644 index 00000000..b36d1f0c --- /dev/null +++ b/examples/next-14/components/Dashboard/resources/config.jsx @@ -0,0 +1,40 @@ +import { ConfigurationTableConfig } from './configuration/ConfigurationTableConfig'; +import { NamespaceTableConfig } from './namespace/NamespaceTableConfig'; +import { NodeTableConfig } from './nodes/NodeTableConfig'; +import { SecurityTypesConfig } from './security/SecurityTypesConfig'; +import { StorageTableConfig } from './storage/StorageTableConfig'; +import { WorkloadTableConfig } from './workloads/WorkloadTableConfig'; + +export const ResourcesConfig = { + Node: { + tableConfig: NodeTableConfig, + submenu: false, + }, + Namespace: { + tableConfig: NamespaceTableConfig, + submenu: false, + }, + Workload: { + tableConfig: WorkloadTableConfig, + submenu: true, + }, + Configuration: { + tableConfig: ConfigurationTableConfig, + submenu: true, + }, + Network: { + // tableConfig: NetWorkTableConfig, + submenu: true, + }, + Security: { + tableConfig: SecurityTypesConfig, + submenu: true, + }, + Storage: { + tableConfig: StorageTableConfig, + submenu: true, + }, +}; + +export const ALL_VIEW = 'all'; +export const SINGLE_VIEW = 'single'; diff --git a/examples/next-14/components/Dashboard/resources/configuration/ConfigurationTableConfig/index.jsx b/examples/next-14/components/Dashboard/resources/configuration/ConfigurationTableConfig/index.jsx new file mode 100644 index 00000000..a302934a --- /dev/null +++ b/examples/next-14/components/Dashboard/resources/configuration/ConfigurationTableConfig/index.jsx @@ -0,0 +1,1608 @@ +import { Title } from '@/components/Dashboard/View'; +import { DefaultTableCell } from '../../DefaultTableCell'; +import { SortableTableCell } from '../../SortableTableCell'; +import { SINGLE_VIEW } from '../../config'; +import useKubernetes from '@/lib/hooks/useKubernetes'; + +export const ConfigurationTableConfig = ( + switchView, + meshSyncResources, + k8sConfig, + connectionMetadataState, +) => { + const ping = useKubernetes(); + return { + ConfigMap: { + name: 'ConfigMap', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + customBodyRender: (value) => , + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return ; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + Secrets: { + name: 'Secrets', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'type', + label: 'Type', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + ResourceQuota: { + name: 'ResourceQuota', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + LimitRange: { + name: 'LimitRange', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + HorizontalPodAutoscaler: { + name: 'HorizontalPodAutoscaler', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['spec.attribute', 'm'], + ['status.attribute', 'm'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Min Replicas', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let minReplicas = attribute?.minReplicas; + return <>{minReplicas}</>; + }, + }, + }, + { + name: 'spec.attribute', + label: 'Max Replicas', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let maxReplicas = attribute?.maxReplicas; + return <>{maxReplicas}</>; + }, + }, + }, + { + name: 'status.attribute', + label: 'Current Replicas', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let currentReplicas = attribute?.currentReplicas; + return <>{currentReplicas}</>; + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + sortThirdClickReset: true, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + VerticalPodAutoscaler: { + name: 'VerticalPodAutoscaler', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + PodDisruptionBudget: { + name: 'PodDisruptionBudget', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['spec.attribute', 'm'], + ['status.attribute', 'm'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Min Available', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let minAvailable = attribute?.minAvailable; + return <>{minAvailable}</>; + }, + }, + }, + { + name: 'spec.attribute', + label: 'Max Available', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let maxAvailable = attribute?.maxAvailable; + return <>{maxAvailable}</>; + }, + }, + }, + { + name: 'status.attribute', + label: 'Current Healthy', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let currentHealthy = attribute?.currentHealthy; + return <>{currentHealthy}</>; + }, + }, + }, + { + name: 'status.attribute', + label: 'Desired Healthy', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let desiredtHealthy = attribute?.desiredtHealthy; + return <>{desiredtHealthy}</>; + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + PriorityClass: { + name: 'PriorityClass', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 'm'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + RuntimeClass: { + name: 'RuntimeClass', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 'm'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + Leases: { + name: 'Leases', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['spec.attribute', 'm'], + ['status.attribute', 'm'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Holder Identity', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let holderIdentity = attribute?.holderIdentity; + return <>{holderIdentity}</>; + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + MutatingWebhookConfiguration: { + name: 'MutatingWebhookConfiguration', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 'm'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + }; +}; diff --git a/examples/next-14/components/Dashboard/resources/namespace/NamespaceTableConfig/index.jsx b/examples/next-14/components/Dashboard/resources/namespace/NamespaceTableConfig/index.jsx new file mode 100644 index 00000000..aac4547b --- /dev/null +++ b/examples/next-14/components/Dashboard/resources/namespace/NamespaceTableConfig/index.jsx @@ -0,0 +1,121 @@ +import useKubernetes from '@/lib/hooks/useKubernetes'; +import { Title } from '@/components/Dashboard/View'; +import { DefaultTableCell } from '../../DefaultTableCell'; +import { SortableTableCell } from '../../SortableTableCell'; +import { SINGLE_VIEW } from '../../config'; + +export const NamespaceTableConfig = ( + switchView, + meshSyncResources, + k8sConfig, + connectionMetadataState, +) => { + const ping = useKubernetes(); + return { + name: 'Namespace', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }; +}; diff --git a/examples/next-14/components/Dashboard/resources/network/NetworkTableConfig/index.jsx b/examples/next-14/components/Dashboard/resources/network/NetworkTableConfig/index.jsx new file mode 100644 index 00000000..a5081ed3 --- /dev/null +++ b/examples/next-14/components/Dashboard/resources/network/NetworkTableConfig/index.jsx @@ -0,0 +1,872 @@ +import useKubernetes from '@/lib/hooks/useKubernetes'; +import { Title } from '@/components/Dashboard/View'; +import { DefaultTableCell } from '../../DefaultTableCell'; +import { SortableTableCell } from '../../SortableTableCell'; +import { SINGLE_VIEW } from '../../config'; + +export const NetWorkTableConfig = ( + switchView, + meshSyncResources, + k8sConfig, + connectionMetadataState, +) => { + const ping = useKubernetes(); + return { + Service: { + name: 'Service', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['spec.attribute', 's'], + ['spec.attribute', 's'], + ['status.attribute', 'na'], + ['spec.attribute', 'm'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Type', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let type = attribute?.type; + return <>{type}</>; + }, + }, + }, + { + name: 'spec.attribute', + label: 'Cluster IP', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let clusterIP = attribute?.clusterIP; + return <>{clusterIP}</>; + }, + }, + }, + { + name: 'status.attribute', + label: 'External IP', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let loadbalancer = attribute?.loadbalancer; + let ingresses = loadbalancer?.ingress; + return ( + <> + {ingresses?.map((ingress, i) => { + return ( + <> + {ingress.hostname} + {i < ingresses.length - 1 && ','} + </> + ); + })} + </> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Ports', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val, tableMeta) { + let attribute = JSON.parse(val); + let ports = attribute?.ports; + + const showViewAll = ports?.length > 1; + return ( + <> + <div style={{ display: 'flex' }}> + {ports?.slice(0, 1).map((p, i) => ( + <div key={i}> + {`${p.port}/${p.targetPort}:${p.protocol}`} + {ports.length > 1 && i === 0 && ','} + </div> + ))} + {showViewAll && ( + <span + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginLeft: '0.5rem', + width: 'max-content', + }} + onClick={() => + switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex]) + } + > + View all + </span> + )} + </div> + </> + ); + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + + return ( + <> + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + </> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + Endpoints: { + name: 'Endpoints', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + Ingress: { + name: 'Ingress', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['spec.attribute', 'm'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Rules', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let ingressRules = attribute?.ingressRule; + return ( + <> + {ingressRules?.map((rule, i) => { + return ( + <> + {`${rule.host}`} + {i < ingressRules.length - 1 && ','} + </> + ); + })} + </> + ); + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <> + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + </> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + IngressClass: { + name: 'IngressClass', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['spec.attribute', 'm'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Controller', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let controller = attribute?.controller; + return <>{controller}</>; + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <> + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + </> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + NetworkPolicy: { + name: 'NetworkPolicy', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['spec.attribute', 'm'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Ports', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let policyTypes = attribute?.policyTypes; + return ( + <> + {policyTypes?.map((policy, i) => { + return ( + <> + {`${policy}`} + {i < policyTypes.length - 1 && ','} + </> + ); + })} + </> + ); + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + }; +}; diff --git a/examples/next-14/components/Dashboard/resources/nodes/NodeTableConfig/index.jsx b/examples/next-14/components/Dashboard/resources/nodes/NodeTableConfig/index.jsx new file mode 100644 index 00000000..45b12b6a --- /dev/null +++ b/examples/next-14/components/Dashboard/resources/nodes/NodeTableConfig/index.jsx @@ -0,0 +1,194 @@ +import useKubernetes from '@/lib/hooks/useKubernetes'; +import { Title } from '@/components/Dashboard/View'; +import { DefaultTableCell } from '../../DefaultTableCell'; +import { SortableTableCell } from '../../SortableTableCell'; +import { SINGLE_VIEW } from '../../config'; + +export const NodeTableConfig = ( + switchView, + meshSyncResources, + k8sConfig, + connectionMetadataState, +) => { + const ping = useKubernetes(); + return { + name: 'Node', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['status.attribute', 'm'], + ['status.attribute', 'm'], + ['cluster_id', 'xs'], + ['status.attribute', 'm'], + ['status.attribute', 'm'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'status.attribute', + label: 'CPU', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let capacity = attribute?.capacity; + let cpu = getResourceStr(resourceParsers['cpu'](capacity?.cpu), 'cpu'); + return <>{cpu}</>; + }, + }, + }, + { + name: 'status.attribute', + label: 'Memory', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let capacity = attribute?.capacity; + let memory = getResourceStr(resourceParsers['memory'](capacity?.memory), 'memory'); + return <>{memory}</>; + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + + return ( + <> + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + </> + ); + }, + }, + }, + { + name: 'status.attribute', + label: 'Internal IP', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let addresses = attribute?.addresses || []; + let internalIP = + addresses?.find((address) => address.type === 'InternalIP')?.address || ''; + return <>{internalIP}</>; + }, + }, + }, + { + name: 'status.attribute', + label: 'External IP', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let addresses = attribute?.addresses || []; + let externalIP = addresses?.find((address) => address.type === 'ExternalIP') + ?.address || <span style={{ display: 'flex', justifyContent: 'center' }}>-</span>; + return <>{externalIP}</>; + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }; +}; diff --git a/examples/next-14/components/Dashboard/resources/security/SecurityTypesConfig/index.jsx b/examples/next-14/components/Dashboard/resources/security/SecurityTypesConfig/index.jsx new file mode 100644 index 00000000..d9c2d314 --- /dev/null +++ b/examples/next-14/components/Dashboard/resources/security/SecurityTypesConfig/index.jsx @@ -0,0 +1,582 @@ +import useKubernetes from '@/lib/hooks/useKubernetes'; +import { Title } from '@/components/Dashboard/View'; +import { DefaultTableCell } from '../../DefaultTableCell'; +import { SortableTableCell } from '../../SortableTableCell'; +import { SINGLE_VIEW } from '../../config'; + +export const SecurityTypesConfig = ( + switchView, + meshSyncResources, + k8sConfig, + connectionMetadataState, +) => { + const ping = useKubernetes(); + return { + ServiceAccount: { + name: 'ServiceAccount', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + ClusterRole: { + name: 'ClusterRole', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + {value ? ( + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + ) : ( + <div style={{ textAlign: 'center' }}>-</div> + )} + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + Role: { + name: 'Role', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + ClusterRoleBinding: { + name: 'ClusterRoleBinding', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + RoleBinding: { + name: 'RoleBinding', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + }; +}; diff --git a/examples/next-14/components/Dashboard/resources/storage/StorageTableConfig/index.jsx b/examples/next-14/components/Dashboard/resources/storage/StorageTableConfig/index.jsx new file mode 100644 index 00000000..223b3cd2 --- /dev/null +++ b/examples/next-14/components/Dashboard/resources/storage/StorageTableConfig/index.jsx @@ -0,0 +1,465 @@ +import useKubernetes from '@/lib/hooks/useKubernetes'; +import { Title } from '@/components/Dashboard/View'; +import { DefaultTableCell } from '../../DefaultTableCell'; +import { SortableTableCell } from '../../SortableTableCell'; +import { SINGLE_VIEW } from '../../config'; + +export const StorageTableConfig = ( + switchView, + meshSyncResources, + k8sConfig, + connectionMetadataState, +) => { + const ping = useKubernetes(); + return { + PersistentVolume: { + name: 'PersistentVolume', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['spec.attribute', 's'], + ['spec.attribute', 's'], + ['status.attribute', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Storage Class', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let storageClassName = attribute?.StorageClassName; + return <>{storageClassName}</>; + }, + }, + }, + { + name: 'spec.attribute', + label: 'Capacity', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let capacity = attribute?.capacity; + let storage = capacity?.storage; + return <>{storage}</>; + }, + }, + }, + { + name: 'status.attribute', + label: 'Status', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let phase = attribute?.phase; + return <>{phase}</>; + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <> + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + </> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + PersistentVolumeClaim: { + name: 'PersistentVolumeClaim', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['spec.attribute', 's'], + ['spec.attribute', 's'], + ['status.attribute', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Storage Class', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let storageClassName = attribute?.StorageClassName; + return <>{storageClassName}</>; + }, + }, + }, + { + name: 'spec.attribute', + label: 'Size', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let resources = attribute?.resources; + let requests = resources?.requests; + let storage = requests?.storage; + return <>{storage}</>; + }, + }, + }, + { + name: 'status.attribute', + label: 'Status', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let phase = attribute?.phase; + return <>{phase}</>; + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + StorageClass: { + name: 'StorageClass', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + }; +}; diff --git a/examples/next-14/components/Dashboard/resources/workloads/WorkloadTableConfig/index.jsx b/examples/next-14/components/Dashboard/resources/workloads/WorkloadTableConfig/index.jsx new file mode 100644 index 00000000..a9703d59 --- /dev/null +++ b/examples/next-14/components/Dashboard/resources/workloads/WorkloadTableConfig/index.jsx @@ -0,0 +1,1350 @@ +import useKubernetes from '@/lib/hooks/useKubernetes'; +import { Title } from '@/components/Dashboard/View'; +import { DefaultTableCell } from '../../DefaultTableCell'; +import { SortableTableCell } from '../../SortableTableCell'; +import { SINGLE_VIEW } from '../../config'; + +export const WorkloadTableConfig = ( + switchView, + meshSyncResources, + k8sConfig, + connectionMetadataState, +) => { + const ping = useKubernetes(); + return { + PODS: { + name: 'Pod', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['status.attribute', 's'], + ['status.attribute', 's'], + ['status.attribute', 'm'], + ['metadata.namespace', 'm'], + ['spec.attribute', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + setCellProps: () => ({ style: { paddingRight: '0px', width: '0%' } }), + setCellHeaderProps: () => ({ style: { paddingRight: '0px' } }), + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + }, + }, + { + name: 'status.attribute', + label: 'Phase', + options: { + sort: false, + setCellProps: () => ({ style: { paddingLeft: '0px' } }), + setCellHeaderProps: () => ({ style: { paddingLeft: '0px' } }), + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let phase = attribute?.phase; + return <>{phase}</>; + }, + }, + }, + { + name: 'status.attribute', + label: 'Host IP', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let hostIP = attribute?.hostIP; + return <>{hostIP}</>; + }, + }, + }, + { + name: 'status.attribute', + label: 'Pod IP', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let podIP = attribute?.podIP; + return <>{podIP}</>; + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Node', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let nodeName = attribute?.nodeName; + return ( + <> + <ResizableCell value={nodeName} /> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <> + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + width="10.5rem" + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + </> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + DEPLOYMENT: { + name: 'Deployment', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['status.attribute', 's'], + ['spec.attribute', 's'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'status.attribute', + label: 'Replicas', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let replicas = attribute?.replicas; + return <>{replicas}</>; + }, + }, + }, + { + name: 'spec.attribute', + label: 'Restart Policy', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let template = attribute?.template; + let spec = template.spec; + let restartPolicy = spec.restartPolicy; + return <>{restartPolicy}</>; + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <> + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={(event) => { + event.preventDefault(); + ping(context.name, context.server, context.connection_id); + }} + /> + </> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + DAEMONSETS: { + name: 'DaemonSet', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['spec.attribute', 's'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Node Selector', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let template = attribute?.template; + let spec = template.spec; + let nodeSelector = spec.nodeSelector; + return <>{JSON.stringify(nodeSelector)}</>; + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + STATEFULSETS: { + name: 'StatefulSet', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['status.attribute', 's'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'status.attribute', + label: 'Replicas', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let replicas = attribute?.replicas; + return <>{replicas}</>; + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + REPLICASETS: { + name: 'ReplicaSet', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['spec.attribute', 's'], + ['status.attribute', 's'], + ['status.attribute', 'm'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Desired Replicas', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let replicas = attribute?.replicas; + return <>{replicas}</>; + }, + }, + }, + { + name: 'status.attribute', + label: 'Current Replicas', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let replicas = attribute?.replicas; + return <>{replicas}</>; + }, + }, + }, + { + name: 'status.attribute', + label: 'Ready Replicas', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let readyReplicas = attribute?.readyReplicas; + return <>{readyReplicas}</>; + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + sortThirdClickReset: true, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + REPLICATIONCONTROLLERS: { + name: 'ReplicationController', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['spec.attribute', 's'], + ['status.attribute', 's'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Desired Replicas', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let replicas = attribute?.replicas; + return <>{replicas}</>; + }, + }, + }, + { + name: 'status.attribute', + label: 'Current Replicas', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let replicas = attribute?.replicas; + return <>{replicas}</>; + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + JOBS: { + name: 'Job', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + CRONJOBS: { + name: 'CronJob', + colViews: [ + ['id', 'na'], + ['metadata.name', 'xs'], + ['apiVersion', 's'], + ['spec.attribute', 's'], + ['spec.attribute', 's'], + ['metadata.namespace', 'm'], + ['cluster_id', 'xs'], + ['metadata.creationTimestamp', 'l'], + ], + columns: [ + { + name: 'id', + label: 'ID', + options: { + display: false, + customBodyRender: (value) => <FormatId id={value} />, + }, + }, + { + name: 'metadata.name', + label: 'Name', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <Title + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + data={ + meshSyncResources[tableMeta.rowIndex] + ? meshSyncResources[tableMeta.rowIndex]?.component_metadata?.metadata + : {} + } + value={value} + /> + ); + }, + }, + }, + { + name: 'apiVersion', + label: 'API version', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + }, + }, + { + name: 'spec.attribute', + label: 'Schedule', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let schedule = attribute?.schedule; + return <>{schedule}</>; + }, + }, + }, + { + name: 'spec.attribute', + label: 'Suspend', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(val) { + let attribute = JSON.parse(val); + let suspend = attribute?.suspend; + return <>{suspend}</>; + }, + }, + }, + { + name: 'metadata.namespace', + label: 'Namespace', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value, tableMeta) { + return ( + <> + <div + style={{ + color: 'inherit', + textDecorationLine: 'underline', + cursor: 'pointer', + marginBottom: '0.5rem', + }} + onClick={() => switchView(SINGLE_VIEW, meshSyncResources[tableMeta.rowIndex])} + > + {value} + </div> + </> + ); + }, + }, + }, + { + name: 'cluster_id', + label: 'Cluster', + options: { + sort: true, + sortThirdClickReset: true, + customHeadRender: function CustomHead({ index, ...column }, sortColumn, columnMeta) { + return ( + <SortableTableCell + index={index} + columnData={column} + columnMeta={columnMeta} + onSort={() => sortColumn(index)} + /> + ); + }, + customBodyRender: function CustomBody(val) { + let context = getK8sContextFromClusterId(val, k8sConfig); + return ( + <TootltipWrappedConnectionChip + title={context.name} + iconSrc={ + connectionMetadataState + ? connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon + : '' + } + handlePing={() => ping(context.name, context.server, context.connection_id)} + /> + ); + }, + }, + }, + { + name: 'metadata.creationTimestamp', + label: 'Age', + options: { + sort: false, + customHeadRender: function CustomHead({ ...column }) { + return <DefaultTableCell columnData={column} />; + }, + customBodyRender: function CustomBody(value) { + let time = timeAgo(value); + return <>{time}</>; + }, + }, + }, + ], + }, + }; +}; diff --git a/examples/next-14/components/Header/K8sContextMenu.jsx b/examples/next-14/components/Header/K8sContextMenu.jsx new file mode 100644 index 00000000..86e198ed --- /dev/null +++ b/examples/next-14/components/Header/K8sContextMenu.jsx @@ -0,0 +1,229 @@ +import { useNotification } from '@/hooks/useNotification'; +import { useState, useEffect } from 'react'; +import { Button, IconButton, ClickAwayListener } from '@layer5/sistent'; +import { Slide } from '@mui/material'; +import Link from 'next/link'; + +function K8sContextMenu({ + classes = {}, + contexts = {}, + activeContexts = [], + show, + updateK8SConfig, + setActiveContexts = () => {}, + searchContexts = () => {}, +}) { + const [anchorEl, setAnchorEl] = useState(false); + const [showFullContextMenu, setShowFullContextMenu] = useState(false); + const [transformProperty, setTransformProperty] = useState(100); + const deleteCtxtRef = createRef(); + const { notify } = useNotification(); + const ping = useKubernetes(); + const meshsyncControllerState = useSelector((state) => state.get('controllerState')); + const connectionMetadataState = useSelector((state) => state.get('connectionMetadataState')); + + const { getControllerStatesByContexID } = useControllerStatus(meshsyncControllerState); + const styleSlider = { + position: 'absolute', + left: '-7rem', + zIndex: '-1', + bottom: showFullContextMenu ? '-55%' : '-110%', + transform: showFullContextMenu ? `translateY(${transformProperty}%)` : 'translateY(0)', + }; + + const ctxStyle = { + ...disabledStyle, + marginRight: '0.5rem', + }; + + const handleKubernetesDelete = (name, connectionID) => async () => { + let responseOfDeleteK8sCtx = await deleteCtxtRef.current.show({ + title: `Delete ${name} context ?`, + subtitle: `Are you sure you want to delete ${name} cluster from Meshery?`, + options: ['CONFIRM', 'CANCEL'], + variant: PROMPT_VARIANTS.DANGER, + }); + if (responseOfDeleteK8sCtx === 'CONFIRM') { + const successCallback = async () => { + const updatedConfig = await loadActiveK8sContexts(); + if (Array.isArray(updatedConfig)) { + updateK8SConfig({ k8sConfig: updatedConfig }); + } + }; + deleteKubernetesConfig( + successHandlerGenerator(notify, `Kubernetes config removed for ${name}`, successCallback), + errorHandlerGenerator(notify, `Not able to remove config for ${name}`), + connectionID, + ); + } + }; + + let open = Boolean(anchorEl); + if (showFullContextMenu) { + open = showFullContextMenu; + } + + useEffect(() => { + setTransformProperty( + (prev) => prev + (contexts.total_count ? contexts.total_count * 3.125 : 0), + ); + }, []); + + return ( + <> + <div style={show ? cursorNotAllowed : {}}> + <IconButton + aria-label="contexts" + className="k8s-icon-button" + onClick={(e) => { + e.preventDefault(); + setShowFullContextMenu((prev) => !prev); + }} + onMouseOver={(e) => { + e.preventDefault(); + setAnchorEl(true); + }} + onMouseLeave={(e) => { + e.preventDefault(); + setAnchorEl(false); + }} + aria-owns={open ? 'menu-list-grow' : undefined} + aria-haspopup="true" + style={show ? ctxStyle : { marginRight: '0.5rem' }} + > + <div className={classes.cbadgeContainer}> + <img + className="k8s-image" + src={ + connectionMetadataState + ? `/${connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon}` + : '' + } + width="24px" + height="24px" + // style={{ zIndex: '2' }} + /> + <div className={classes.cbadge}>{contexts?.total_count || 0}</div> + </div> + </IconButton> + </div> + + <Slide + direction="down" + style={styleSlider} + timeout={400} + in={open} + mountOnEnter + unmountOnExit + > + <div> + <ClickAwayListener + onClickAway={(e) => { + if ( + typeof e.target.className == 'string' && + !e.target.className?.includes('cbadge') && + e.target?.className != 'k8s-image' && + !e.target.className.includes('k8s-icon-button') + ) { + setAnchorEl(false); + setShowFullContextMenu(false); + } + }} + > + <Paper className={classes.cMenuContainer}> + <div> + <TextField + id="search-ctx" + label="Search" + size="small" + variant="outlined" + onChange={(ev) => searchContexts(ev.target.value)} + style={{ + width: '100%', + backgroundColor: 'rgba(102, 102, 102, 0.12)', + margin: '1px 0px', + }} + InputProps={{ + endAdornment: <Search className={classes.searchIcon} style={iconMedium} />, + }} + /> + </div> + <div> + {contexts?.total_count ? ( + <> + <Checkbox + checked={activeContexts.includes('all')} + onChange={() => setActiveContexts('all')} + color="primary" + /> + <span style={{ fontWeight: 'bolder' }}>select all</span> + </> + ) : ( + <Link href="/settings"> + <Button + type="submit" + variant="contained" + color="primary" + size="large" + style={{ margin: '0.5rem 0.5rem', whiteSpace: 'nowrap' }} + > + <AddIcon className={classes.AddIcon} style={iconMedium} /> + Connect Clusters + </Button> + </Link> + )} + {contexts?.contexts?.map((ctx, idx) => { + const { operatorState, meshSyncState, natsState } = getControllerStatesByContexID( + ctx.id, + ); + + return ( + <div key={`${ctx.uniqueID}-${idx}`} id={ctx.id} className={classes.chip}> + <CustomTextTooltip + backgroundColor={CHARCOAL} + title={`Server: ${ctx.server}, Operator: ${formatToTitleCase( + operatorState, + )}, MeshSync: ${formatToTitleCase( + meshSyncState, + )}, Broker: ${formatToTitleCase(natsState)}`} + > + <div + style={{ + display: 'flex', + justifyContent: 'flex-start', + alignItems: 'center', + }} + > + <Checkbox + checked={activeContexts.includes(ctx.id)} + onChange={() => setActiveContexts(ctx.id)} + color="primary" + /> + <_ConnectionChip + title={ctx?.name} + onDelete={handleKubernetesDelete(ctx.name, ctx.connection_id)} + handlePing={() => ping(ctx.name, ctx.server, ctx.connection_id)} + iconSrc={ + connectionMetadataState + ? `/${connectionMetadataState[CONNECTION_KINDS.KUBERNETES]?.icon}` + : '' + } // chnage to use connection def + status={operatorState} + /> + </div> + </CustomTextTooltip> + </div> + ); + })} + </div> + </Paper> + </ClickAwayListener> + </div> + </Slide> + + <PromptComponent ref={deleteCtxtRef} /> + </> + ); +} + +export default K8sContextMenu; diff --git a/examples/next-14/components/Header/index.jsx b/examples/next-14/components/Header/index.jsx new file mode 100644 index 00000000..4bcc936b --- /dev/null +++ b/examples/next-14/components/Header/index.jsx @@ -0,0 +1,196 @@ +import React, { useState } from 'react'; +import { AppBar, Grid, Toolbar, Typography } from '@layer5/sistent'; +import K8sContextMenu from './K8sContextMenu'; +import { withNotify } from '@/hooks/useNotification'; +import { connect } from 'react-redux'; + +const iconMedium = { + // your styles for icon medium +}; + +const cursorNotAllowed = { + // your styles for cursor not allowed +}; + +const disabledStyle = { + // your styles for disabled style +}; + +function Header({ + title, + onDrawerToggle, + isBeta, + theme, + themeSetter, + onDrawerCollapse, + capabilityregistryObj, + updateCapabilities, +}) { + const [collaboratorExt, setCollaboratorExt] = useState(null); + + useEffect(() => { + const fetchData = async () => { + try { + const result = await dataFetch('/api/provider/capabilities', { + method: 'GET', + credentials: 'include', + }); + const capabilitiesRegistryObj = new CapabilitiesRegistry(result); + setCollaboratorExt( + ExtensionPointSchemaValidator('collaborator')(result?.extensions?.collaborator), + ); + updateCapabilities({ capabilitiesRegistry: result }); + } catch (err) { + console.error(err); + } + }; + + fetchData(); + + return () => { + // cleanup + }; + }, [updateCapabilities]); + + return ( + <React.Fragment> + {/* LoadTheme component goes here */} + <AppBar + color="primary" + position="sticky" + // elevation={1} + className={onDrawerCollapse ? classes.appBarOnDrawerClosed : classes.appBarOnDrawerOpen} + > + <Toolbar + className={onDrawerCollapse ? classes.toolbarOnDrawerClosed : classes.toolbarOnDrawerOpen} + > + <Grid container alignItems="center"> + <Hidden smUp> + <Grid item> + <IconButton + color="inherit" + aria-label="Open drawer" + onClick={onDrawerToggle} + className={classes.menuButton} + > + <MenuIcon className={classes.headerIcons} style={iconMedium} /> + </IconButton> + </Grid> + </Hidden> + <Grid item xs container alignItems="center" className={classes.pageTitleWrapper}> + <Typography + color="inherit" + variant="h5" + className={classes.pageTitle} + data-cy="headerPageTitle" + > + {title} + {isBeta ? <sup className={classes.betaBadge}>BETA</sup> : ''} + </Typography> + </Grid> + <Grid + item + className={classes.userContainer} + style={{ position: 'relative', right: '-27px' }} + > + {/* According to the capabilities load the component */} + {collaboratorExt && ( + <ExtensionSandbox + type="collaborator" + Extension={(url) => RemoteComponent({ url, loaderType })} + capabilitiesRegistry={capabilityregistryObj} + /> + )} + <div className={classes.userSpan} style={{ position: 'relative' }}> + <K8sContextMenu + classes={classes} + // other props go here + /> + </div> + + <div + data-test="settings-button" + style={ + !capabilityregistryObj?.isHeaderComponentEnabled([SETTINGS]) + ? cursorNotAllowed + : {} + } + > + <Link href="/settings"> + <IconButton + style={ + !capabilityregistryObj?.isHeaderComponentEnabled([SETTINGS]) + ? disabledStyle + : {} + } + color="inherit" + > + <OutlinedSettingsIcon + fill={WHITE} + className={ + classes.headerIcons + + ' ' + + (title === 'Settings' ? classes.itemActiveItem : '') + } + style={iconMedium} + /> + </IconButton> + </Link> + </div> + + <div data-test="notification-button"> + <NotificationDrawerButton /> + </div> + <span className={classes.userSpan}> + <User + classes={classes} + theme={theme} + themeSetter={themeSetter} + color="inherit" + iconButtonClassName={classes.iconButtonAvatar} + avatarClassName={classes.avatar} + // other props go here + /> + </span> + {/* <div className="dark-theme-toggle"> + <input id="toggle" className="toggle" type="checkbox" onChange={themeToggler} checked={!themeToggle} /> + </div> */} + </Grid> + </Grid> + </Toolbar> + </AppBar> + </React.Fragment> + ); +} + +Header.propTypes = { + classes: PropTypes.object.isRequired, + onDrawerToggle: PropTypes.func.isRequired, + title: PropTypes.string.isRequired, + isBeta: PropTypes.bool.isRequired, + theme: PropTypes.object.isRequired, + themeSetter: PropTypes.func.isRequired, + onDrawerCollapse: PropTypes.bool.isRequired, + capabilityregistryObj: PropTypes.object.isRequired, + updateCapabilities: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => { + return { + title: state.get('page').get('title'), + isBeta: state.get('page').get('isBeta'), + selectedK8sContexts: state.get('selectedK8sContexts'), + k8sconfig: state.get('k8sConfig'), + operatorState: state.get('operatorState'), + meshSyncState: state.get('meshSyncState'), + capabilitiesRegistry: state.get('capabilitiesRegistry'), + }; +}; + +const mapDispatchToProps = (dispatch) => ({ + updateK8SConfig: bindActionCreators(updateK8SConfig, dispatch), + updateProgress: bindActionCreators(updateProgress, dispatch), + updateCapabilities: bindActionCreators(updateCapabilities, dispatch), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(withNotify(Header)); diff --git a/examples/next-14/components/Header/loadActiveK8sContexts.jsx b/examples/next-14/components/Header/loadActiveK8sContexts.jsx new file mode 100644 index 00000000..fbb659f1 --- /dev/null +++ b/examples/next-14/components/Header/loadActiveK8sContexts.jsx @@ -0,0 +1,14 @@ +import { promisifiedDataFetch } from '@/utils/dataFetch'; + +export async function loadActiveK8sContexts() { + try { + const res = await promisifiedDataFetch('/api/system/sync'); + if (res?.k8sConfig) { + return res.k8sConfig; + } else { + throw new Error('No kubernetes configurations found'); + } + } catch (e) { + console.error('An error occurred while loading k8sconfig', e); + } +} diff --git a/examples/next-14/components/Lifecycle/EmptyState/CurvedArrowIcon.jsx b/examples/next-14/components/Lifecycle/EmptyState/CurvedArrowIcon.jsx new file mode 100644 index 00000000..5e0dd47a --- /dev/null +++ b/examples/next-14/components/Lifecycle/EmptyState/CurvedArrowIcon.jsx @@ -0,0 +1,19 @@ +export const CurvedArrowIcon = ({ width = '4.5rem', height = '4.5rem', props }) => { + return ( + <svg + xmlns="http://www.w3.org/2000/svg" + width={width} + height={height} + viewBox="0 0 50 73" + fill="none" + {...props} + > + <path + d="M11.6836 8.50538L10.1837 8.49039L11.6836 8.50538ZM12.8198 0.949356C12.2399 0.357744 11.2902 0.348252 10.6986 0.928158L1.05775 10.3782C0.466141 10.9581 0.456653 11.9078 1.03656 12.4994C1.61646 13.0911 2.56616 13.1005 3.15777 12.5206L11.7274 4.12057L20.1275 12.6902C20.7074 13.2818 21.6571 13.2913 22.2487 12.7114C22.8403 12.1315 22.8498 11.1818 22.2699 10.5902L12.8198 0.949356ZM13.1835 8.52037L13.2485 2.01435L10.2487 1.98437L10.1837 8.49039L13.1835 8.52037ZM49.3092 70.0002C26.8233 57.7658 12.9277 34.1179 13.1835 8.52037L10.1837 8.49039C9.91679 35.1976 24.4147 59.8706 47.8755 72.6354L49.3092 70.0002Z" + fill="#808080" + /> + </svg> + ); +}; + +export default CurvedArrowIcon; diff --git a/examples/next-14/components/Lifecycle/EmptyState/index.jsx b/examples/next-14/components/Lifecycle/EmptyState/index.jsx new file mode 100644 index 00000000..3f28ee22 --- /dev/null +++ b/examples/next-14/components/Lifecycle/EmptyState/index.jsx @@ -0,0 +1,62 @@ +import { Grid, Typography } from '@layer5/sistent'; +import React from 'react'; +import CurvedArrowIcon from './CurvedArrowIcon'; + +/** + * Wrapper component for flip cards. + * + * @param {Object} props - The component props. + * @param {Object} props.message - The message of the empty state. + * @param {string} props.icon - The icon of the empty state. + * + */ + +const EmptyState = ({ icon, message, pointerLabel }) => { + return ( + <div + style={{ + textAlign: 'center', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'center', + minHeight: '50vh', + }} + > + <Grid style={{ display: 'flex', width: '100%', padding: '0 40px' }}> + <CurvedArrowIcon /> + <Typography + style={{ + fontSize: 24, + color: '#808080', + px: 5, + py: 2, + lineHeight: 1.5, + letterSpacing: '0.15px', + display: 'flex', + alignItems: 'flex-end', + marginBottom: -32, + }} + > + {pointerLabel} + </Typography> + </Grid> + <Grid style={{ marginTop: '120px' }}> + {icon} + <Typography + style={{ + fontSize: 24, + color: '#808080', + px: 5, + py: 2, + lineHeight: 1, + }} + > + {message} + </Typography> + </Grid> + </div> + ); +}; + +export default EmptyState; diff --git a/examples/next-14/components/Lifecycle/Enviroments/EnvironmentCard.jsx b/examples/next-14/components/Lifecycle/Enviroments/EnvironmentCard.jsx new file mode 100644 index 00000000..e545d5a7 --- /dev/null +++ b/examples/next-14/components/Lifecycle/Enviroments/EnvironmentCard.jsx @@ -0,0 +1,230 @@ +import React from 'react'; +import { Button, Card, Grid, Typography, Box, Checkbox } from '@layer5/sistent'; +import { SyncAlt as SyncAltIcon } from '@mui/icons-material'; +import { Delete, Edit } from '@mui/icons-material'; + +export const formattoLongDate = (date) => { + return new Date(date).toLocaleDateString('en-US', { + day: 'numeric', + month: 'long', + year: 'numeric', + }); +}; + +export const TransferButton = ({ title, count, onAssign, classes }) => { + return ( + <Button variant="contained" color="primary" className={classes.popupButton} onClick={onAssign}> + <Grid> + <Typography className={classes.tabCount}>{count}</Typography> + <Typography className={classes.tabTitle}>{title}</Typography> + <SyncAltIcon style={{ position: 'absolute', top: '10px', right: '10px' }} /> + </Grid> + </Button> + ); +}; + +/** + * Renders a environment card component. + * + * @param {Object} props - The component props. + * @param {Object} props.environmentDetails - The details of the environment. + * @param {string} props.environmentDetails.name - The name of the environment. + * @param {string} props.environmentDetails.description - The description of the environment. + * @param {Function} props.onDelete - Function to delete the environment. + * @param {Function} props.onEdit - Function to edit the environment. + * @param {Function} props.onSelect - Function to select environment for bulk actions. + * @param {Function} props.onAssignConnection - Function to open connection assignment modal open. + * @param {Array} props.selectedEnvironments - Selected environments list for delete. + * @param {String} props.classes - Styles property names for classes. + * + */ + +const EnvironmentCard = ({ + environmentDetails, + selectedEnvironments, + onDelete, + onEdit, + onSelect, + onAssignConnection, + classes, +}) => { + const { data: environmentConnections } = useGetEnvironmentConnectionsQuery( + { + environmentId: environmentDetails.id, + }, + { skip: !environmentDetails.id }, + ); + const environmentConnectionsCount = environmentConnections?.total_count || 0; + + const deleted = environmentDetails.deleted_at.Valid; + + return ( + <FlipCard + disableFlip={ + selectedEnvironments?.filter((id) => id == environmentDetails.id).length === 1 + ? true + : false + } + frontComponents={ + <Card + className={classes.cardWrapper} + style={{ + minHeight: '320px', + height: '320px', + }} + > + <Grid style={{ display: 'flex', flexDirection: 'row', pb: 1 }}> + <Typography + className={classes.listItem} + variant="body2" + onClick={(e) => e.stopPropagation()} + > + {environmentDetails?.name} + </Typography> + </Grid> + <Grid + style={{ + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + }} + > + <Grid xs={12} sm={9} md={12} style={{ display: 'flex', justifyContent: 'flex-start' }}> + {environmentDetails.description ? ( + <Typography + className={classNames(classes.emptyDescription, classes.descriptionLabel)} + onClick={(e) => e.stopPropagation()} + style={{ marginBottom: { xs: 2, sm: 0 }, paddingRight: { sm: 2, lg: 0 } }} + > + {environmentDetails.description} + </Typography> + ) : ( + <Typography + className={classes.emptyDescription} + onClick={(e) => e.stopPropagation()} + style={{ color: 'rgba(122,132,142,1)' }} + > + No description + </Typography> + )} + </Grid> + <Grid + xs={12} + style={{ + paddingTop: '15px', + display: 'flex', + alignItems: 'flex-end', + justifyContent: 'flex-end', + gap: '10px', + }} + > + <Box className={classes.allocationButton} onClick={(e) => e.stopPropagation()}> + <TransferButton + title="Assigned Connections" + count={environmentConnectionsCount} + onAssign={onAssignConnection} + classes={classes} + /> + </Box> + {/* temporary disable workspace allocation button */} + {false && ( + <Box className={classes.allocationButton} onClick={(e) => e.stopPropagation()}> + <TransferButton + title="Assigned Workspaces" + count={ + environmentDetails.workspaces ? environmentDetails.workspaces?.length : 0 + } + onAssign={onAssignConnection} + classes={classes} + /> + </Box> + )} + </Grid> + </Grid> + </Card> + } + backComponents={ + <Card + elevation={2} + className={classes.cardWrapper} + style={{ + minHeight: '320px', + background: 'linear-gradient(180deg, #007366 0%, #000 100%)', + }} + > + <Grid xs={12} style={{ display: 'flex', flexDirection: 'row', height: '40px' }}> + <Grid xs={6} style={{ display: 'flex', alignItems: 'flex-start' }}> + <Checkbox + className={classes.bulkSelectCheckbox} + onClick={(e) => e.stopPropagation()} + onChange={onSelect} + disabled={deleted ? true : false} + /> + <Typography + className={classes.cardTitle} + style={{ color: 'white' }} + variant="body2" + onClick={(e) => e.stopPropagation()} + > + {environmentDetails?.name} + </Typography> + </Grid> + <Grid + xs={6} + style={{ + display: 'flex', + alignItems: 'flex-start', + justifyContent: 'flex-end', + }} + > + <Button + className={classes.iconButton} + onClick={onEdit} + disabled={ + selectedEnvironments?.filter((id) => id == environmentDetails.id).length === 1 + ? true + : !CAN(keys.EDIT_ENVIRONMENT.action, keys.EDIT_ENVIRONMENT.subject) + } + > + <Edit style={{ color: 'white', margin: '0 2px' }} /> + </Button> + <Button + className={classes.iconButton} + onClick={onDelete} + disabled={ + selectedEnvironments?.filter((id) => id == environmentDetails.id).length === 1 + ? true + : !CAN(keys.DELETE_ENVIRONMENT.action, keys.DELETE_ENVIRONMENT.subject) + } + > + <Delete style={{ color: 'white', margin: '0 2px' }} /> + </Button> + </Grid> + </Grid> + <Grid style={{ display: 'flex', flexDirection: 'row', color: 'white' }}> + <Grid xs={6} style={{ textAlign: 'left' }}> + <Typography + className={classes.dateLabel} + variant="span" + onClick={(e) => e.stopPropagation()} + > + Updated At: {formattoLongDate(environmentDetails?.updated_at)} + </Typography> + </Grid> + <Grid xs={6} style={{ textAlign: 'left' }}> + <Typography + className={classes.dateLabel} + variant="span" + onClick={(e) => e.stopPropagation()} + > + Created At: {formattoLongDate(environmentDetails?.created_at)} + </Typography> + </Grid> + </Grid> + </Card> + } + /> + ); +}; + +export default EnvironmentCard; diff --git a/examples/next-14/components/Lifecycle/Enviroments/index.jsx b/examples/next-14/components/Lifecycle/Enviroments/index.jsx new file mode 100644 index 00000000..5bd2ef90 --- /dev/null +++ b/examples/next-14/components/Lifecycle/Enviroments/index.jsx @@ -0,0 +1,577 @@ +import { useState, useEffect } from 'react'; +import { + useAddConnectionToEnvironmentMutation, + useRemoveConnectionFromEnvironmentMutation, + useGetEnvironmentConnectionsQuery, + useGetEnvironmentsQuery, + useCreateEnvironmentMutation, + useUpdateEnvironmentMutation, + useDeleteEnvironmentMutation, +} from '@/lib/rtk-query/queries/environments'; +import { useNotification } from '@/hooks/useNotification'; +import EnvironmentCard from './EnvironmentCard'; +import { EnvironmentIcon, Box, SearchBar, Grid, Typography, Button } from '@layer5/sistent'; +import { Delete, ChevronLeft, ChevronRight } from '@mui/icons-material'; + +function Environments({ organization }) { + const [environmentModal, setEnvironmentModal] = useState({ + open: false, + schema: {}, + }); + const [actionType, setActionType] = useState(''); + const [initialData, setInitialData] = useState({}); + const [editEnvId, setEditEnvId] = useState(''); + const [page, setPage] = useState(0); + const [search, setSearch] = useState(''); + const [orgId, setOrgId] = useState(''); + const [selectedEnvironments, setSelectedEnvironments] = useState([]); + const [assignConnectionModal, setAssignConnectionModal] = useState(false); + const [connectionAssignEnv, setConnectionAssignEnv] = useState({}); + const [assignedConnections, setAssignedConnections] = useState([]); + const [connectionsData, setConnectionsData] = useState([]); + const [connectionsPage, setConnectionsPage] = useState(0); + const [environmentConnectionsData, setEnvironmentConnectionsData] = useState([]); + const [connectionsOfEnvironmentPage, setConnectionsOfEnvironmentPage] = useState(0); + const [skip, setSkip] = useState(true); + const [isSearchExpanded, setIsSearchExpanded] = useState(false); + const [disableTranferButton, setDisableTranferButton] = useState(true); + + const pageSize = 10; + const connectionPageSize = 25; + + const modalRef = useRef(null); + const { notify } = useNotification(); + const StyleClass = useStyles(); + + const { + data: environmentsData, + // isLoading: isEnvironmentsLoading, + isError: isEnvironmentsError, + error: environmentsError, + } = useGetEnvironmentsQuery( + { + search: search, + page: page, + pagesize: pageSize, + orgId: orgId, + }, + { + skip: !orgId ? true : false, + }, + ); + + const [createEnvironment] = useCreateEnvironmentMutation(); + + const [updateEnvironment] = useUpdateEnvironmentMutation(); + + const [deleteEnvironment] = useDeleteEnvironmentMutation(); + + const { + data: connections, + isError: isConnectionsError, + error: connectionsError, + } = useGetEnvironmentConnectionsQuery( + { + environmentId: connectionAssignEnv.id, + page: connectionsData.length === 0 ? 0 : connectionsPage, + pagesize: connectionPageSize, + filter: '{"assigned":false}', + }, + { + skip, + }, + ); + + const { + data: environmentConnections, + isError: isEnvironmentConnectionsError, + error: environmentConnectionsError, + } = useGetEnvironmentConnectionsQuery( + { + environmentId: connectionAssignEnv.id, + page: environmentConnectionsData.length === 0 ? 0 : connectionsOfEnvironmentPage, + pagesize: connectionPageSize, + }, + { + skip, + }, + ); + + const { data: schemaEnvironment } = useGetSchemaQuery({ + schemaName: 'environment', + }); + + const environments = environmentsData?.environments ? environmentsData.environments : []; + const connectionsDataRtk = connections?.connections ? connections.connections : []; + const environmentConnectionsDataRtk = environmentConnections?.connections + ? environmentConnections.connections + : []; + + useEffect(() => { + setConnectionsData((prevData) => [...prevData, ...connectionsDataRtk]); + }, [connections]); + + useEffect(() => { + setEnvironmentConnectionsData((prevData) => [...prevData, ...environmentConnectionsDataRtk]); + }, [environmentConnections]); + + useEffect(() => { + if (isEnvironmentsError) { + handleError(`Environments Fetching Error: ${environmentsError?.data}`); + } + if (isEnvironmentConnectionsError) { + handleError( + `Connections of a Environment fetching Error: ${environmentConnectionsError?.data}`, + ); + } + if (isConnectionsError) { + handleError(`Connections fetching Error: ${connectionsError?.data}`); + } + }, [ + isEnvironmentsError, + isEnvironmentConnectionsError, + isConnectionsError, + environmentsError, + environmentConnectionsError, + connectionsError, + handleError, + ]); + + const handleError = (action) => (error) => { + updateProgress({ showProgress: false }); + notify({ + message: `${action.error_msg}: ${error}`, + event_type: EVENT_TYPES.ERROR, + details: error.toString(), + }); + }; + + const handleSuccess = (msg) => { + updateProgress({ showProgress: false }); + notify({ + message: msg, + event_type: EVENT_TYPES.SUCCESS, + }); + }; + + useEffect(() => { + setOrgId(organization?.id); + }, [organization]); + + const fetchSchema = () => { + const updatedSchema = { ...schemaEnvironment }; + updatedSchema.rjsfSchema?.properties?.organization && + ((updatedSchema.rjsfSchema = { + ...updatedSchema.rjsfSchema, + properties: { + ...updatedSchema.rjsfSchema.properties, + organization: { + ...updatedSchema.rjsfSchema.properties.organization, + enum: [organization?.id], + enumNames: [organization?.name], + }, + }, + }), + (updatedSchema.uiSchema = { + ...updatedSchema.uiSchema, + organization: { + ...updatedSchema.uiSchema.organization, + ['ui:widget']: 'hidden', + }, + })); + setEnvironmentModal({ + open: true, + schema: updatedSchema, + }); + }; + + const [addConnectionToEnvironmentMutator] = useAddConnectionToEnvironmentMutation(); + const [removeConnectionFromEnvMutator] = useRemoveConnectionFromEnvironmentMutation(); + + const addConnectionToEnvironment = async (environmentId, connectionId) => { + addConnectionToEnvironmentMutator({ environmentId, connectionId }); + }; + + const removeConnectionFromEnvironment = (environmentId, connectionId) => { + removeConnectionFromEnvMutator({ environmentId, connectionId }); + }; + + const handleEnvironmentModalOpen = (e, actionType, envObject) => { + e.stopPropagation(); + if (actionType === ACTION_TYPES.EDIT) { + setActionType(ACTION_TYPES.EDIT); + setInitialData({ + name: envObject.name, + description: envObject.description, + organization: envObject.organization_id, + }); + setEditEnvId(envObject.id); + } else { + setActionType(ACTION_TYPES.CREATE); + setInitialData({ + name: undefined, + description: '', + organization: orgId, + }); + setEditEnvId(''); + } + fetchSchema(); + }; + + const handleEnvironmentModalClose = () => { + setEnvironmentModal({ + open: false, + schema: {}, + }); + setActionType(''); + }; + + const handleCreateEnvironment = ({ organization, name, description }) => { + createEnvironment({ + environmentPayload: { + name: name, + description: description, + organization_id: organization, + }, + }) + .unwrap() + .then(handleSuccess(`Environment "${name}" created `)) + .catch((error) => handleError(`Environment Create Error: ${error?.data}`)); + handleEnvironmentModalClose(); + }; + + const handleEditEnvironment = ({ name, description }) => { + updateEnvironment({ + environmentId: editEnvId, + environmentPayload: { + name: name, + description: description, + organization_id: initialData.organization, + }, + }) + .unwrap() + .then(handleSuccess(`Environment "${name}" updated`)) + .catch((error) => handleError(`Environment Update Error: ${error?.data}`)); + handleEnvironmentModalClose(); + }; + + const handleDeleteEnvironmentConfirm = async (e, environment) => { + e.stopPropagation(); + let response = await modalRef.current.show({ + title: `Delete "${environment.name}" environment?`, + subtitle: deleteEnvironmentModalContent(environment.name), + options: ['DELETE', 'CANCEL'], + showInfoIcon: `Deleting an environment does not delete any resources (e.g. connections) currently contained with the environment. Resources that belong to others environments will continue to belong to those other environments. + + Learn more about the behavior of [lifecycle of environments and their resources](https://docs.meshery.io/concepts/logical/environments) in Meshery Docs.`, + variant: PROMPT_VARIANTS.DANGER, + }); + if (response === 'DELETE') { + handleDeleteEnvironment(environment.id); + } + }; + + const handleDeleteEnvironment = (id) => { + deleteEnvironment({ + environmentId: id, + }) + .unwrap() + .then(handleSuccess(`Environment deleted`)) + .catch((error) => handleError(`Environment Delete Error: ${error?.data}`)); + }; + + const deleteEnvironmentModalContent = (environment) => ( + <> + <p>Are you sure you want to delete this environment? (This action is irreversible)</p> + <p> + `Environment Name: ` + <i> + <b>{environment}</b> + </i> + </p> + </> + ); + + const handleBulkSelect = (e, id) => { + const isChecked = e.target.checked; + if (isChecked) { + setSelectedEnvironments([...selectedEnvironments, id]); + } else { + const newSelectedEnv = selectedEnvironments.filter((env) => env !== id); + setSelectedEnvironments(newSelectedEnv); + } + }; + + const handleBulkDeleteEnvironmentConfirm = async (e) => { + e.stopPropagation(); + let response = await modalRef.current.show({ + title: `Delete Environment(s) ?`, + subtitle: `Do you want to delete ${selectedEnvironments.length} environment(s) ?`, + options: ['DELETE', 'CANCEL'], + variant: PROMPT_VARIANTS.DANGER, + }); + if (response === 'DELETE') { + handleBulkDeleteEnv(); + } + }; + + const handleBulkDeleteEnv = () => { + selectedEnvironments.map((envId) => { + handleDeleteEnvironment(envId); + }); + setSelectedEnvironments([]); + }; + + const handleAssignConnection = () => { + const { addedConnectionsIds, removedConnectionsIds } = + getAddedAndRemovedConnection(assignedConnections); + + addedConnectionsIds.map((id) => addConnectionToEnvironment(connectionAssignEnv.id, id)); + + removedConnectionsIds.map((id) => removeConnectionFromEnvironment(connectionAssignEnv.id, id)); + setEnvironmentConnectionsData([]); + setConnectionsData([]); + handleonAssignConnectionModalClose(); + }; + + const handleonAssignConnectionModalOpen = (e, environment) => { + e.stopPropagation(); + setAssignConnectionModal(true); + if (connectionAssignEnv.id !== environment.id) { + setConnectionsData([]); + setEnvironmentConnectionsData([]); + } + setConnectionAssignEnv(environment); + setSkip(false); + }; + + const handleonAssignConnectionModalClose = () => { + setAssignConnectionModal(false); + setSkip(true); + }; + + const handleAssignConnectionData = (updatedAssignedData) => { + const { addedConnectionsIds, removedConnectionsIds } = + getAddedAndRemovedConnection(updatedAssignedData); + (addedConnectionsIds.length > 0 || removedConnectionsIds.length) > 0 + ? setDisableTranferButton(false) + : setDisableTranferButton(true); + + setAssignedConnections(updatedAssignedData); + }; + + const getAddedAndRemovedConnection = (allAssignedConnections) => { + const originalConnectionsIds = environmentConnectionsData.map((conn) => conn.id); + const updatedConnectionsIds = allAssignedConnections.map((conn) => conn.id); + + const addedConnectionsIds = updatedConnectionsIds.filter( + (id) => !originalConnectionsIds.includes(id), + ); + const removedConnectionsIds = originalConnectionsIds.filter( + (id) => !updatedConnectionsIds.includes(id), + ); + + return { + addedConnectionsIds, + removedConnectionsIds, + }; + }; + + const handleAssignablePage = () => { + const pagesCount = parseInt(Math.ceil(parseInt(connections?.total_count) / connectionPageSize)); + if (connectionsPage < pagesCount - 1) { + setConnectionsPage((prevConnectionsPage) => prevConnectionsPage + 1); + } + }; + + const handleAssignedPage = () => { + const pagesCount = parseInt( + Math.ceil(parseInt(environmentConnections?.total_count) / connectionPageSize), + ); + if (connectionsOfEnvironmentPage < pagesCount - 1) { + setConnectionsOfEnvironmentPage( + (prevConnectionsOfEnvironmentPage) => prevConnectionsOfEnvironmentPage + 1, + ); + } + }; + + return ( + <NoSsr> + {CAN(keys.VIEW_ENVIRONMENTS.action, keys.VIEW_ENVIRONMENTS.subject) ? ( + <> + <div className={StyleClass.toolWrapper} style={{ marginBottom: '20px', display: 'flex' }}> + <div className={classes.createButtonWrapper}> + <Button + type="submit" + variant="contained" + color="primary" + size="large" + onClick={(e) => handleEnvironmentModalOpen(e, ACTION_TYPES.CREATE)} + style={{ + padding: '8px', + borderRadius: 5, + marginRight: '2rem', + }} + disabled={!CAN(keys.CREATE_ENVIRONMENT.action, keys.CREATE_ENVIRONMENT.subject)} + data-cy="btnResetDatabase" + > + <AddIconCircleBorder style={{ width: '20px', height: '20px' }} /> + <Typography + style={{ + paddingLeft: '4px', + marginRight: '4px', + }} + > + Create + </Typography> + </Button> + </div> + <SearchBar + onSearch={(value) => { + setSearch(value); + }} + placeholder="Search connections..." + expanded={isSearchExpanded} + setExpanded={setIsSearchExpanded} + /> + </div> + {selectedEnvironments.length > 0 && ( + <Box className={classNames(classes.bulkActionWrapper, StyleClass.toolWrapper)}> + <Typography> + {selectedEnvironments.length > 1 + ? `${selectedEnvironments.length} environments selected` + : `${selectedEnvironments.length} environment selected`} + </Typography> + <Button className={classes.iconButton}> + <Delete + style={{ color: 'red', margin: '0 2px' }} + onClick={handleBulkDeleteEnvironmentConfirm} + disabled={ + selectedEnvironments.length > 0 + ? !CAN(keys.DELETE_ENVIRONMENT.action, keys.DELETE_ENVIRONMENT.subject) + : true + } + /> + </Button> + </Box> + )} + {environments.length > 0 ? ( + <> + <Grid container spacing={2} sx={{ marginTop: '10px' }}> + {environments.map((environment) => ( + <Grid item xs={12} md={6} key={environment.id}> + <EnvironmentCard + classes={classes} + environmentDetails={environment} + selectedEnvironments={selectedEnvironments} + onEdit={(e) => handleEnvironmentModalOpen(e, ACTION_TYPES.EDIT, environment)} + onDelete={(e) => handleDeleteEnvironmentConfirm(e, environment)} + onSelect={(e) => handleBulkSelect(e, environment.id)} + onAssignConnection={(e) => handleonAssignConnectionModalOpen(e, environment)} + /> + </Grid> + ))} + </Grid> + <Grid + container + sx={{ padding: '2rem 0' }} + style={{ marginTop: '20px' }} + flex + justifyContent="center" + spacing={2} + > + <Pagination + count={Math.ceil(environmentsData?.total_count / pageSize)} + page={page + 1} + sx={{ + backgroundColor: 'white', + borderRadius: '1rem', + padding: '0.5rem', + }} + onChange={debounce((_, page) => setPage(page - 1), 150)} + boundaryCount={3} + renderItem={(item) => ( + <PaginationItem + slots={{ previous: ChevronLeft, next: ChevronRight }} + {...item} + /> + )} + /> + </Grid> + </> + ) : ( + <EmptyState + icon={ + <EnvironmentIcon + height="6rem" + width="6rem" + fill="#808080" + secondaryFill="#979797" + /> + } + message="No environment available" + pointerLabel="Click “Create” to establish your first environment." + /> + )} + {(CAN(keys.CREATE_ENVIRONMENT.action, keys.CREATE_ENVIRONMENT.subject) || + CAN(keys.EDIT_ENVIRONMENT.action, keys.EDIT_ENVIRONMENT.subject)) && + environmentModal.open && ( + <Modal + open={environmentModal.open} + schema={environmentModal.schema.rjsfSchema} + uiSchema={environmentModal.schema.uiSchema} + handleClose={handleEnvironmentModalClose} + handleSubmit={ + actionType === ACTION_TYPES.CREATE + ? handleCreateEnvironment + : handleEditEnvironment + } + title={ + actionType === ACTION_TYPES.CREATE ? 'Create Environment' : 'Edit Environment' + } + submitBtnText={actionType === ACTION_TYPES.CREATE ? 'Save' : 'Update'} + initialData={initialData} + /> + )} + <GenericModal + open={assignConnectionModal} + handleClose={handleonAssignConnectionModalClose} + title={`${connectionAssignEnv.name} Resources`} + body={ + <TransferList + name="Connections" + assignableData={connectionsData} + assignedData={handleAssignConnectionData} + originalAssignedData={environmentConnectionsData} + emptyStateIconLeft={ + <ConnectionIcon width="120" primaryFill="#808080" secondaryFill="#979797" /> + } + emtyStateMessageLeft="No connections available" + emptyStateIconRight={ + <ConnectionIcon width="120" primaryFill="#808080" secondaryFill="#979797" /> + } + emtyStateMessageRight="No connections assigned" + transferComponentType={TRANSFER_COMPONENT.CHIP} + assignablePage={handleAssignablePage} + assignedPage={handleAssignedPage} + originalLeftCount={connections?.total_count} + originalRightCount={environmentConnections?.total_count} + /> + } + action={handleAssignConnection} + buttonTitle="Save" + disabled={disableTranferButton} + leftHeaderIcon={<EnvironmentIcon height="2rem" width="2rem" fill="white" />} + helpText="Assign connections to environment" + maxWidth="md" + /> + <PromptComponent ref={modalRef} /> + </> + ) : ( + <DefaultError /> + )} + </NoSsr> + ); +} + +export default Environments; diff --git a/examples/next-14/components/Lifecycle/Enviroments/styles.jsx b/examples/next-14/components/Lifecycle/Enviroments/styles.jsx new file mode 100644 index 00000000..e69de29b diff --git a/examples/next-14/components/Lifecycle/FlipCard/index.jsx b/examples/next-14/components/Lifecycle/FlipCard/index.jsx new file mode 100644 index 00000000..68ccc4b4 --- /dev/null +++ b/examples/next-14/components/Lifecycle/FlipCard/index.jsx @@ -0,0 +1,63 @@ +import React, { useState } from 'react'; +import { styled } from '@mui/material'; + +const FlipCardWrapper = styled('div')({ + background: 'transparent', + perspective: '1000px', +}); + +const FlipCardInner = styled('div')({ + display: 'flex', + flexDirection: 'column', + width: '100%', + height: '100%', + textAlign: 'center', + transition: 'transform 0.6s', + transformStyle: 'preserve-3d', + boxShadow: '0 4px 8px 0 rgba(0,0,0,0.2)', +}); + +const FlipCardBack = styled('div')({ + flex: 1, + display: 'flex', + width: '100%', + height: 'fit-content', + WebkitBackfaceVisibility: 'hidden', + backfaceVisibility: 'hidden', + transform: 'rotateY(180deg)', +}); + +const FlipCardFront = styled('div')({ + flex: 1, + display: 'flex', + position: 'absolute', + top: 0, + width: '100%', + height: '100%', + WebkitBackfaceVisibility: 'hidden', + backfaceVisibility: 'hidden', +}); + +const FlipCard = ({ frontComponents, backComponents, disableFlip }) => { + const [isFlipped, setIsFlipped] = useState(false); + + const handleFlip = () => { + if (!disableFlip) { + setIsFlipped(!isFlipped); + } + }; + + return ( + <FlipCardWrapper> + <FlipCardInner + onClick={handleFlip} + style={{ transform: isFlipped ? 'rotateY(180deg)' : 'rotateY(0deg)' }} + > + <FlipCardFront>{frontComponents}</FlipCardFront> + <FlipCardBack>{backComponents}</FlipCardBack> + </FlipCardInner> + </FlipCardWrapper> + ); +}; + +export default FlipCard; diff --git a/examples/next-14/components/Lifecycle/GenericModal/DialogTooltip.jsx b/examples/next-14/components/Lifecycle/GenericModal/DialogTooltip.jsx new file mode 100644 index 00000000..04510f21 --- /dev/null +++ b/examples/next-14/components/Lifecycle/GenericModal/DialogTooltip.jsx @@ -0,0 +1,18 @@ +import Tooltip, { tooltipClasses } from '@mui/material/Tooltip'; + +const DialogTooltip = styled(({ className, ...props }) => ( + <Tooltip {...props} classes={{ popper: className }} /> +))({ + [`& .${tooltipClasses.tooltip}`]: { + backgroundColor: 'rgba(122,132,142,1)', + color: '#F5F5F5', + padding: '1rem', + fontSize: '0.925rem', + '& .tooltip-dark': { + fontWeight: 'bold', + fontSize: '1rem', + }, + }, +}); + +export default DialogTooltip; diff --git a/examples/next-14/components/Lifecycle/GenericModal/index.jsx b/examples/next-14/components/Lifecycle/GenericModal/index.jsx new file mode 100644 index 00000000..a939902d --- /dev/null +++ b/examples/next-14/components/Lifecycle/GenericModal/index.jsx @@ -0,0 +1,151 @@ +import DialogTooltip from './DialogTooltip'; +import { + Dialog, + DialogActions, + DialogTitle, + IconButton, + CloseIcon, + Grid, + DialogContent, +} from '@layer5/sistent'; + +const CustomDialog = styled(Dialog)({ + '& .MuiDialogTitle-root': { + backgroundColor: theme.palette.secondary.mainBackground, + justifyContent: 'space-between', + flexDirection: 'row', + alignItems: 'center', + padding: '12px 20px', + gap: '146px', + color: theme.palette.secondary.white, + textAlign: 'center', + textOverflow: 'ellipsis', + '& h2': { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + }, + }, + '& .closing': { + transform: 'rotate(-90deg)', + '&:hover': { + transform: 'rotate(90deg)', + transition: 'all .3s ease-in', + cursor: 'pointer', + }, + }, + '& .modalActions': { + padding: '1rem 1.5rem', + display: 'flex', + justifyContent: 'flex-end', + width: '100%', + gap: '10px', + }, +}); + +const GenericModal = ({ + open, + handleClose, + title, + body, + selector, + action, + buttonTitle, + leftHeaderIcon, + actionBtnIcon, + hideFooter = false, + disabled = false, + helpText, + maxWidth = 'xs', +}) => { + return ( + <CustomDialog + fullWidth={true} + maxWidth={maxWidth} + aria-labelledby="transition-modal-title" + aria-describedby="transition-modal-description" + open={open} + onClose={handleClose} + closeAfterTransition + BackdropComponent={Backdrop} + BackdropProps={{ + timeout: 500, + }} + > + <DialogTitle textAlign="center" id="form-dialog-title"> + {leftHeaderIcon && ( + <div style={{ display: 'flex', alignItems: 'center' }}>{leftHeaderIcon}</div> + )} + <div style={{ display: 'flex', alignItems: 'center' }}> + <Typography variant="h6" component="h6"> + {title} + </Typography> + {selector ? selector : null} + </div> + <div style={{ display: 'flex', alignItems: 'center' }}> + {helpText && ( + <DialogTooltip title={helpText}> + <IconButton> + <HelpOutlineIcon + height={'2rem'} + wdith={'2rem'} + fill={theme.palette.secondary.primaryModalText} + /> + </IconButton> + </DialogTooltip> + )} + <IconButton + aria-label="close" + onClick={handleClose} + component="button" + className="closing" + style={{ + color: theme.palette.secondary.primaryModalText, + }} + > + <CloseIcon /> + </IconButton> + </div> + </DialogTitle> + <DialogContent style={{ padding: '1.5rem' }}>{body}</DialogContent> + {!hideFooter && ( + <DialogActions + style={{ + justifyContent: 'space-evenly', + marginBottom: '0.5rem', + }} + > + <Grid className="modalActions"> + <Button variant="outlined" onClick={handleClose} className="copyButton"> + Cancel + </Button> + <Button + title={buttonTitle ? buttonTitle : 'Submit'} + variant="contained" + color="primary" + className="submitButton" + disabled={disabled} + onClick={action} + > + {actionBtnIcon && ( + <div + style={{ + display: 'flex', + alignItems: 'center', + marginRight: '0.27rem', + color: theme.palette.primaryModalText, + }} + > + {actionBtnIcon} + </div> + )} + <span className="btnText">{buttonTitle ? buttonTitle : 'Submit'}</span> + </Button> + </Grid> + </DialogActions> + )} + </CustomDialog> + ); +}; + +export default GenericModal; diff --git a/examples/next-14/components/Lifecycle/TransferList/index.jsx b/examples/next-14/components/Lifecycle/TransferList/index.jsx new file mode 100644 index 00000000..c5645eb6 --- /dev/null +++ b/examples/next-14/components/Lifecycle/TransferList/index.jsx @@ -0,0 +1,292 @@ +function not(a, b) { + return a.filter((value) => b.indexOf(value) === -1); +} + +function intersection(a, b) { + return a.filter((value) => b.indexOf(value) !== -1); +} + +/** + * Renders transfer component. + * + * @param {Object} props - The component props. + * @param {String} props.name - This is the name of the data list. + * @param {Array} props.assignableData - The assignable data list. + * @param {Function} props.assignedData - The callback function to transfer assigned data list. + * @param {Array} props.originalAssignedData - The already assigend data list. + * @param {Element} props.emptyStateIconLeft - Icon for empty state of list left. + * @param {String} props.emtyStateMessageLeft - Message for the empty state of the list left. + * @param {Element} props.emptyStateIconRight - Icon for empty state of list right. + * @param {String} props.emtyStateMessageRight - Message for the empty state of the list right. + * @param {String} props.transferComponentType - Type of the component transfer (There is two types: chip and other). + */ + +export default function TransferList({ + name, + assignableData, + assignedData, + originalAssignedData, + emptyStateIconLeft, + emtyStateMessageLeft, + emptyStateIconRight, + emtyStateMessageRight, + transferComponentType = TRANSFER_COMPONENT.OTHER, + assignablePage, + assignedPage, + originalLeftCount, + originalRightCount, +}) { + const [checked, setChecked] = React.useState([]); + const [left, setLeft] = useState([]); + const [right, setRight] = useState([]); + const [leftCount, setLeftCount] = useState(0); + const [rightCount, setRightCount] = useState(0); + + useEffect(() => { + setRight(originalAssignedData); + }, [originalAssignedData]); + + useEffect(() => { + setLeft(assignableData); + }, [assignableData]); + + useEffect(() => { + setLeftCount(originalLeftCount); + setRightCount(originalRightCount); + }, [originalLeftCount, originalRightCount]); + + const leftChecked = intersection(checked, left); + const rightChecked = intersection(checked, right); + + useEffect(() => { + assignedData(right); + }, [right]); + + useEffect(() => { + const handleScroll = (entries) => { + const target = entries[0]; + if (target.isIntersecting) { + assignablePage(); + } + }; + + const observer = new IntersectionObserver(handleScroll, { threshold: 1 }); + const sentinel = document.getElementById('leftList'); + if (sentinel) { + observer.observe(sentinel); + } + + return () => { + if (sentinel) { + observer.unobserve(sentinel); + } + }; + }, [assignableData]); + + useEffect(() => { + const handleScroll = (entries) => { + const target = entries[0]; + if (target.isIntersecting) { + assignedPage(); + } + }; + + const observer = new IntersectionObserver(handleScroll, { threshold: 1 }); + const sentinel = document.getElementById('rightList'); + if (sentinel) { + observer.observe(sentinel); + } + + return () => { + if (sentinel) { + observer.unobserve(sentinel); + } + }; + }, [originalAssignedData]); + + const handleToggle = (value) => () => { + const currentIndex = checked.indexOf(value); + const newChecked = [...checked]; + + if (currentIndex === -1) { + newChecked.push(value); + } else { + newChecked.splice(currentIndex, 1); + } + + setChecked(newChecked); + }; + + const handleAllRight = () => { + setRight(right.concat(left)); + setLeft([]); + setLeftCount(0); + setRightCount(originalLeftCount); + }; + + const handleCheckedRight = () => { + setRight(right.concat(leftChecked)); + setLeft(not(left, leftChecked)); + setChecked(not(checked, leftChecked)); + setLeftCount((prevLeftCount) => prevLeftCount - leftChecked.length); + setRightCount((prevRightCount) => prevRightCount + leftChecked.length); + }; + + const handleCheckedLeft = () => { + setLeft(left.concat(rightChecked)); + setRight(not(right, rightChecked)); + setChecked(not(checked, rightChecked)); + setRightCount((prevRightCount) => prevRightCount - rightChecked.length); + setLeftCount((prevLeftCount) => prevLeftCount + rightChecked.length); + }; + + const handleAllLeft = () => { + setLeft(left.concat(right)); + setRight([]); + setRightCount(0); + setLeftCount(originalLeftCount); + }; + + const customList = (items, emptyStateIcon, emtyStateMessage, listId) => ( + <StyledPaper> + <List dense component="div" role="list"> + {items?.length > 0 ? ( + items.map((item) => { + const labelId = `transfer-list-item-${item.name}-label`; + return ( + <ListItem + key={item.id} + role="listitem" + style={{ + display: 'flex', + justifyContent: 'space-between', + '&:hover': { + backgroundColor: '#00000010', + }, + }} + onClick={handleToggle(item)} + > + {transferComponentType === TRANSFER_COMPONENT.CHIP ? ( + <Tooltip title={item.name} placement="top"> + <StyledChip + style={{ padding: '10px 0' }} + variant="outlined" + label={item.name} + onDelete={() => {}} + deleteIcon={<SMPIcon />} + icon={<KubernetesIcon />} + /> + </Tooltip> + ) : ( + <Tooltip title={item.name} placement="top"> + <Typography style={{ maxWidth: '230px', height: '1.5rem', overflow: 'hidden' }}> + {item.name} + </Typography> + </Tooltip> + )} + <StyledCheckbox + checked={checked.indexOf(item) !== -1} + tabIndex={-1} + disableRipple + inputProps={{ + 'aria-labelledby': labelId, + }} + /> + </ListItem> + ); + }) + ) : ( + <div + style={{ + textAlign: 'center', + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + height: '264px', + }} + > + {emptyStateIcon} + <Typography style={{ color: '#979797', padding: '24px 5px', lineHeight: 1 }}> + {emtyStateMessage} + </Typography> + </div> + )} + </List> + <div id={listId}></div> + </StyledPaper> + ); + + return ( + <Grid container justifyContent="center" alignItems="center"> + <ListGrid> + <ListHeading> + Available {name} ({leftCount ? leftCount : 0}) + </ListHeading> + {customList(left, emptyStateIconLeft, emtyStateMessageLeft, 'leftList')} + </ListGrid> + <ButtonGrid> + <Grid container direction="column" alignItems="center"> + <TransferButton + variant="outlined" + size="small" + color="primary" + onClick={handleAllRight} + disabled={left?.length === 0 || left.length < leftCount} + aria-label="move all right" + > + <RightArrowIcon primaryFill={Colors.keppelGreen} width={18} height={18} /> + <RightArrowIcon + primaryFill={Colors.keppelGreen} + style={{ position: 'absolute', left: '27px' }} + width={18} + height={18} + /> + </TransferButton> + <TransferButton + variant="outlined" + size="small" + color="primary" + onClick={handleCheckedRight} + disabled={leftChecked.length === 0} + aria-label="move selected right" + > + <RightArrowIcon primaryFill={Colors.keppelGreen} width={18} height={18} /> + </TransferButton> + <TransferButton + variant="outlined" + size="small" + color="primary" + onClick={handleCheckedLeft} + disabled={rightChecked.length === 0} + aria-label="move selected left" + > + <LeftArrowIcon primaryFill={Colors.keppelGreen} width={18} height={18} /> + </TransferButton> + <TransferButton + variant="outlined" + size="small" + color="primary" + onClick={handleAllLeft} + disabled={right.length === 0 || right.length < rightCount} + aria-label="move all left" + > + <LeftArrowIcon primaryFill={Colors.keppelGreen} width={18} height={18} /> + <LeftArrowIcon + primaryFill={Colors.keppelGreen} + style={{ position: 'absolute', left: '27px' }} + width={18} + height={18} + /> + </TransferButton> + </Grid> + </ButtonGrid> + <ListGrid> + <ListHeading> + Assigned {name} ({rightCount ? rightCount : 0}) + </ListHeading> + {customList(right, emptyStateIconRight, emtyStateMessageRight, 'rightList')} + </ListGrid> + </Grid> + ); +} diff --git a/examples/next-14/components/Lifecycle/TransferList/styles.jsx b/examples/next-14/components/Lifecycle/TransferList/styles.jsx new file mode 100644 index 00000000..f7d5e579 --- /dev/null +++ b/examples/next-14/components/Lifecycle/TransferList/styles.jsx @@ -0,0 +1,77 @@ +import { Button, Checkbox, Chip, Grid, Paper, Typography } from '@layer5/sistent'; +import { styled } from '@mui/material'; + +export const StyledChip = styled(Chip)({ + padding: '5px 6px !important', + fontSize: '14px', + textTransform: 'uppercase', + fontWeight: 400, + height: 'unset', + borderRadius: '100px', + border: `0.5px solid ${theme.palette.secondary.card}`, + maxWidth: '215px', +}); + +export const StyledPaper = styled(Paper)({ + width: 300, + height: 280, + overflow: 'auto', + borderRadius: '10px', + boxShadow: '0px 1px 4px 0px rgba(0, 0, 0, 0.25) inset', + '@media (max-width: 843px)': { + width: 260, + }, + '@media (max-width: 768px)': { + width: 300, + }, + '@media (max-width: 375px)': { + width: '100%', + }, +}); + +export const ListHeading = styled(Typography)({ + paddingBottom: '15px', + textAlign: 'center', + fontSize: '1rem', + letterSpacing: '0.15px', +}); + +export const TransferButton = styled(Button)({ + margin: '5px 0', + padding: '7px 0', + borderRadius: '10px', + boxShadow: 'none', + borderColor: Colors.keppelGreen, +}); + +export const ListGrid = styled(Grid)({ + padding: '0 1rem', + '@media (max-width: 768px)': { + padding: '0', + display: 'flex', + alignItems: 'center', + flexDirection: 'column', + width: '100%', + }, +}); + +export const ButtonGrid = styled(Grid)({ + padding: '40px 1rem 0 1rem', + '@media (max-width: 768px)': { + padding: '1rem', + transform: 'rotate(90deg)', + height: '100px', + marginLeft: '100px', + }, +}); + +export const StyledCheckbox = styled(Checkbox)({ + color: Colors.keppelGreen, + '&:hover': { + color: Colors.keppelGreen, + cursor: 'pointer', + }, + '&.Mui-checked': { + color: Colors.keppelGreen, + }, +}); diff --git a/examples/next-14/components/Lifecycle/index.jsx b/examples/next-14/components/Lifecycle/index.jsx new file mode 100644 index 00000000..e69de29b diff --git a/examples/next-14/components/MeshModelRegistry/MeshModel.style.jsx b/examples/next-14/components/MeshModelRegistry/MeshModel.style.jsx new file mode 100644 index 00000000..79a6d5ba --- /dev/null +++ b/examples/next-14/components/MeshModelRegistry/MeshModel.style.jsx @@ -0,0 +1,48 @@ +import { styled, alpha } from '@mui/material'; +import { TreeItem, treeItemClasses } from '@mui/x-tree-view'; + +export const DisableButton = styled(Button)(({ theme }) => ({ + '&.MuiButtonBase-root:disabled': { + cursor: 'not-allowed', + pointerEvents: 'auto', + backgroundColor: theme.palette.secondary.disableButtonBg, + color: theme.palette.secondary.disableButton, + }, +})); + +export const StyledTreeItemRoot = styled(TreeItem)(({ theme, root, lineColor }) => ({ + position: 'relative', + '&:before': { + pointerEvents: 'none', + content: '""', + position: 'absolute', + width: 32, + left: -34, + top: 23, + borderBottom: !root ? `1px dashed ${alpha(lineColor, 0.4)}` : 'none', + }, + + [`& .${treeItemClasses.content}`]: { + fontWeight: theme.typography.fontWeightMedium, + borderRadius: '0px 4px 4px 0px', + '&.Mui-expanded': { + fontWeight: theme.typography.fontWeightRegular, + }, + '&:hover': { + backgroundColor: `transparent`, + }, + '&.Mui-focused, &.Mui-selected, &.Mui-selected.Mui-focused': { + backgroundColor: `#00bfa030`, + borderLeft: '3px solid #00bfa0', + }, + [`& .${treeItemClasses.label}`]: { + fontWeight: 'inherit', + }, + }, + [`& .${treeItemClasses.group}`]: { + // marginLeft: 34, + paddingLeft: 36, + borderLeft: `1px dashed ${alpha(lineColor, 0.4)}`, + borderOpacity: 0.5, + }, +})); diff --git a/examples/next-14/components/MeshModelRegistry/MeshModel/index.jsx b/examples/next-14/components/MeshModelRegistry/MeshModel/index.jsx new file mode 100644 index 00000000..e69de29b diff --git a/examples/next-14/components/MeshModelRegistry/MeshModelDetails/index.jsx b/examples/next-14/components/MeshModelRegistry/MeshModelDetails/index.jsx new file mode 100644 index 00000000..e69de29b diff --git a/examples/next-14/components/MeshModelRegistry/MesheryTreeView/index.jsx b/examples/next-14/components/MeshModelRegistry/MesheryTreeView/index.jsx new file mode 100644 index 00000000..e69de29b diff --git a/examples/next-14/components/MeshModelRegistry/StyledTreeItem.jsx b/examples/next-14/components/MeshModelRegistry/StyledTreeItem.jsx new file mode 100644 index 00000000..52f6b6c9 --- /dev/null +++ b/examples/next-14/components/MeshModelRegistry/StyledTreeItem.jsx @@ -0,0 +1,78 @@ +import { StyledTreeItemRoot } from './MeshModel.style'; +import React, { useState } from 'react'; +import { useWindowDimensions, SearchBar, Typography } from '@layer5/sistent'; +import { useTheme } from '@mui/material'; + +/** + * Customized item component in mui-x-tree + */ +const StyledTreeItem = React.forwardRef(function StyledTreeItem(props, ref) { + // const [checked, setChecked] = useState(false); + const { labelText, root, search, setSearchText, ...other } = props; + const theme = useTheme(); + const { width } = useWindowDimensions(); + const [isSearchExpanded, setIsSearchExpanded] = useState(false); + + return ( + <StyledTreeItemRoot + // onMouseEnter={() => setHover(true)} + // onMouseLeave={() => setHover(false)} + root={root} + lineColor={theme.palette.secondary.text} + label={ + <Box + sx={{ + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + py: 1.5, + px: 0, + }} + > + {width < 1370 && isSearchExpanded ? null : ( + <div + style={{ + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + }} + > + <Typography variant={'body'} style={{ color: `${root}` }}> + {labelText} + </Typography> + </div> + )} + + {/* Currently the functionality of checkbox is not supported */} + + {/* {check && ( + <Checkbox + onClick={() => setChecked((prevcheck) => !prevcheck)} + size="small" + checked={checked} + sx={{ + visibility: hover || checked ? 'visible' : 'hidden', + color: '#00B39F', + '&.Mui-checked': { + color: '#00B39F', + }, + }} + /> + )} */} + {search && ( + <SearchBar + onSearch={debounce((value) => setSearchText(value), 200)} + expanded={isSearchExpanded} + setExpanded={setIsSearchExpanded} + placeholder="Search" + /> + )} + </Box> + } + {...other} + ref={ref} + /> + ); +}); + +export default StyledTreeItem; diff --git a/examples/next-14/components/MeshModelRegistry/helper.jsx b/examples/next-14/components/MeshModelRegistry/helper.jsx new file mode 100644 index 00000000..4acea4f6 --- /dev/null +++ b/examples/next-14/components/MeshModelRegistry/helper.jsx @@ -0,0 +1,109 @@ +/** + * Retrieves filtered data for the details component based on the selected item ID. + * + * @param {Array} data - An array of data representing the tree. + * @param {string} selectedItemUUID - Node ID of the selected element in the tree. + * @returns {Object} - An object containing the selected component, model, and relationship, with type and data properties. + */ +export const getFilteredDataForDetailsComponent = (data, selectedItemUUID) => { + const selectedIdArr = selectedItemUUID.split('.'); + const resultObject = findNestedObject( + data, + (obj) => _.get(obj, 'id') === selectedIdArr[selectedIdArr.length - 1], + ); + + const propertiesArr = resultObject ? Object.keys(resultObject).map(_.toLower) : []; + const isPropertyIncluded = (property) => propertiesArr.includes(_.toLower(property)); + + const isDepthCheck = () => { + if (isPropertyIncluded('summary')) { + return REGISTRANTS; + } else if (isPropertyIncluded(COMPONENTS) || isPropertyIncluded(RELATIONSHIPS)) { + return MODELS; + } else if (isPropertyIncluded('evaluationQuery')) { + return RELATIONSHIPS; + } else if (isPropertyIncluded('schema')) { + return COMPONENTS; + } + }; + + const selectedType = isDepthCheck(); + + return { + type: selectedType || '', + data: resultObject || {}, + }; +}; + +/** + * Group relationships by kind + * @param {object} - Relationships arrays + */ +export const groupRelationshipsByKind = (relationships) => { + const groupedRelationships = {}; + + relationships.forEach((relationship) => { + const { id, kind } = relationship; + + if (!groupedRelationships[kind]) { + groupedRelationships[kind] = { kind, relationships: [] }; + } + + groupedRelationships[kind].relationships.push({ id, ...relationship }); + }); + const resultArray = Object.values(groupedRelationships); + return resultArray; +}; + +/** + * Function takes models data and merges the duplicate data + * @param {object} - models data + */ +export const removeDuplicateVersions = (data) => { + const groupedModels = _.groupBy(data, 'name'); + + const result = _.reduce( + groupedModels, + (acc, models, name) => { + const uniqueVersions = _.groupBy(models, 'version'); + const arrayOfUniqueVersions = Object.values(uniqueVersions); + + const existingModel = acc.find((m) => m.name === name); + + const mergedData = arrayOfUniqueVersions.map((modelsWithSameVersion) => { + let subVal = { + relationships: {}, + components: {}, + }; + modelsWithSameVersion.map((model) => { + subVal.relationships = _.union(subVal.relationships, model.relationships); + subVal.components = _.union(subVal.components, model.components); + }); + return { + ...modelsWithSameVersion[0], + ...subVal, + }; + }); + + if (existingModel) { + existingModel.version = _.union( + existingModel.version, + mergedData.map((model) => model.version), + ); + existingModel.versionBasedData = existingModel.versionBasedData.concat(mergedData); + } else { + const selectedModel = models[0]; + acc.push({ + ...selectedModel, + version: mergedData.map((model) => model.version), + versionBasedData: mergedData, + }); + } + + return acc; + }, + [], + ); + + return result; +}; diff --git a/examples/next-14/components/MesheryMeshInterface/TextTooltip.jsx b/examples/next-14/components/MesheryMeshInterface/TextTooltip.jsx new file mode 100644 index 00000000..1e3f18f4 --- /dev/null +++ b/examples/next-14/components/MesheryMeshInterface/TextTooltip.jsx @@ -0,0 +1,42 @@ +import { CHARCOAL, Tooltip } from '@layer5/sistent'; +import { styled } from '@mui/material'; +import { ziCalc } from '@/utils/zIndex'; + +export const renderTooltipContent = ({ showPriorText, showAfterText, link }) => { + const handleClick = (e) => { + window.open(link, '_blank'); + e.stopPropagation; + }; + + return ( + <div> + <span style={{ marginRight: '2px' }}>{showPriorText}</span> + <a onClick={handleClick} target="_blank" rel="noopener noreferrer"> + Read docs + </a> + <span style={{ marginLeft: '2px' }}>{showAfterText}</span> + </div> + ); +}; + +const CustomTextTooltip = styled(Tooltip)(({ backgroundColor, flag }) => ({ + '& .MuiTooltip-tooltip': { + backgroundColor: backgroundColor || CHARCOAL, + color: '#fff', + opacity: '100%', + fontSize: '0.75rem', + fontFamily: flag ? 'Qanelas Soft, sans-serif' : 'inherit', + borderRadius: '0.9375rem', + padding: '0.9rem', + zIndex: ziCalc(11), + }, + '& .MuiTooltip-popper': { + zIndex: `${ziCalc(5)} !important`, + }, +})); + +export function TextTooltip({ backgroundColor = CHARCOAL, flag, ...props }) { + return <CustomTextTooltip {...props} />; +} + +export default TextTooltip; diff --git a/examples/next-14/components/Modals/GenericModal/index.jsx b/examples/next-14/components/Modals/GenericModal/index.jsx new file mode 100644 index 00000000..902135c8 --- /dev/null +++ b/examples/next-14/components/Modals/GenericModal/index.jsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { Modal, Backdrop, Fade } from '@mui/material'; + +/** + * A generic modal component. + * @param {Object} props - The props object. + * @param {boolean} [props.open] - Whether the modal is open or not. + * @param {React.ReactNode | JSX.Element} [props.children] - The content of the modal. + * @param {Function} [props.handleClose] - Function to handle modal close event. + * @param {React.ReactInstance | Function} [props.container] - The container to render the modal into. + * @returns {JSX.Element} A JSX element representing the generic modal. + */ +export function GenericModal({ open, children, handleClose, container }) { + return ( + <Modal + style={{ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }} + open={open} + onClose={handleClose} + closeAfterTransition + slots={Backdrop} + slotProps={{ timeout: 200 }} + container={container} + id="searchClick" + > + <Fade in={open} style={{ maxHeight: '90vh', overflow: 'auto' }}> + {children} + </Fade> + </Modal> + ); +} + +export default GenericModal; diff --git a/examples/next-14/components/Modals/ResultModal/index.jsx b/examples/next-14/components/Modals/ResultModal/index.jsx new file mode 100644 index 00000000..e69de29b diff --git a/examples/next-14/components/Modals/TroubleshootModal/index.jsx b/examples/next-14/components/Modals/TroubleshootModal/index.jsx new file mode 100644 index 00000000..e69de29b diff --git a/examples/next-14/components/Modals/URLUploader/index.jsx b/examples/next-14/components/Modals/URLUploader/index.jsx new file mode 100644 index 00000000..74bbde7d --- /dev/null +++ b/examples/next-14/components/Modals/URLUploader/index.jsx @@ -0,0 +1,91 @@ +import { urlValidator } from '@/utils/urlValidator'; +import { Tooltip, IconButton, Grid, TextField, Button } from '@layer5/sistent-components'; +import GenericModal from '../GenericModal'; +import React from 'react'; + +export function URLUploader({ onSubmit }) { + const [open, setOpen] = React.useState(false); + const [input, setInput] = React.useState(''); + const [isError, setIsError] = React.useState(false); + + React.useEffect(() => { + if (input) { + setIsError(!urlValidator(input)); + } + }, [input]); + + const handleOpen = () => { + setOpen(true); + }; + + const handleClose = () => { + setOpen(false); + }; + + const handleSubmit = () => { + onSubmit(input); + handleClose(); + }; + + return ( + <> + <label htmlFor="url-upload-button"> + <Tooltip title="Upload URL"> + <IconButton aria-label="URL-Upload" component="span" onClick={handleOpen} size="large"> + <LinkIcon /> + </IconButton> + </Tooltip> + <GenericModal + open={open} + handleClose={handleClose} + Content={ + <div + style={{ + position: 'absolute', + width: 600, + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + borderRadius: 10, + }} + > + <Grid container spacing={2}> + <Grid item xs={12}> + <h2 id="simple-modal-title">Import using URL</h2> + </Grid> + <Grid item xs={12}> + <TextField + error={isError} + helperText={isError && 'Invalid URL'} + variant="outlined" + label="Paste URL here" + fullWidth + onChange={(e) => setInput(e.target.value)} + /> + </Grid> + <Grid item xs={12} sm={6}> + <Button fullWidth variant="contained" onClick={handleClose}> + Cancel + </Button> + </Grid> + <Grid item xs={12} sm={6}> + <Button + disabled={isError || !input} + fullWidth + variant="contained" + color="primary" + onClick={() => handleSubmit()} + > + Import + </Button> + </Grid> + </Grid> + </div> + } + /> + </label> + </> + ); +} + +export default URLUploader; diff --git a/examples/next-14/components/NotificationCenter/constants/notification.js b/examples/next-14/components/NotificationCenter/constants/notification.js new file mode 100644 index 00000000..6ec39d5c --- /dev/null +++ b/examples/next-14/components/NotificationCenter/constants/notification.js @@ -0,0 +1,189 @@ +import Ajv from 'ajv'; +import _ from 'lodash'; +import ReadIcon from '@/icons/ReadIcon'; +import AlertIcon from '@/icons/AlertIcon'; +import InfoIcon from '@/icons/InfoIcon'; +import ErrorIcon from '@/icons/ErrorIcon'; + +export const Colors = { + darkJungleGreen: '#1E2117', + caribbeanGreen: '#00D3a9', + keppelGreen: '#00B39F', + charcoal: '#3C494F', +}; + +export const NOTIFICATION_COLORS = { + ERROR: '#F91313', // #B32700 + WARNING: '#F0A303', + SUCCESS: '#206D24', + INFO: '#2196F3', +}; + +export const SEVERITY = { + INFO: 'informational', + ERROR: 'error', + WARNING: 'warning', + SUCCESS: 'success', +}; + +// This class is required to add to any svg or button that opens notification center +// To prevent the ClickAwayListener from blocking it +export const NOTIFICATION_CENTER_TOGGLE_CLASS = 'toggle-notification-center'; + +export const SEVERITY_TO_NOTIFICATION_TYPE_MAPPING = { + [SEVERITY.INFO]: 'info', + [SEVERITY.ERROR]: 'error', + [SEVERITY.WARNING]: 'warning', + [SEVERITY.SUCCESS]: 'success', +}; + +export const STATUS = { + READ: 'read', + UNREAD: 'unread', +}; + +export const STATUS_STYLE = { + [STATUS.READ]: { + icon: ReadIcon, + color: Colors.charcoal, + darkColor: '#BCC7CC', + }, +}; + +export const SEVERITY_STYLE = { + [SEVERITY.INFO]: { + icon: InfoIcon, + color: NOTIFICATION_COLORS.INFO, + darkColor: NOTIFICATION_COLORS.INFO, + }, + [SEVERITY.ERROR]: { + icon: ErrorIcon, + color: NOTIFICATION_COLORS.ERROR, + darkColor: NOTIFICATION_COLORS.ERROR, + }, + [SEVERITY.WARNING]: { + icon: AlertIcon, + color: NOTIFICATION_COLORS.WARNING, + darkColor: NOTIFICATION_COLORS.WARNING, + }, + [SEVERITY.SUCCESS]: { + icon: InfoIcon, + color: NOTIFICATION_COLORS.SUCCESS, + darkColor: NOTIFICATION_COLORS.SUCCESS, + }, +}; + +//TODO: This should be generated from OPENAPI schema +const EVENT_SCHEMA = { + type: 'object', + properties: { + id: { type: 'string' }, + description: { + type: 'string', + default: '', + }, + severity: { + type: 'string', + enum: Object.values(SEVERITY), + default: SEVERITY.INFO, + }, + status: { + type: 'string', + enum: Object.values(STATUS), + default: STATUS.UNREAD, + }, + created_at: { type: 'string' }, + updated_at: { type: 'string' }, + user_id: { type: 'string' }, + system_id: { type: 'string' }, + operation_id: { type: 'string' }, + action: { type: 'string' }, + category: { type: 'string' }, + metadata: { + type: ['object', 'null'], + }, + }, + required: [ + 'id', + 'severity', + 'status', + 'created_at', + 'updated_at', + 'user_id', + 'system_id', + 'action', + ], +}; + +// Validate event against EVENT_SCHEMA and return [isValid,validatedEvent] +export const validateEvent = (event) => { + const eventCopy = _.cloneDeep(event) || {}; + eventCopy.status = eventCopy.status.trim() || STATUS.UNREAD; + eventCopy.severity = eventCopy.severity.trim() || SEVERITY.INFO; + const ajv = new Ajv({ + useDefaults: true, + }); + const validate = ajv.compile(EVENT_SCHEMA); + const valid = validate(eventCopy); + return [valid, eventCopy]; +}; + +// return validated events (adds default values if not present) +export const validateEvents = (events) => { + return events + .map((event) => { + const [isValid, validatedEvent] = validateEvent(event); + return isValid ? validatedEvent : null; + }) + .filter((event) => event); +}; + +const EVENT_METADATA_SCHEMA = { + type: 'object', + properties: { + error: { + type: 'object', + properties: { + Code: { type: 'string' }, + LongDescription: { + type: 'array', + items: { type: 'string' }, + default: [], + }, + ProbableCause: { + type: 'array', + items: { type: 'string' }, + default: [], + }, + Severity: { type: 'number', default: 1 }, + ShortDescription: { + type: 'array', + items: { type: 'string' }, + default: [], + }, + SuggestedRemediation: { + type: 'array', + items: { type: 'string' }, + default: [], + }, + }, + required: [ + 'Code', + 'LongDescription', + 'ProbableCause', + 'Severity', + 'ShortDescription', + 'SuggestedRemediation', + ], + }, + }, + required: ['error'], +}; + +export const validateEventMetadata = (metadata) => { + const metadataCopy = _.cloneDeep(metadata) || {}; + const ajv = new Ajv(); + const validate = ajv.compile(EVENT_METADATA_SCHEMA); + const valid = validate(metadataCopy); + return [valid, metadataCopy]; +}; diff --git a/examples/next-14/components/Preferences/User.jsx b/examples/next-14/components/Preferences/User.jsx new file mode 100644 index 00000000..30ba83b3 --- /dev/null +++ b/examples/next-14/components/Preferences/User.jsx @@ -0,0 +1,106 @@ +import { useRouter } from 'next/router'; +import exportToJsonFile from './exportToJsonFile'; +import RenderAccountExtension from './renderAccountExtension'; +import useFetchUserData from '@/lib/hooks/useFetchUserData'; +import withMetadata from '@/utils/getMetadataWrapper'; +import React from 'react'; +import Popper from '@mui/material/Popper'; +import { + Avatar, + Box, + ClickAwayListener, + IconButton, + MenuItem, + MenuList, + Paper, +} from '@layer5/sistent'; +import Grow from '@mui/material/Grow'; + +function UserPref({ getPath, pageTitle, color }) { + const router = useRouter(); + const [open, setOpen] = React.useState(false); + const [anchorEl, setAnchorEl] = React.useState(); + + const { user, loading, error } = useFetchUserData('/api/user', { + credentials: 'same-origin', + }); + + if (loading) { + return <div>Loading...</div>; + } + + if (error) { + return <div>Error: {error}</div>; + } + + const handleToggle = () => { + setOpen(!open); + }; + + const handleClose = (event) => { + if (anchorEl.contains(event.target)) { + return; + } + setOpen(false); + }; + + const handlePreference = () => { + router.push('/user/preferences'); + }; + + const handleLogout = () => { + window.location.href = '/user/logout'; + }; + + const handleGetToken = () => { + const data = user; + exportToJsonFile(data, 'auth.json'); + }; + + return ( + <React.Fragment> + <Box data-test="profile-button"> + <IconButton + color={color} + ref={(node) => { + anchorEl = node; + }} + > + <Avatar /> + </IconButton> + </Box> + <Popper + open={open} + anchorEl={anchorEl} + transition + style={{ zIndex: 10000 }} + placement="top-end" + > + {({ TransitionProps, placement }) => ( + <Grow + {...TransitionProps} + id="menu-list-grow" + style={{ + transformOrigin: placement === 'bottom' ? 'left top' : 'left bottom', + }} + > + <Paper className={classes.popover}> + <ClickAwayListener onClickAway={handleClose}> + <MenuList> + {account && account.length ? ( + <RenderAccountExtension accountExtensions={account} /> + ) : null} + <MenuItem onClick={handleGetToken}>Get Token</MenuItem> + <MenuItem onClick={handlePreference}>Preferences</MenuItem> + <MenuItem onClick={handleLogout}>Logout</MenuItem> + </MenuList> + </ClickAwayListener> + </Paper> + </Grow> + )} + </Popper> + </React.Fragment> + ); +} + +export default withMetadata(UserPref); diff --git a/examples/next-14/components/Preferences/exportToJsonFile.js b/examples/next-14/components/Preferences/exportToJsonFile.js new file mode 100644 index 00000000..faa73cff --- /dev/null +++ b/examples/next-14/components/Preferences/exportToJsonFile.js @@ -0,0 +1,16 @@ +const exportToJsonFile = (jsonData, filename) => { + const dataStr = JSON.stringify(jsonData); + const dataUri = `data:application/json;charset=utf-8,${encodeURIComponent(dataStr)}`; + const exportFileDefaultName = filename; + + const linkElement = document.createElement('a'); + linkElement.href = dataUri; + linkElement.download = exportFileDefaultName; + linkElement.style.display = 'none'; + + document.body.appendChild(linkElement); + linkElement.click(); + document.body.removeChild(linkElement); +}; + +export default exportToJsonFile; diff --git a/examples/next-14/components/Preferences/extensionPointContent.jsx b/examples/next-14/components/Preferences/extensionPointContent.jsx new file mode 100644 index 00000000..5119f0e4 --- /dev/null +++ b/examples/next-14/components/Preferences/extensionPointContent.jsx @@ -0,0 +1,20 @@ +import { ListItemText } from '@layer5/sistent'; +import Link from 'next/link'; +import React from 'react'; + +export const ExtensionPointContent = ({ href, name, updateExtensionType }) => { + const content = ( + <div> + <ListItemText>{name}</ListItemText> + </div> + ); + + if (href) { + return ( + <Link href={href}> + <span onClick={() => updateExtensionType(name)}>{content}</span> + </Link> + ); + } + return content; +}; diff --git a/examples/next-14/components/Preferences/renderAccountExtension.jsx b/examples/next-14/components/Preferences/renderAccountExtension.jsx new file mode 100644 index 00000000..2abad911 --- /dev/null +++ b/examples/next-14/components/Preferences/renderAccountExtension.jsx @@ -0,0 +1,31 @@ +import { List, ListItemButton } from '@layer5/sistent'; +import { Fragment } from 'react'; + +import { ExtensionPointContent } from './extensionPointContent'; + +const RenderAccountExtension = ({ accountExtensions }) => { + if (accountExtensions && accountExtensions.length > 0) { + return ( + <List disablePadding> + {accountExtensions.map(({ id, href, title, show: showc }) => { + if (typeof showc !== 'undefined' && !showc) { + return ''; + } + return ( + <Fragment key={id}> + <ListItemButton key={id}> + <ExtensionPointContent + href={href} + name={name} + updateExtensionType={updateExtensionType} + /> + </ListItemButton> + </Fragment> + ); + })} + </List> + ); + } +}; + +export default RenderAccountExtension; diff --git a/examples/next-14/components/ProviderLogin/ProviderFooter/index.jsx b/examples/next-14/components/ProviderLogin/ProviderFooter/index.jsx new file mode 100644 index 00000000..aba062aa --- /dev/null +++ b/examples/next-14/components/ProviderLogin/ProviderFooter/index.jsx @@ -0,0 +1,47 @@ +import { Paper } from '@layer5/sistent'; +import FavoriteIcon from '@mui/icons-material/Favorite'; +import { styled } from '@mui/material/styles'; +import Typography from '@mui/material/Typography'; +import React, { Fragment } from 'react'; + +const Item = styled(Paper)(({ theme }) => ({ + backgroundColor: theme.palette.background.paper, + padding: theme.spacing(2), + color: '#737373', + border: '0', +})); + +export default function ProviderFooter() { + const handleL5CommunityClick = () => { + if (typeof window !== 'undefined') { + const w = window.open('https://layer5.io', '_blank'); + w?.focus(); + } + }; + + return ( + <Fragment> + <Item component="footer" square variant="outlined"> + <Typography variant="body2" align="center" color="textSecondary" component="p"> + <span + onClick={handleL5CommunityClick} + style={{ + cursor: 'pointer', + display: 'inline', + verticalAlign: 'middle', + }} + > + Built with{' '} + <FavoriteIcon + sx={{ + display: 'inline', + verticalAlign: 'top', + }} + />{' '} + by the Layer5 Community + </span> + </Typography> + </Item> + </Fragment> + ); +} diff --git a/examples/next-14/components/ProviderLogin/ProviderLearnMoreSection/index.jsx b/examples/next-14/components/ProviderLogin/ProviderLearnMoreSection/index.jsx new file mode 100644 index 00000000..e296a20f --- /dev/null +++ b/examples/next-14/components/ProviderLogin/ProviderLearnMoreSection/index.jsx @@ -0,0 +1,32 @@ +import { Box, Tooltip, Typography } from '@layer5/sistent'; +import Link from 'next/link'; +import { styled } from '@mui/material/styles'; + +export const ProviderLearnMoreContainer = styled(Box)(() => ({ + width: '60%', + marginLeft: 'auto', + marginRight: 'auto', + marginTop: '3rem', +})); + +export function ProviderLearnMoreSection({ handleOpen }) { + return ( + <ProviderLearnMoreContainer> + <Typography variant="h5" sx={{ fontWeight: 500 }} gutterBottom> + Learn more about{' '} + <Tooltip title="Learn more aboout providers" placement="bottom" data-cy="providers-tooltip"> + <Link + href={'#'} + style={{ color: '#00B39F', cursor: 'pointer', fontWeight: 700 }} + onClick={handleOpen} + > + {' '} + providers{' '} + </Link> + </Tooltip> + </Typography> + </ProviderLearnMoreContainer> + ); +} + +export default ProviderLearnMoreSection; diff --git a/examples/next-14/components/ProviderLogin/ProviderLoginLayout/index.jsx b/examples/next-14/components/ProviderLogin/ProviderLoginLayout/index.jsx new file mode 100644 index 00000000..3ef29ebb --- /dev/null +++ b/examples/next-14/components/ProviderLogin/ProviderLoginLayout/index.jsx @@ -0,0 +1,13 @@ +import { Box } from '@layer5/sistent'; +import { styled } from '@mui/material/styles'; + +export const ProviderLoginContainer = styled(Box)(() => ({ + padding: '170px 0px', + textAlign: 'center', +})); + +export function ProviderLoginLayout({ children }) { + return <ProviderLoginContainer data-cy="root">{children}</ProviderLoginContainer>; +} + +export default ProviderLoginLayout; diff --git a/examples/next-14/components/ProviderLogin/ProviderModal/index.jsx b/examples/next-14/components/ProviderLogin/ProviderModal/index.jsx new file mode 100644 index 00000000..d6013479 --- /dev/null +++ b/examples/next-14/components/ProviderLogin/ProviderModal/index.jsx @@ -0,0 +1,197 @@ +import { useFetchProvidersQuery } from '@/lib/rtk-query/queries/provider'; +import { providerData } from '@/pages/provider/providerData'; +import { + Box, + CloseIcon, + Dialog, + DialogContent, + DialogContentText, + DialogTitle, + IconButton, + List, + ListItem, + Typography, + DARK_SHADE_GRAY, + DialogActions, + Button, +} from '@layer5/sistent'; +import { ListItemText } from '@mui/material'; +import { styled } from '@mui/material/styles'; +import Link from 'next/link'; +import { Fragment } from 'react'; + +function ExternalLinkIcon({ width = 16, height = 16, ...props }) { + return ( + <svg + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 20 20" + width={width} + height={height} + {...props} + > + <g + style={{ + stroke: 'gray', + strokeWidth: 1, + }} + > + <path d="M5 5v9m9-5v5m-9 0h9M5 5h4m1-3h7m0 0v7" /> + <path + style={{ + strokeWidth: 1.5, + }} + d="m10 9 7-7" + /> + </g> + </svg> + ); +} + +function ProviderDialogTitle({ onClose, title, children, ...props }) { + const { ...other } = props; + + return ( + <DialogTitle sx={{ m: 0, p: 2, backgroundColor: '#eee' }} {...other}> + {title} + {onClose ? ( + <IconButton + aria-label="close" + onClick={onClose} + sx={{ + position: 'absolute', + right: '1rem', + top: '1rem', + color: (theme) => theme.palette.grey[500], + }} + > + <CloseIcon /> + </IconButton> + ) : null} + </DialogTitle> + ); +} + +/** + * Retrieve list of available providers + * + * Meshery or None + * + * @param param0 + * @returns + */ +function ProvidersAvailableList({ availableProviders }) { + if (!Array.isArray(availableProviders)) { + return null; + } + + return ( + <Box> + {availableProviders.map((provider, index) => ( + <Box key={index} sx={{ marginBottom: 2 }}> + <Typography variant="h6" sx={{ fontWeight: 700 }}> + {provider.provider_name} + </Typography> + <List dense disablePadding> + {provider.provider_description.map((desc, i) => ( + <ListItem dense disableGutters disablePadding key={i}> + <ListItemText primary={desc} /> + </ListItem> + ))} + </List> + </Box> + ))} + </Box> + ); +} + +function ProviderList({ providerData }) { + return ( + <Box> + {providerData.map((provider, index) => ( + <Box key={index} sx={{ marginBottom: 2 }}> + <Typography variant="h5" sx={{ fontWeight: 700 }}> + {provider.name} + </Typography> + <List dense disablePadding> + {provider.description.map((desc, i) => ( + <ListItem dense disableGutters disablePadding key={i}> + <ListItemText primary={desc} /> + </ListItem> + ))} + </List> + </Box> + ))} + </Box> + ); +} + +export const ProviderDialog = styled(Dialog)(({ theme }) => ({ + '& .MuiDialogContent-root': { + padding: theme.spacing(2), + }, + '& .MuiDialogActions-root': { + padding: theme.spacing(1), + }, + '& .MuiDialogContentText-root > a': { + color: DARK_SHADE_GRAY, + }, +})); + +export const ProviderDialogActions = styled(DialogActions)(({ theme }) => ({ + display: 'flex', + justifyContent: 'space-between', + background: '#eee', + padding: theme.spacing(2), + '& div > a': { + color: DARK_SHADE_GRAY, + }, +})); + +export const mesheryLoginText = ` +Login to Meshery by choosing from the available providers. +Providers extend Meshery by offering various plugins and services, +including identity services, long-term persistence, advanced +performance analysis, multi-player user collaboration, and so on. +`; + +export function ProviderModal({ open, handleClose }) { + const { data: availableProviders = {}, isLoading, isError } = useFetchProvidersQuery({}); + + return ( + <Fragment> + <ProviderDialog + open={open} + onClose={handleClose} + disableScrollLock={true} + data-cy="providers-modal" + > + <ProviderDialogTitle title={' Choosing a Provider'} onClose={handleClose} /> + <DialogContent dividers> + <DialogContentText> + {mesheryLoginText} + <Typography variant="h4">Available Providers</Typography> + <ProvidersAvailableList availableProviders={availableProviders} /> + <ProviderList providerData={providerData} /> + </DialogContentText> + </DialogContent> + <ProviderDialogActions> + <Link href="https://docs.meshery.io/extensibility/providers"> + Providers in Meshery Docs + </Link> + <ExternalLinkIcon /> + <Button + onClick={handleClose} + color="primary" + data-cy="providers-modal-button-ok" + variant="contained" + > + {' '} + OK + </Button> + </ProviderDialogActions> + </ProviderDialog> + </Fragment> + ); +} + +export default ProviderModal; diff --git a/examples/next-14/components/ProviderLogin/content.jsx b/examples/next-14/components/ProviderLogin/content.jsx new file mode 100644 index 00000000..057bfa4d --- /dev/null +++ b/examples/next-14/components/ProviderLogin/content.jsx @@ -0,0 +1,23 @@ +export const content = [ + { + title: 'SMI Conformance', + items: [ + 'Remote provider for SMI Conformance Testing', + 'Provides provenance of test results and their persistence', + ], + }, + { + title: 'The University of Texas at Austin', + items: [ + 'Academic research and advanced studies by Ph.D. researchers', + 'Used by school of Electrical and Computer Engineering (ECE)', + ], + }, + { + title: 'Cloud Native Computing Foundation Infrastructure Lab', + items: [ + 'Performance and compatibility-centric research and validation', + 'Used by various service meshes and by the Service Mesh Performance project', + ], + }, +]; diff --git a/examples/next-14/components/ProviderLogin/disabledMenuItem.jsx b/examples/next-14/components/ProviderLogin/disabledMenuItem.jsx new file mode 100644 index 00000000..8a4e10e5 --- /dev/null +++ b/examples/next-14/components/ProviderLogin/disabledMenuItem.jsx @@ -0,0 +1,5 @@ +export const disabledMenuItems = [ + { key: 'SMI', text: 'SMI Conformance' }, + { key: 'UT Austin', text: 'The University of Texas at Austin' }, + { key: 'CNCF Cluster', text: 'CNCF Cluster' }, +]; diff --git a/examples/next-14/components/ProviderLogin/index.jsx b/examples/next-14/components/ProviderLogin/index.jsx new file mode 100644 index 00000000..24dc9f33 --- /dev/null +++ b/examples/next-14/components/ProviderLogin/index.jsx @@ -0,0 +1,274 @@ +import { useTheme } from '@mui/material'; +import { Fragment, useState, useEffect, useRef } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { fetchProviders } from '@/lib/redux/features/provider/provider.slice'; +import { selectProviders } from '@/lib/redux/selectors'; +import { + Typography, + Tooltip, + DialogContent, + DialogContentText, + List, + ListItem, + DialogActions, + Button, + Box, + ButtonGroup, + Paper, + ClickAwayListener, + MenuList, + MenuItem, + Divider, +} from '@layer5/sistent'; +import ProviderLayout from './layout'; +import { useMediaQuery, Link, ListItemText, CircularProgress, Popper, Grow } from '@mui/material'; +import { MesheryLogo, MesheryDialog, MesheryDialogTitle, MenuProviderDisabled } from './styles'; +import { content } from './content'; +import ProviderFooter from './ProviderFooter'; +import { disabledMenuItems } from './disabledMenuItem'; +import { ArrowDropDown } from '@mui/icons-material'; +import { useFetchProvidersQuery } from '@/lib/rtk-query/queries/provider'; + +export default function Provider() { + const [open, setOpen] = useState(false); + const theme = useTheme(); + const fullScreen = useMediaQuery(theme.breakpoints.down('md')); + + const { data: availableProviders } = useFetchProvidersQuery({}); + + const handleClickOpen = () => { + setOpen(true); + }; + + const handleClose = () => { + setOpen(false); + }; + + return ( + <Fragment> + <ProviderLayout> + <MesheryLogo + src="/static/img/meshery-logo/meshery-logo-light-text.png" + alt="meshery logo" + /> + <Typography variant="h6" sx={{ fontWeight: 700 }} gutterBottom> + Please choose a + <Tooltip + title="Learn more about providers" + arrow + placement="bottom" + data-cy="providers-tooltip" + sx={{ + color: '#00B39F', + cursor: 'pointer', + fontWeight: 700, + }} + > + <Link + onClick={handleClickOpen} + underline="none" + sx={{ + color: 'darkcyan', + cursor: 'pointer', + fontWeight: 700, + }} + > + {' '} + provider{' '} + </Link> + </Tooltip> + </Typography> + <MesheryDialog + fullScreen={fullScreen} + open={open} + onClick={handleClose} + aria-labelledby="dialog-title" + disableScrollLock={true} + data-cy="providers-modal" + > + <MesheryDialogTitle id="dialog-title" onClose={handleClose}> + Choosing a provider + </MesheryDialogTitle> + <DialogContent dividers> + <DialogContentText> + <Typography paragraph gutterBottom> + Login to Meshery by choosing from the available providers. Providers offer + authentication, session management and long-term persistence of user preferences, + performance tests, service mesh adapter configurations and so on. + </Typography> + {availableProviders != null && + Object.keys(availableProviders).map((key) => { + const provider = availableProviders[key]; + + return ( + <Fragment key={provider?.provider_name}> + <p style={{ fontWeight: 700 }}>{provider?.provider_name}</p> + <ul> + {provider?.provider_description?.map((desc, i) => ( + <li key={`desc-${i}`}>{String(desc)}</li> + ))} + </ul> + </Fragment> + ); + })} + {content.map((section, index) => ( + <div key={index}> + <Typography variant="body1" fontWeight={700}> + {section.title} + </Typography> + <List dense> + {section.items.map((item, itemIndex) => ( + <ListItem disablePadding key={itemIndex}> + <ListItemText primary={item} /> + </ListItem> + ))} + </List> + </div> + ))} + </DialogContentText> + </DialogContent> + <DialogActions> + <Button + autoFocus + onClick={handleClose} + color="primary" + variant="contained" + data-cy="providers-modal-button-ok" + > + OK + </Button> + </DialogActions> + </MesheryDialog> + <ProviderOptions /> + </ProviderLayout> + <ProviderFooter /> + </Fragment> + ); +} + +function ProviderOptions() { + const dispatch = useDispatch(); + const availableProviders = useSelector(selectProviders); + + useEffect(() => { + dispatch(fetchProviders()) + .unwrap() + .catch((error) => { + console.log('Error fetching providers:', error); + }); + }, [dispatch]); + + const [isLoading, setIsLoading] = useState(false); + const [open, setOpen] = useState(false); + const anchorRef = useRef(null); + + const handleClick = () => { + console.log('clicked!'); + }; + + const handleToggle = () => { + setOpen((prevOpen) => !prevOpen); + }; + + const handleMenuItemClick = (event, provider) => { + event.preventDefault(); + void dispatch(setSelectedProvider(provider)); + setIsLoading(true); + window.location.href = `/api/provider?provider=${encodeURIComponent(provider)}`; + }; + + const handleClose = (event) => { + if (anchorRef.current?.contains(event.target) ?? false) { + return; + } + + setOpen(false); + }; + + return ( + <Box + sx={(theme) => ({ + width: '60%', + marginLeft: 'auto', + marginRight: 'auto', + marginTop: theme.spacing(4), + })} + > + <ButtonGroup variant="contained" color="primary" ref={anchorRef} aria-label="provider button"> + <Button size="large" onClick={handleClick}> + Select a Provider + </Button> + <Button + size="large" + aria-controls={open ? 'split-button-menu' : undefined} + aria-expanded={open ? 'true' : undefined} + aria-label="select provider" + aria-haspopup="menu" + onClick={handleToggle} + > + {isLoading && <CircularProgress />} + {selectProviders !== '' ? selectProviders : 'Select your provider'} + <ArrowDropDown /> + </Button> + </ButtonGroup> + <Popper + sx={{ + zIndex: 1, + }} + open={open} + anchorEl={anchorRef.current} + transition + disablePortal + > + {({ TransitionProps, placement }) => ( + <Grow + {...TransitionProps} + style={{ + transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom', + }} + > + <Paper> + <ClickAwayListener onClickAway={handleClose}> + <MenuList id="split-button-menu" autoFocusItem> + {availableProviders != null && + Object.keys(availableProviders).map((key) => ( + <MenuItem + key={key} + onClick={(e) => { + handleMenuItemClick(e, key); + }} + > + {key} + </MenuItem> + ))} + {isLoading && ( + <Fragment> + <Divider sx={{ my: 0.5 }} /> + {disabledMenuItems.map((item) => ( + <MenuProviderDisabled disabled={true} key={item.key}> + {item.text} + {'\u00A0'} <span>Disabled</span> + </MenuProviderDisabled> + ))} + </Fragment> + )} + {!isLoading && ( + <Fragment> + <Divider sx={{ my: 0.5 }} /> + {disabledMenuItems.map((item) => ( + <MenuProviderDisabled disabled={true} key={item.key}> + {item.text} + {'\u00A0'} <span>Disabled</span> + </MenuProviderDisabled> + ))} + </Fragment> + )} + </MenuList> + </ClickAwayListener> + </Paper> + </Grow> + )} + </Popper> + </Box> + ); +} diff --git a/examples/next-14/components/ProviderLogin/layout.jsx b/examples/next-14/components/ProviderLogin/layout.jsx new file mode 100644 index 00000000..52927829 --- /dev/null +++ b/examples/next-14/components/ProviderLogin/layout.jsx @@ -0,0 +1,12 @@ +import { Paper } from '@layer5/sistent'; +import React from 'react'; + +export default function ProviderLayout({ children }) { + return ( + <React.Fragment> + <Paper elevation={2} sx={{ padding: '170px 0px', minWidth: '90%', textAlign: 'center' }}> + {children} + </Paper> + </React.Fragment> + ); +} diff --git a/examples/next-14/components/ProviderLogin/styles.jsx b/examples/next-14/components/ProviderLogin/styles.jsx new file mode 100644 index 00000000..58214e83 --- /dev/null +++ b/examples/next-14/components/ProviderLogin/styles.jsx @@ -0,0 +1,47 @@ +import { Dialog, DialogTitle, IconButton, MenuItem } from '@layer5/sistent'; +import { Close } from '@mui/icons-material'; +import { styled } from '@mui/material'; + +export const MesheryLogo = styled('img')(({ theme }) => ({ + width: theme.spacing(50), + maxWidth: '100%', + height: 'auto', +})); + +export const MesheryDialog = styled(Dialog)(({ theme }) => ({ + '& .MuiDialogContent-root': { + padding: theme.spacing(2), + }, + '& .MuiDialogActions-root': { + padding: theme.spacing(1), + }, +})); + +export const MenuProviderDisabled = styled(MenuItem)(() => ({ + display: 'flex', + justifyContent: 'space-between', +})); + +export function MesheryDialogTitle(props) { + const { children, onClose, ...other } = props; + + return ( + <DialogTitle sx={{ m: 0, p: 2 }} {...other}> + {children} + {onClose ? ( + <IconButton + aria-label="close" + onClick={onClose} + sx={{ + position: 'absolute', + right: 8, + top: 8, + color: (theme) => theme.palette.grey[500], + }} + > + <Close /> + </IconButton> + ) : null} + </DialogTitle> + ); +} diff --git a/examples/next-14/components/UploadImport/index.jsx b/examples/next-14/components/UploadImport/index.jsx new file mode 100644 index 00000000..014e044f --- /dev/null +++ b/examples/next-14/components/UploadImport/index.jsx @@ -0,0 +1,229 @@ +import { promisifiedDataFetch } from '@/utils/dataFetch'; +import { urlValidator } from '@/utils/urlValidator'; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Divider, + Grid, + TextField, + Typography, +} from '@layer5/sistent'; +import NativeSelect from '@mui/material/NativeSelect'; +import React from 'react'; + +export function UploadImport() { + const { handleUpload, handleUrlUpload, configuration, isFilter, open, handleClose, fetch } = + props; + const [input, setInput] = React.useState(''); + const [name, setName] = React.useState(''); + const [config, setConfig] = React.useState(''); + const [isError, setIsError] = React.useState(false); + const [fileType, setFileType] = React.useState(); + const [sourceType, setSourceType] = React.useState(); + const [supportedTypes, setSupportedTypes] = React.useState(); + const isDesign = configuration === 'patterns'; + + React.useEffect(() => { + if (isDesign) { + (async () => { + setSupportedTypes(await promisifiedDataFetch('/api/pattern/types')); + })(); + } + }, []); + + const handleFileType = (index) => { + if (isDesign) { + setFileType(supportedTypes?.[index]?.supported_extensions); + setSourceType(supportedTypes?.[index]?.design_type); + } + }; + + React.useEffect(() => { + if (input) { + setIsError(!urlValidator(input)); + } + }, [input]); + + React.useEffect(() => { + if (isDesign) { + setFileType(supportedTypes?.[0]?.supported_extensions); + setSourceType(supportedTypes?.[0]?.design_type); + } + }, [open]); + + const handleSubmit = async () => { + await handleUrlUpload(input, sourceType, { name, config }); + handleClose(); + }; + + const handleUploader = async (input) => { + await handleUpload(input, sourceType, { name, config }); + fetch?.(); + handleClose(); + }; + + return ( + <> + <label htmlFor="url-upload-button"> + <Dialog open={open} onClose={handleClose}> + <DialogTitle> + <b id="simple-modal-title" style={{ textAlign: 'center' }}> + Import {configuration} + </b> + </DialogTitle> + <DialogContent> + <Grid container spacing={24} alignItems="center"> + <Grid item xs={3}> + <h4>Name</h4> + </Grid> + <Grid item xs={9}> + <TextField + required + size="small" + variant="outlined" + label="Name" + style={{ width: '100%' }} + onChange={(e) => setName(e.target.value)} + /> + </Grid> + {isFilter && ( + <> + <Grid container spacing={24} alignItems="center"> + <Grid item xs={3}> + <h4>WASM Config</h4> + </Grid> + <Grid item xs={9}> + <TextField + placeholder="" + multiline + required + minRows={4} + size="small" + variant="outlined" + label="WASM Filter Config" + style={{ width: '100%' }} + onChange={(e) => setConfig(e.target.value)} + /> + </Grid> + </Grid> + <br /> + </> + )} + <Grid item xs={12}> + <Divider style={{ margin: '8px 0px' }} /> + </Grid> + <Grid item xs={3}> + <h4>FROM URL</h4> + </Grid> + <Grid item xs={9}> + <TextField + size="small" + error={isError} + helperText={isError && 'Invalid URL'} + variant="outlined" + label={`URL for ${configuration}`} + style={{ width: '100%' }} + onChange={(e) => setInput(e.target.value)} + /> + </Grid> + </Grid> + {isFilter && ( + <div + style={{ + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + }} + > + <Typography variant="caption">---OR---</Typography> + </div> + )} + {sourceType !== 'Helm Chart' && ( + <Grid container spacing={24} alignItems="center"> + <Grid item xs={3}> + <h4>UPLOAD FILE</h4> + </Grid> + <Grid item xs={6}> + <TextField + size="small" + variant="outlined" + label="Filename" + style={{ width: '100%' }} + /> + </Grid> + <Grid item xs={3}> + <label htmlFor="upload-button"> + <Button + disabled={sourceType === 'Helm Chart'} + variant="contained" + aria-label="Upload Button" + onChange={sourceType === 'Helm Chart' ? null : handleUploader} + component="span" + > + <input + id="upload-button" + type="file" + accept={fileType} + disabled={sourceType === 'Helm Chart'} + hidden + name="upload-button" + /> + Browse + </Button> + </label> + </Grid> + </Grid> + )} + + <Grid container spacing={24} alignItems="center"> + {isDesign && <h4>SELECT TYPE</h4>} + {isDesign && ( + <> + <NativeSelect + defaultValue={0} + onChange={(e) => handleFileType(e.target.value)} + inputProps={{ + name: 'name', + id: 'uncontrolled-native', + }} + > + {supportedTypes?.map((type, index) => ( + <option key={index} value={index}> + {type.design_type} + </option> + ))} + </NativeSelect> + </> + )} + </Grid> + </DialogContent> + <DialogActions> + <label htmlFor="cancel"> + <Button variant="outlined" color="secondary" onClick={handleClose}> + Cancel + </Button> + </label> + <label htmlFor="URL"> + <Button + id="URL" + disabled={isError || !input} + variant="contained" + onClick={async (e) => { + await handleSubmit(e, handleUploader); + fetch?.(); + }} + > + Import + </Button> + </label> + </DialogActions> + </Dialog> + </label> + </> + ); +} + +export default UploadImport; diff --git a/examples/next-14/components/Validation/index.jsx b/examples/next-14/components/Validation/index.jsx new file mode 100644 index 00000000..fdd4663a --- /dev/null +++ b/examples/next-14/components/Validation/index.jsx @@ -0,0 +1,108 @@ +import { Divider, List, ListItem, ListSubheader, Typography } from '@layer5/sistent'; +import Collapse from '@mui/material/Collapse'; +import ListItemText from '@mui/material/ListItemText'; +import React from 'react'; + +export function Validation({ errors, compCount, handleClose }) { + const [open, setOpen] = React.useState([false]); + + const handleClick = (index) => { + let updatedState = [...open]; + updatedState[index] = !updatedState[index]; + setOpen(updatedState); + }; + let errorCount = + errors?.reduce((count, ele) => { + return ele.errors.length + count; + }, 0) || 0; + + return ( + <List + aria-labelledby="nested-list-subheader" + subheader={ + <ListSubheader + component="div" + id="nested-list-subheader" + sx={{ display: 'flex', justifyContent: 'space-around' }} + > + <Typography variant="h6" sx={{ position: 'relative', left: '35px' }}> + {compCount} component{compCount > 1 ? 's' : ''} + { + <Divider + style={{ + transform: 'rotate(90deg)', + width: '33%', + top: '-10px', + position: 'relative', + left: '120px', + }} + /> + } + </Typography> + <Typography + variant="h6" + sx={{ + position: 'relative', + left: '-50px', + borderRadius: '0.4rem', + padding: '0.5rem', + top: '-0.45rem', + border: `2px solid ${errorCount > 0 ? '#F0A303' : '#3fc6b6'}`, + color: `${errorCount > 0 ? '#F0A303' : '#3fc6b6'}`, + }} + > + error{errorCount > 1 ? 's' : ''}: {errorCount} + </Typography> + </ListSubheader> + } + style={{ width: '100%', maxHeight: '18rem' }} + > + {errors?.length > 0 ? ( + errors?.map((err, index) => ( + <div style={{ margin: '0.6rem 0rem' }} key={index}> + <ListItem + button + onClick={() => handleClick(index)} + sx={{ backgroundColor: 'transparent' }} + > + <ListItemText primary={err?.service} />({err?.errors.length}) + {open[index] ? <ExpandLess /> : <ExpandMore />} + </ListItem> + <Collapse + in={open[index]} + timeout="auto" + unmountOnExit + onClick={() => { + handleClose(); + // err.openRJSF(); + }} + > + {err?.errors.map((description, index) => ( + <Typography + variant="subtitle2" + sx={{ + padding: '8px', + backgroundColor: '#e0e0e0', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + }} + key={index} + > + {description?.charAt(0).toUpperCase() + description?.slice(1)} + {index !== err?.errors.length - 1 ? ', ' : ''} + </Typography> + ))} + </Collapse> + </div> + )) + ) : ( + <Typography variant="h6" align="center"> + No Validation errors. + </Typography> + )} + </List> + ); +} + +export default Validation; diff --git a/examples/next-14/components/graphql/mutations/AdapterStatusMutation.js b/examples/next-14/components/graphql/mutations/AdapterStatusMutation.js new file mode 100644 index 00000000..cc6f3ef2 --- /dev/null +++ b/examples/next-14/components/graphql/mutations/AdapterStatusMutation.js @@ -0,0 +1,26 @@ +import { graphql, commitMutation } from 'react-relay'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function changeAdapterState(onComplete, variables) { + const environment = createRelayEnvironment({}); + const vars = { + input: { + targetStatus: variables.status, + targetPort: variables.targetPort, + adapter: variables.adapter, + }, + }; + + const adapterStatusMutation = graphql` + mutation AdapterStatusMutation($input: AdapterStatusInput) { + adapterStatus: changeAdapterStatus(input: $input) + } + `; + + commitMutation(environment, { + mutation: adapterStatusMutation, + variables: vars, + onCompleted: onComplete, + onError: (error) => console.log(`An error occured:`, error), + }); +} diff --git a/examples/next-14/components/graphql/mutations/OperatorStatusMutation.js b/examples/next-14/components/graphql/mutations/OperatorStatusMutation.js new file mode 100644 index 00000000..1b6d3680 --- /dev/null +++ b/examples/next-14/components/graphql/mutations/OperatorStatusMutation.js @@ -0,0 +1,22 @@ +import { graphql, commitMutation } from 'react-relay'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function changeOperatorState(onComplete, variables) { + const environment = createRelayEnvironment({}); + const vars = { + input: { targetStatus: variables.status, contextID: variables.contextID }, + }; + + const operatorStatusMutation = graphql` + mutation OperatorStatusMutation($input: OperatorStatusInput) { + operatorStatus: changeOperatorStatus(input: $input) + } + `; + + commitMutation(environment, { + mutation: operatorStatusMutation, + variables: vars, + onCompleted: onComplete, + onError: (error) => console.log(`An error occured:`, error), + }); +} diff --git a/examples/next-14/components/graphql/mutations/__generated__/AdapterStatusMutation.graphql.js b/examples/next-14/components/graphql/mutations/__generated__/AdapterStatusMutation.graphql.js new file mode 100644 index 00000000..d73ea8ad --- /dev/null +++ b/examples/next-14/components/graphql/mutations/__generated__/AdapterStatusMutation.graphql.js @@ -0,0 +1,64 @@ +/** + * @generated SignedSource<<aff6f55dc556ea8dcf170a9dd4d5853b>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": "adapterStatus", + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "kind": "ScalarField", + "name": "changeAdapterStatus", + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "AdapterStatusMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "AdapterStatusMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "910bac5b935be9f44edf2e0b45186c89", + "id": null, + "metadata": {}, + "name": "AdapterStatusMutation", + "operationKind": "mutation", + "text": "mutation AdapterStatusMutation(\n $input: AdapterStatusInput\n) {\n adapterStatus: changeAdapterStatus(input: $input)\n}\n" + } +}; +})(); + +node.hash = "3d97311fb835925f575991945093af8e"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/mutations/__generated__/OperatorStatusMutation.graphql.js b/examples/next-14/components/graphql/mutations/__generated__/OperatorStatusMutation.graphql.js new file mode 100644 index 00000000..f2b279f4 --- /dev/null +++ b/examples/next-14/components/graphql/mutations/__generated__/OperatorStatusMutation.graphql.js @@ -0,0 +1,64 @@ +/** + * @generated SignedSource<<f97047255e02327cdd44fbcb3090b49c>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": "operatorStatus", + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "kind": "ScalarField", + "name": "changeOperatorStatus", + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "OperatorStatusMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "OperatorStatusMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "86d68e3b96cd8684338daf88a6f49ab5", + "id": null, + "metadata": {}, + "name": "OperatorStatusMutation", + "operationKind": "mutation", + "text": "mutation OperatorStatusMutation(\n $input: OperatorStatusInput\n) {\n operatorStatus: changeOperatorStatus(input: $input)\n}\n" + } +}; +})(); + +node.hash = "fc306fe156aa1a0f9984281666bd7693"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/AddonsStatusQuery.js b/examples/next-14/components/graphql/queries/AddonsStatusQuery.js new file mode 100644 index 00000000..9572f5f2 --- /dev/null +++ b/examples/next-14/components/graphql/queries/AddonsStatusQuery.js @@ -0,0 +1,17 @@ +import { fetchQuery, graphql } from 'relay-runtime'; +import { createRelayEnvironment } from '@/lib/relay/RelayEnvironment'; + +export default function fetchAvailableAddons(variables) { + const environment = createRelayEnvironment({}); + const vars = { filter: variables }; + + const AddonsStatusQueryNode = graphql` + query AddonsStatusQuery($filter: ServiceMeshFilter) { + addonsState: getAvailableAddons(filter: $filter) { + name + owner + } + } + `; + return fetchQuery(environment, AddonsStatusQueryNode, vars); +} diff --git a/examples/next-14/components/graphql/queries/CatalogFilterQuery.js b/examples/next-14/components/graphql/queries/CatalogFilterQuery.js new file mode 100644 index 00000000..5e6a401f --- /dev/null +++ b/examples/next-14/components/graphql/queries/CatalogFilterQuery.js @@ -0,0 +1,24 @@ +import { fetchQuery, graphql } from 'relay-runtime'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function fetchCatalogFilter(variables) { + const environment = createRelayEnvironment({}); + + const CatalogFilterQueryNode = graphql` + query CatalogFilterQuery($selector: CatalogSelector!) { + catalogFilters: fetchFilterCatalogContent(selector: $selector) { + id + name + user_id + filter_file + filter_resource + visibility + catalog_data + created_at + updated_at + } + } + `; + + return fetchQuery(environment, CatalogFilterQueryNode, variables); +} diff --git a/examples/next-14/components/graphql/queries/CatalogPatternQuery.js b/examples/next-14/components/graphql/queries/CatalogPatternQuery.js new file mode 100644 index 00000000..d33db6d8 --- /dev/null +++ b/examples/next-14/components/graphql/queries/CatalogPatternQuery.js @@ -0,0 +1,23 @@ +import { fetchQuery, graphql } from 'relay-runtime'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function fetchCatalogPattern(variables) { + const environment = createRelayEnvironment({}); + + const CatalogPatternQueryNode = graphql` + query CatalogPatternQuery($selector: CatalogSelector!) { + catalogPatterns: fetchPatternCatalogContent(selector: $selector) { + id + name + user_id + pattern_file + visibility + catalog_data + created_at + updated_at + } + } + `; + + return fetchQuery(environment, CatalogPatternQueryNode, variables); +} diff --git a/examples/next-14/components/graphql/queries/ControlPlanesQuery.js b/examples/next-14/components/graphql/queries/ControlPlanesQuery.js new file mode 100644 index 00000000..f21e66ce --- /dev/null +++ b/examples/next-14/components/graphql/queries/ControlPlanesQuery.js @@ -0,0 +1,23 @@ +import { fetchQuery, graphql } from 'react-relay'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function fetchControlPlanes(variables) { + const environment = createRelayEnvironment({}); + const vars = { filter: variables }; + + const ControlPlanesQueryNode = graphql` + query ControlPlanesQuery($filter: ServiceMeshFilter) { + controlPlanesState: getControlPlanes(filter: $filter) { + name + members { + name + version + component + namespace + } + } + } + `; + + return fetchQuery(environment, ControlPlanesQueryNode, vars); +} diff --git a/examples/next-14/components/graphql/queries/DataPlanesQuery.js b/examples/next-14/components/graphql/queries/DataPlanesQuery.js new file mode 100644 index 00000000..5efcd9a5 --- /dev/null +++ b/examples/next-14/components/graphql/queries/DataPlanesQuery.js @@ -0,0 +1,41 @@ +import { fetchQuery, graphql } from 'react-relay'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function fetchDataPlanes(variables) { + const environment = createRelayEnvironment({}); + const vars = { + filter: variables, + }; + + const DataPlanesQueryNode = graphql` + query DataPlanesQuery($filter: ServiceMeshFilter) { + dataPlanesState: getDataPlanes(filter: $filter) { + name + proxies { + controlPlaneMemberName + containerName + image + status { + containerStatusName + image + state + lastState + ready + restartCount + started + imageID + containerID + } + ports { + name + containerPort + protocol + } + resources + } + } + } + `; + + return fetchQuery(environment, DataPlanesQueryNode, vars); +} diff --git a/examples/next-14/components/graphql/queries/FetchAllResultsQuery.js b/examples/next-14/components/graphql/queries/FetchAllResultsQuery.js new file mode 100644 index 00000000..d9c0d305 --- /dev/null +++ b/examples/next-14/components/graphql/queries/FetchAllResultsQuery.js @@ -0,0 +1,32 @@ +import { fetchQuery, graphql } from 'react-relay'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function fetchAllResults(variables) { + const environment = createRelayEnvironment({}); + const vars = { selector: variables.selector }; + + const FetchAllResultsQueryNode = graphql` + query FetchAllResultsQuery($selector: PageFilter!) { + fetchAllResults(selector: $selector) { + page + page_size + total_count + results { + meshery_id + name + mesh + performance_profile + test_id + server_metrics + test_start_time + created_at + user_id + updated_at + runner_results + } + } + } + `; + + return fetchQuery(environment, FetchAllResultsQueryNode, vars); +} diff --git a/examples/next-14/components/graphql/queries/MeshModelSummaryQuery.js b/examples/next-14/components/graphql/queries/MeshModelSummaryQuery.js new file mode 100644 index 00000000..8ea71107 --- /dev/null +++ b/examples/next-14/components/graphql/queries/MeshModelSummaryQuery.js @@ -0,0 +1,26 @@ +import { fetchQuery, graphql } from 'react-relay'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +// not in use +export default function fetchMeshModelSummary(selector) { + const environment = createRelayEnvironment({}); + + const vars = { selector: selector }; + + const MeshModelSummaryQueryNode = graphql` + query MeshModelSummaryQuery($selector: MeshModelSummarySelector!) { + meshmodelSummary: getMeshModelSummary(selector: $selector) { + components { + name + count + } + relationships { + name + count + } + } + } + `; + + return fetchQuery(environment, MeshModelSummaryQueryNode, vars); +} diff --git a/examples/next-14/components/graphql/queries/MeshsyncStatusQuery.js b/examples/next-14/components/graphql/queries/MeshsyncStatusQuery.js new file mode 100644 index 00000000..bef1a241 --- /dev/null +++ b/examples/next-14/components/graphql/queries/MeshsyncStatusQuery.js @@ -0,0 +1,18 @@ +import { fetchQuery, graphql } from 'react-relay'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function MeshsyncStatusQuery(vars = { connectionID: vars.connectionID }) { + const environment = createRelayEnvironment({}); + + const MeshsyncStatusQueryNode = graphql` + query MeshsyncStatusQuery($connectionID: String!) { + controller: getMeshsyncStatus(connectionID: $connectionID) { + name + version + status + } + } + `; + + return fetchQuery(environment, MeshsyncStatusQueryNode, vars); +} diff --git a/examples/next-14/components/graphql/queries/NamespaceQuery.js b/examples/next-14/components/graphql/queries/NamespaceQuery.js new file mode 100644 index 00000000..31b29987 --- /dev/null +++ b/examples/next-14/components/graphql/queries/NamespaceQuery.js @@ -0,0 +1,16 @@ +import { fetchQuery, graphql } from 'react-relay'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function fetchAvailableNamespaces(vars) { + const environment = createRelayEnvironment({}); + + const NamespaceQueryNode = graphql` + query NamespaceQuery($k8sClusterIDs: [String!]) { + namespaces: getAvailableNamespaces(k8sClusterIDs: $k8sClusterIDs) { + namespace + } + } + `; + + return fetchQuery(environment, NamespaceQueryNode, vars); +} diff --git a/examples/next-14/components/graphql/queries/NatsStatusQuery.js b/examples/next-14/components/graphql/queries/NatsStatusQuery.js new file mode 100644 index 00000000..79963e98 --- /dev/null +++ b/examples/next-14/components/graphql/queries/NatsStatusQuery.js @@ -0,0 +1,18 @@ +import { fetchQuery, graphql } from 'react-relay'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function NatsStatusQuery(vars) { + const environment = createRelayEnvironment({}); + + const NatsStatusQueryNode = graphql` + query NatsStatusQuery($connectionID: String!) { + controller: getNatsStatus(connectionID: $connectionID) { + name + version + status + } + } + `; + + return fetchQuery(environment, NatsStatusQueryNode, vars); +} diff --git a/examples/next-14/components/graphql/queries/OperatorStatusQuery.js b/examples/next-14/components/graphql/queries/OperatorStatusQuery.js new file mode 100644 index 00000000..1dacbe3a --- /dev/null +++ b/examples/next-14/components/graphql/queries/OperatorStatusQuery.js @@ -0,0 +1,19 @@ +import { fetchQuery, graphql } from 'react-relay'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function fetchMesheryOperatorStatus(variables) { + const environment = createRelayEnvironment({}); + const vars = { k8scontextID: variables.k8scontextID }; + + const OperatorStatusQueryNode = graphql` + query OperatorStatusQuery($k8scontextID: String!) { + operator: getOperatorStatus(k8scontextID: $k8scontextID) { + status + controller + contextId + } + } + `; + + return fetchQuery(environment, OperatorStatusQueryNode, vars); +} diff --git a/examples/next-14/components/graphql/queries/PerformanceProfilesQuery.js b/examples/next-14/components/graphql/queries/PerformanceProfilesQuery.js new file mode 100644 index 00000000..4f15f692 --- /dev/null +++ b/examples/next-14/components/graphql/queries/PerformanceProfilesQuery.js @@ -0,0 +1,39 @@ +import { fetchQuery, graphql } from 'react-relay'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function fetchPerformanceProfiles(variables) { + const environment = createRelayEnvironment({}); + const vars = { selector: variables.selector }; + + const PerformanceProfilesQueryNode = graphql` + query PerformanceProfilesQuery($selector: PageFilter!) { + getPerformanceProfiles(selector: $selector) { + page + page_size + total_count + profiles { + concurrent_request + created_at + duration + endpoints + id + last_run + load_generators + name + qps + total_results + updated_at + user_id + request_body + request_cookies + request_headers + content_type + service_mesh + metadata + } + } + } + `; + + return fetchQuery(environment, PerformanceProfilesQueryNode, vars); +} diff --git a/examples/next-14/components/graphql/queries/PerformanceResultQuery.js b/examples/next-14/components/graphql/queries/PerformanceResultQuery.js new file mode 100644 index 00000000..a08f925b --- /dev/null +++ b/examples/next-14/components/graphql/queries/PerformanceResultQuery.js @@ -0,0 +1,32 @@ +import { fetchQuery, graphql } from 'react-relay'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function fetchPerformanceResults(variables) { + const environment = createRelayEnvironment({}); + const vars = { selector: variables.selector, profileID: variables.profileID }; + + const PerformanceResultQueryNode = graphql` + query PerformanceResultQuery($selector: PageFilter!, $profileID: String!) { + fetchResults(selector: $selector, profileID: $profileID) { + page + page_size + total_count + results { + meshery_id + name + mesh + performance_profile + test_id + server_metrics + test_start_time + created_at + user_id + updated_at + runner_results + } + } + } + `; + + return fetchQuery(environment, PerformanceResultQueryNode, vars); +} diff --git a/examples/next-14/components/graphql/queries/ResetDatabaseQuery.js b/examples/next-14/components/graphql/queries/ResetDatabaseQuery.js new file mode 100644 index 00000000..37340a92 --- /dev/null +++ b/examples/next-14/components/graphql/queries/ResetDatabaseQuery.js @@ -0,0 +1,18 @@ +import { fetchQuery, graphql } from 'react-relay'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function resetDatabase(variables) { + const environment = createRelayEnvironment({}); + const vars = { + selector: variables.selector, + k8scontextID: variables.k8scontextID, + }; + + const ResetDatabaseQueryNode = graphql` + query ResetDatabaseQuery($selector: ReSyncActions!, $k8scontextID: String!) { + resetStatus: resyncCluster(selector: $selector, k8scontextID: $k8scontextID) + } + `; + + return fetchQuery(environment, ResetDatabaseQueryNode, vars); +} diff --git a/examples/next-14/components/graphql/queries/TelemetryComponentsQuery.js b/examples/next-14/components/graphql/queries/TelemetryComponentsQuery.js new file mode 100644 index 00000000..a6502cd1 --- /dev/null +++ b/examples/next-14/components/graphql/queries/TelemetryComponentsQuery.js @@ -0,0 +1,17 @@ +import { fetchQuery, graphql } from 'react-relay'; +import { createRelayEnvironment } from '../../../lib/relayEnvironment'; + +export default function fetchTelemetryCompsQuery(variables) { + const environment = createRelayEnvironment({}); + + const TelemetryComponentsQueryNode = graphql` + query TelemetryComponentsQuery($contexts: [String!]) { + telemetryComps: fetchTelemetryComponents(contexts: $contexts) { + name + spec + status + } + } + `; + return fetchQuery(environment, TelemetryComponentsQueryNode, variables); +} diff --git a/examples/next-14/components/graphql/queries/__generated__/AddonsStatusQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/AddonsStatusQuery.graphql.js new file mode 100644 index 00000000..a359d909 --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/AddonsStatusQuery.graphql.js @@ -0,0 +1,82 @@ +/** + * @generated SignedSource<<1282ae0224439164af34f0d4fba4a71a>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "filter" + } +], +v1 = [ + { + "alias": "addonsState", + "args": [ + { + "kind": "Variable", + "name": "filter", + "variableName": "filter" + } + ], + "concreteType": "AddonList", + "kind": "LinkedField", + "name": "getAvailableAddons", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "owner", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "AddonsStatusQuery", + "selections": (v1/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "AddonsStatusQuery", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "49f96950f100465ccdab36e9903b9281", + "id": null, + "metadata": {}, + "name": "AddonsStatusQuery", + "operationKind": "query", + "text": "query AddonsStatusQuery(\n $filter: ServiceMeshFilter\n) {\n addonsState: getAvailableAddons(filter: $filter) {\n name\n owner\n }\n}\n" + } +}; +})(); + +node.hash = "9cbf0a827a321dead7e3e6d0c2e9cbe7"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/__generated__/CatalogFilterQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/CatalogFilterQuery.graphql.js new file mode 100644 index 00000000..9da043c7 --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/CatalogFilterQuery.graphql.js @@ -0,0 +1,131 @@ +/** + * @generated SignedSource<<a07a98dc9791c788442de20f95e19f5d>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "selector" + } +], +v1 = [ + { + "alias": "catalogFilters", + "args": [ + { + "kind": "Variable", + "name": "selector", + "variableName": "selector" + } + ], + "concreteType": "CatalogFilter", + "kind": "LinkedField", + "name": "fetchFilterCatalogContent", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "user_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "filter_file", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "filter_resource", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "visibility", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "catalog_data", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "created_at", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updated_at", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "CatalogFilterQuery", + "selections": (v1/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "CatalogFilterQuery", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "2178c2622b2e672bcf288e1004c939a0", + "id": null, + "metadata": {}, + "name": "CatalogFilterQuery", + "operationKind": "query", + "text": "query CatalogFilterQuery(\n $selector: CatalogSelector!\n) {\n catalogFilters: fetchFilterCatalogContent(selector: $selector) {\n id\n name\n user_id\n filter_file\n filter_resource\n visibility\n catalog_data\n created_at\n updated_at\n }\n}\n" + } +}; +})(); + +node.hash = "391a34d0da3dfd429e7a8a335e07930b"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/__generated__/CatalogPatternQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/CatalogPatternQuery.graphql.js new file mode 100644 index 00000000..53cb69e7 --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/CatalogPatternQuery.graphql.js @@ -0,0 +1,124 @@ +/** + * @generated SignedSource<<250f6fec42f64cdf2df9bd2be3190563>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "selector" + } +], +v1 = [ + { + "alias": "catalogPatterns", + "args": [ + { + "kind": "Variable", + "name": "selector", + "variableName": "selector" + } + ], + "concreteType": "CatalogPattern", + "kind": "LinkedField", + "name": "fetchPatternCatalogContent", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "user_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "pattern_file", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "visibility", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "catalog_data", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "created_at", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updated_at", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "CatalogPatternQuery", + "selections": (v1/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "CatalogPatternQuery", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "5819e3c1959f0e6ce5329f2a222a499d", + "id": null, + "metadata": {}, + "name": "CatalogPatternQuery", + "operationKind": "query", + "text": "query CatalogPatternQuery(\n $selector: CatalogSelector!\n) {\n catalogPatterns: fetchPatternCatalogContent(selector: $selector) {\n id\n name\n user_id\n pattern_file\n visibility\n catalog_data\n created_at\n updated_at\n }\n}\n" + } +}; +})(); + +node.hash = "3662bdbf1b55f72dec9757315e54e8ab"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/__generated__/ControlPlanesQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/ControlPlanesQuery.graphql.js new file mode 100644 index 00000000..bccd5165 --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/ControlPlanesQuery.graphql.js @@ -0,0 +1,109 @@ +/** + * @generated SignedSource<<c7d21a27e2d8edf0e2cc11470bd35a50>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "filter" + } +], +v1 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v2 = [ + { + "alias": "controlPlanesState", + "args": [ + { + "kind": "Variable", + "name": "filter", + "variableName": "filter" + } + ], + "concreteType": "ControlPlane", + "kind": "LinkedField", + "name": "getControlPlanes", + "plural": true, + "selections": [ + (v1/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "ControlPlaneMember", + "kind": "LinkedField", + "name": "members", + "plural": true, + "selections": [ + (v1/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "version", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "component", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "namespace", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ControlPlanesQuery", + "selections": (v2/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ControlPlanesQuery", + "selections": (v2/*: any*/) + }, + "params": { + "cacheID": "2a087a7971334b86b29d478c175cd336", + "id": null, + "metadata": {}, + "name": "ControlPlanesQuery", + "operationKind": "query", + "text": "query ControlPlanesQuery(\n $filter: ServiceMeshFilter\n) {\n controlPlanesState: getControlPlanes(filter: $filter) {\n name\n members {\n name\n version\n component\n namespace\n }\n }\n}\n" + } +}; +})(); + +node.hash = "82f1d5dbf1eec9d253f34bc6b6a7e6f4"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/__generated__/DataPlanesQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/DataPlanesQuery.graphql.js new file mode 100644 index 00000000..b28cc270 --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/DataPlanesQuery.graphql.js @@ -0,0 +1,210 @@ +/** + * @generated SignedSource<<9bbed48895609893de91588cdca94029>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "filter" + } +], +v1 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "image", + "storageKey": null +}, +v3 = [ + { + "alias": "dataPlanesState", + "args": [ + { + "kind": "Variable", + "name": "filter", + "variableName": "filter" + } + ], + "concreteType": "DataPlane", + "kind": "LinkedField", + "name": "getDataPlanes", + "plural": true, + "selections": [ + (v1/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Container", + "kind": "LinkedField", + "name": "proxies", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "controlPlaneMemberName", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "containerName", + "storageKey": null + }, + (v2/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Container_Status", + "kind": "LinkedField", + "name": "status", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "containerStatusName", + "storageKey": null + }, + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "state", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "lastState", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "ready", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "restartCount", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "started", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "imageID", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "containerID", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "Container_Port", + "kind": "LinkedField", + "name": "ports", + "plural": true, + "selections": [ + (v1/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "containerPort", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "protocol", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "resources", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "DataPlanesQuery", + "selections": (v3/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "DataPlanesQuery", + "selections": (v3/*: any*/) + }, + "params": { + "cacheID": "b2b75c4ae9ac1a89e28f4d4454fe6a1f", + "id": null, + "metadata": {}, + "name": "DataPlanesQuery", + "operationKind": "query", + "text": "query DataPlanesQuery(\n $filter: ServiceMeshFilter\n) {\n dataPlanesState: getDataPlanes(filter: $filter) {\n name\n proxies {\n controlPlaneMemberName\n containerName\n image\n status {\n containerStatusName\n image\n state\n lastState\n ready\n restartCount\n started\n imageID\n containerID\n }\n ports {\n name\n containerPort\n protocol\n }\n resources\n }\n }\n}\n" + } +}; +})(); + +node.hash = "972da366246c7024e36e973fb98f27a5"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/__generated__/FetchAllResultsQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/FetchAllResultsQuery.graphql.js new file mode 100644 index 00000000..8517af09 --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/FetchAllResultsQuery.graphql.js @@ -0,0 +1,177 @@ +/** + * @generated SignedSource<<cb2d1ba54f1f01fa667e58282587e036>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "selector" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "selector", + "variableName": "selector" + } + ], + "concreteType": "PerfPageResult", + "kind": "LinkedField", + "name": "fetchAllResults", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "page", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "page_size", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "total_count", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "MesheryResult", + "kind": "LinkedField", + "name": "results", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "meshery_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "mesh", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "performance_profile", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "test_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "server_metrics", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "test_start_time", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "created_at", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "user_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updated_at", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "runner_results", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "FetchAllResultsQuery", + "selections": (v1/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "FetchAllResultsQuery", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "0770a3af73084b2362bfb7bad68fbeb4", + "id": null, + "metadata": {}, + "name": "FetchAllResultsQuery", + "operationKind": "query", + "text": "query FetchAllResultsQuery(\n $selector: PageFilter!\n) {\n fetchAllResults(selector: $selector) {\n page\n page_size\n total_count\n results {\n meshery_id\n name\n mesh\n performance_profile\n test_id\n server_metrics\n test_start_time\n created_at\n user_id\n updated_at\n runner_results\n }\n }\n}\n" + } +}; +})(); + +node.hash = "0aede14fffa5004109535cbff9b07687"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/__generated__/MeshModelSummaryQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/MeshModelSummaryQuery.graphql.js new file mode 100644 index 00000000..ce01bc28 --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/MeshModelSummaryQuery.graphql.js @@ -0,0 +1,104 @@ +/** + * @generated SignedSource<<fc2ef860d09573a73d5b766e731a9d5a>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "selector" + } +], +v1 = [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "count", + "storageKey": null + } +], +v2 = [ + { + "alias": "meshmodelSummary", + "args": [ + { + "kind": "Variable", + "name": "selector", + "variableName": "selector" + } + ], + "concreteType": "MeshModelSummary", + "kind": "LinkedField", + "name": "getMeshModelSummary", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "MeshModelComponent", + "kind": "LinkedField", + "name": "components", + "plural": true, + "selections": (v1/*: any*/), + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "MeshModelRelationship", + "kind": "LinkedField", + "name": "relationships", + "plural": true, + "selections": (v1/*: any*/), + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "MeshModelSummaryQuery", + "selections": (v2/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "MeshModelSummaryQuery", + "selections": (v2/*: any*/) + }, + "params": { + "cacheID": "fb8718ecc59096bb7a68d0479193aaab", + "id": null, + "metadata": {}, + "name": "MeshModelSummaryQuery", + "operationKind": "query", + "text": "query MeshModelSummaryQuery(\n $selector: MeshModelSummarySelector!\n) {\n meshmodelSummary: getMeshModelSummary(selector: $selector) {\n components {\n name\n count\n }\n relationships {\n name\n count\n }\n }\n}\n" + } +}; +})(); + +node.hash = "830ea0f72a52a2f3419b0796d9b3a562"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/__generated__/MeshsyncStatusQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/MeshsyncStatusQuery.graphql.js new file mode 100644 index 00000000..06d4fd55 --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/MeshsyncStatusQuery.graphql.js @@ -0,0 +1,89 @@ +/** + * @generated SignedSource<<89d91dbbc41da00eed2c37155a5b5bed>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "connectionID" + } +], +v1 = [ + { + "alias": "controller", + "args": [ + { + "kind": "Variable", + "name": "connectionID", + "variableName": "connectionID" + } + ], + "concreteType": "OperatorControllerStatus", + "kind": "LinkedField", + "name": "getMeshsyncStatus", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "version", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "MeshsyncStatusQuery", + "selections": (v1/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "MeshsyncStatusQuery", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "1b2cb7cffaec7ee51423e6f26c1e6ae4", + "id": null, + "metadata": {}, + "name": "MeshsyncStatusQuery", + "operationKind": "query", + "text": "query MeshsyncStatusQuery(\n $connectionID: String!\n) {\n controller: getMeshsyncStatus(connectionID: $connectionID) {\n name\n version\n status\n }\n}\n" + } +}; +})(); + +node.hash = "a9ff2d13ffaf332f9be4ca12e09bd7f9"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/__generated__/NamespaceQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/NamespaceQuery.graphql.js new file mode 100644 index 00000000..1e2ba4d6 --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/NamespaceQuery.graphql.js @@ -0,0 +1,75 @@ +/** + * @generated SignedSource<<690faf7517990831cec356b0bf8f28bd>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "k8sClusterIDs" + } +], +v1 = [ + { + "alias": "namespaces", + "args": [ + { + "kind": "Variable", + "name": "k8sClusterIDs", + "variableName": "k8sClusterIDs" + } + ], + "concreteType": "NameSpace", + "kind": "LinkedField", + "name": "getAvailableNamespaces", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "namespace", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "NamespaceQuery", + "selections": (v1/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "NamespaceQuery", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "0e85918419a43e5791cd5a51e7f6896e", + "id": null, + "metadata": {}, + "name": "NamespaceQuery", + "operationKind": "query", + "text": "query NamespaceQuery(\n $k8sClusterIDs: [String!]\n) {\n namespaces: getAvailableNamespaces(k8sClusterIDs: $k8sClusterIDs) {\n namespace\n }\n}\n" + } +}; +})(); + +node.hash = "04f74232907aa0ba765bd0f8db6c427c"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/__generated__/NatsStatusQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/NatsStatusQuery.graphql.js new file mode 100644 index 00000000..738fb8ab --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/NatsStatusQuery.graphql.js @@ -0,0 +1,89 @@ +/** + * @generated SignedSource<<49e3869624d07be085d19ab99c102219>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "connectionID" + } +], +v1 = [ + { + "alias": "controller", + "args": [ + { + "kind": "Variable", + "name": "connectionID", + "variableName": "connectionID" + } + ], + "concreteType": "OperatorControllerStatus", + "kind": "LinkedField", + "name": "getNatsStatus", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "version", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "NatsStatusQuery", + "selections": (v1/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "NatsStatusQuery", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "f232d0001a24e998f5d993786cfed5f6", + "id": null, + "metadata": {}, + "name": "NatsStatusQuery", + "operationKind": "query", + "text": "query NatsStatusQuery(\n $connectionID: String!\n) {\n controller: getNatsStatus(connectionID: $connectionID) {\n name\n version\n status\n }\n}\n" + } +}; +})(); + +node.hash = "10628d273554398f8d127aaa764a94fd"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/__generated__/OperatorStatusQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/OperatorStatusQuery.graphql.js new file mode 100644 index 00000000..c3c12512 --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/OperatorStatusQuery.graphql.js @@ -0,0 +1,89 @@ +/** + * @generated SignedSource<<8db057b6a9f9bea598930f295bc40f58>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "k8scontextID" + } +], +v1 = [ + { + "alias": "operator", + "args": [ + { + "kind": "Variable", + "name": "k8scontextID", + "variableName": "k8scontextID" + } + ], + "concreteType": "MesheryControllersStatusListItem", + "kind": "LinkedField", + "name": "getOperatorStatus", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "controller", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "contextId", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "OperatorStatusQuery", + "selections": (v1/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "OperatorStatusQuery", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "c130db726cf439ef5854c0e9055c6141", + "id": null, + "metadata": {}, + "name": "OperatorStatusQuery", + "operationKind": "query", + "text": "query OperatorStatusQuery(\n $k8scontextID: String!\n) {\n operator: getOperatorStatus(k8scontextID: $k8scontextID) {\n status\n controller\n contextId\n }\n}\n" + } +}; +})(); + +node.hash = "f23b3f72594b73c2a5136019efc1b85a"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/__generated__/PerformanceProfilesQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/PerformanceProfilesQuery.graphql.js new file mode 100644 index 00000000..c3730e41 --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/PerformanceProfilesQuery.graphql.js @@ -0,0 +1,226 @@ +/** + * @generated SignedSource<<58aed683b96a4b759cb5180b0d61e55b>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "selector" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "selector", + "variableName": "selector" + } + ], + "concreteType": "PerfPageProfiles", + "kind": "LinkedField", + "name": "getPerformanceProfiles", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "page", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "page_size", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "total_count", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "PerfProfile", + "kind": "LinkedField", + "name": "profiles", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "concurrent_request", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "created_at", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "duration", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endpoints", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "last_run", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "load_generators", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "qps", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "total_results", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updated_at", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "user_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "request_body", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "request_cookies", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "request_headers", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "content_type", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "service_mesh", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "metadata", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "PerformanceProfilesQuery", + "selections": (v1/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "PerformanceProfilesQuery", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "05fcaffb37eda9d52f8bd45bd8da5550", + "id": null, + "metadata": {}, + "name": "PerformanceProfilesQuery", + "operationKind": "query", + "text": "query PerformanceProfilesQuery(\n $selector: PageFilter!\n) {\n getPerformanceProfiles(selector: $selector) {\n page\n page_size\n total_count\n profiles {\n concurrent_request\n created_at\n duration\n endpoints\n id\n last_run\n load_generators\n name\n qps\n total_results\n updated_at\n user_id\n request_body\n request_cookies\n request_headers\n content_type\n service_mesh\n metadata\n }\n }\n}\n" + } +}; +})(); + +node.hash = "a901902df4422ec63fa999ca605a644b"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/__generated__/PerformanceResultQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/PerformanceResultQuery.graphql.js new file mode 100644 index 00000000..b2e7f5e1 --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/PerformanceResultQuery.graphql.js @@ -0,0 +1,191 @@ +/** + * @generated SignedSource<<9aed7c29919008bbe111bee947e721bf>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "profileID" +}, +v1 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "selector" +}, +v2 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "profileID", + "variableName": "profileID" + }, + { + "kind": "Variable", + "name": "selector", + "variableName": "selector" + } + ], + "concreteType": "PerfPageResult", + "kind": "LinkedField", + "name": "fetchResults", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "page", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "page_size", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "total_count", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "MesheryResult", + "kind": "LinkedField", + "name": "results", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "meshery_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "mesh", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "performance_profile", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "test_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "server_metrics", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "test_start_time", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "created_at", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "user_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updated_at", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "runner_results", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "PerformanceResultQuery", + "selections": (v2/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], + "kind": "Operation", + "name": "PerformanceResultQuery", + "selections": (v2/*: any*/) + }, + "params": { + "cacheID": "cb5e2072afbc31af649ca22bc7e5d4d6", + "id": null, + "metadata": {}, + "name": "PerformanceResultQuery", + "operationKind": "query", + "text": "query PerformanceResultQuery(\n $selector: PageFilter!\n $profileID: String!\n) {\n fetchResults(selector: $selector, profileID: $profileID) {\n page\n page_size\n total_count\n results {\n meshery_id\n name\n mesh\n performance_profile\n test_id\n server_metrics\n test_start_time\n created_at\n user_id\n updated_at\n runner_results\n }\n }\n}\n" + } +}; +})(); + +node.hash = "e42d1c8529e951f7ad055eab6db359b8"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/__generated__/ResetDatabaseQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/ResetDatabaseQuery.graphql.js new file mode 100644 index 00000000..03a29cbc --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/ResetDatabaseQuery.graphql.js @@ -0,0 +1,78 @@ +/** + * @generated SignedSource<<a84076187375aaa2ced461e37f44710e>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "k8scontextID" +}, +v1 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "selector" +}, +v2 = [ + { + "alias": "resetStatus", + "args": [ + { + "kind": "Variable", + "name": "k8scontextID", + "variableName": "k8scontextID" + }, + { + "kind": "Variable", + "name": "selector", + "variableName": "selector" + } + ], + "kind": "ScalarField", + "name": "resyncCluster", + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "ResetDatabaseQuery", + "selections": (v2/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], + "kind": "Operation", + "name": "ResetDatabaseQuery", + "selections": (v2/*: any*/) + }, + "params": { + "cacheID": "37b0c2d517499c337bd4bdfa2ef79380", + "id": null, + "metadata": {}, + "name": "ResetDatabaseQuery", + "operationKind": "query", + "text": "query ResetDatabaseQuery(\n $selector: ReSyncActions!\n $k8scontextID: String!\n) {\n resetStatus: resyncCluster(selector: $selector, k8scontextID: $k8scontextID)\n}\n" + } +}; +})(); + +node.hash = "54a9344cc4d95023f5082936dc95d05d"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/queries/__generated__/TelemetryComponentsQuery.graphql.js b/examples/next-14/components/graphql/queries/__generated__/TelemetryComponentsQuery.graphql.js new file mode 100644 index 00000000..2eb18caa --- /dev/null +++ b/examples/next-14/components/graphql/queries/__generated__/TelemetryComponentsQuery.graphql.js @@ -0,0 +1,89 @@ +/** + * @generated SignedSource<<359e3faf308f403ed9207a13856d700b>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "contexts" + } +], +v1 = [ + { + "alias": "telemetryComps", + "args": [ + { + "kind": "Variable", + "name": "contexts", + "variableName": "contexts" + } + ], + "concreteType": "TelemetryComp", + "kind": "LinkedField", + "name": "fetchTelemetryComponents", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "spec", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "TelemetryComponentsQuery", + "selections": (v1/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "TelemetryComponentsQuery", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "5c359a9d5b083eb5aba9b7bfe49663c9", + "id": null, + "metadata": {}, + "name": "TelemetryComponentsQuery", + "operationKind": "query", + "text": "query TelemetryComponentsQuery(\n $contexts: [String!]\n) {\n telemetryComps: fetchTelemetryComponents(contexts: $contexts) {\n name\n spec\n status\n }\n}\n" + } +}; +})(); + +node.hash = "ec7907a52eb8925b7e063038d08beb85"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/subscriptions/ClusterResourcesSubscription.js b/examples/next-14/components/graphql/subscriptions/ClusterResourcesSubscription.js new file mode 100644 index 00000000..b83e56b4 --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/ClusterResourcesSubscription.js @@ -0,0 +1,26 @@ +import { graphql, requestSubscription } from 'react-relay'; +import { createRelayEnvironment } from '@/lib/relay/RelayEnvironment'; + +export const clusterResourcesSubscription = graphql` + subscription ClusterResourcesSubscription($k8scontextIDs: [String!], $namespace: String!) { + clusterResources: subscribeClusterResources( + k8scontextIDs: $k8scontextIDs + namespace: $namespace + ) { + resources { + kind + count + } + } + } +`; + +export default function subscribeClusterResources(dataCB, variables) { + const environment = createRelayEnvironment({}); + return requestSubscription(environment, { + subscription: clusterResourcesSubscription, + variables: variables, + onNext: dataCB, + onError: (error) => console.log(`Cluster Resources Subscription error:`, error), + }); +} diff --git a/examples/next-14/components/graphql/subscriptions/ConfigurationSubscription.js b/examples/next-14/components/graphql/subscriptions/ConfigurationSubscription.js new file mode 100644 index 00000000..6251934d --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/ConfigurationSubscription.js @@ -0,0 +1,62 @@ +import { graphql, requestSubscription } from 'react-relay'; +import { createRelayEnvironment } from '@/lib/relay/RelayEnvironment'; + +const configurationSubscription = graphql` + subscription ConfigurationSubscription( + $patternSelector: PageFilter! + $filterSelector: PageFilter! + ) { + configuration: subscribeConfiguration( + patternSelector: $patternSelector + filterSelector: $filterSelector + ) { + patterns { + page + page_size + total_count + patterns { + id + name + user_id + pattern_file + visibility + catalog_data + canSupport + errmsg + created_at + updated_at + type { + String + Valid + } + } + } + filters { + page + page_size + total_count + filters { + id + name + filter_file + filter_resource + visibility + catalog_data + user_id + created_at + updated_at + } + } + } + } +`; + +export default function ConfigurationSubscription(onNext, variables) { + const environment = createRelayEnvironment({}); + return requestSubscription(environment, { + subscription: configurationSubscription, + variables: variables, + onNext: onNext, + onError: (error) => console.log('ERROR OCCURED IN CONFIGURATION SUBCRIPTION', error), + }); +} diff --git a/examples/next-14/components/graphql/subscriptions/EventsSubscription.js b/examples/next-14/components/graphql/subscriptions/EventsSubscription.js new file mode 100644 index 00000000..7a58812f --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/EventsSubscription.js @@ -0,0 +1,33 @@ +import { graphql, requestSubscription } from 'react-relay'; +import { createRelayEnvironment } from '@/lib/relay/RelayEnvironment'; + +const eventsSubscription = graphql` + subscription EventsSubscription { + event: subscribeEvents { + id + userID + actedUpon + operationID + systemID + status + severity + action + category + description + metadata + createdAt + updatedAt + deletedAt + } + } +`; + +export default function subscribeEvents(dataCB) { + const environment = createRelayEnvironment({}); + + return requestSubscription(environment, { + subscription: eventsSubscription, + onNext: dataCB, + onError: (error) => console.log(`An error occured:`, error), + }); +} diff --git a/examples/next-14/components/graphql/subscriptions/K8sContextSubscription.js b/examples/next-14/components/graphql/subscriptions/K8sContextSubscription.js new file mode 100644 index 00000000..a202f509 --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/K8sContextSubscription.js @@ -0,0 +1,34 @@ +import { graphql, requestSubscription } from 'relay-runtime'; +import { createRelayEnvironment } from '@/lib/relay/RelayEnvironment'; + +const k8sContextSubscription = graphql` + subscription K8sContextSubscription($selector: PageFilter!) { + k8sContext: subscribeK8sContext(selector: $selector) { + total_count + contexts { + id + name + server + owner + created_by + meshery_instance_id + kubernetes_server_id + deployment_type + updated_at + created_at + version + connection_id + } + } + } +`; + +export default function subscribeK8sContext(dataCB, variables) { + const environment = createRelayEnvironment({}); + return requestSubscription(environment, { + subscription: k8sContextSubscription, + variables: variables, + onNext: dataCB, + onError: (error) => console.log('K8sContextSubscription: An error occured:', error), + }); +} diff --git a/examples/next-14/components/graphql/subscriptions/MeshModelSummarySubscription.js b/examples/next-14/components/graphql/subscriptions/MeshModelSummarySubscription.js new file mode 100644 index 00000000..8b28b732 --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/MeshModelSummarySubscription.js @@ -0,0 +1,28 @@ +import { graphql, requestSubscription } from 'react-relay'; +import { createRelayEnvironment } from '@/lib/relay/RelayEnvironment'; + +// not in use +export const meshmodelSummarySubscription = graphql` + subscription MeshModelSummarySubscription($selector: MeshModelSummarySelector!) { + meshmodelSummary: subscribeMeshModelSummary(selector: $selector) { + components { + name + count + } + relationships { + name + count + } + } + } +`; + +export default function subscribeClusterResources(dataCB, variables) { + const environment = createRelayEnvironment({}); + return requestSubscription(environment, { + subscription: meshmodelSummarySubscription, + variables: variables, + onNext: dataCB, + onError: (error) => console.log(`MeshModel Subscription error:`, error), + }); +} diff --git a/examples/next-14/components/graphql/subscriptions/MeshSyncEventsSubscription.js b/examples/next-14/components/graphql/subscriptions/MeshSyncEventsSubscription.js new file mode 100644 index 00000000..2b720d51 --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/MeshSyncEventsSubscription.js @@ -0,0 +1,28 @@ +import { graphql, requestSubscription } from 'react-relay'; +import { createRelayEnvironment } from '@/lib/relay/RelayEnvironment'; + +const meshSyncEventsSubscription = graphql` + subscription MeshSyncEventsSubscription( + $k8scontextIDs: [String!] + $eventTypes: [MeshSyncEventType!] + ) { + meshsyncevents: subscribeMeshSyncEvents( + k8scontextIDs: $k8scontextIDs + eventTypes: $eventTypes + ) { + type + object + contextId + } + } +`; + +export default function subscribeMeshSyncEvents(dataCB, variables) { + const environment = createRelayEnvironment({}); + return requestSubscription(environment, { + subscription: meshSyncEventsSubscription, + variables: variables, + onNext: dataCB, + onError: (error) => console.log(`An error occured:`, error), + }); +} diff --git a/examples/next-14/components/graphql/subscriptions/MeshSyncStatusSubscription.js b/examples/next-14/components/graphql/subscriptions/MeshSyncStatusSubscription.js new file mode 100644 index 00000000..d4d6731e --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/MeshSyncStatusSubscription.js @@ -0,0 +1,29 @@ +// import { graphql, requestSubscription } from "react-relay"; +// import { createRelayEnvironment } from "@/lib/relay/RelayEnvironment"; + +// const meshSyncStatusSubscription = graphql` +// subscription MeshSyncStatusSubscription($k8scontextIDs: [String!]) { +// listenToMeshSyncEvents(k8scontextIDs: $k8scontextIDs) { +// contextID +// OperatorControllerStatus { +// name +// status +// version +// error { +// code +// description +// } +// } +// } +// } +// `; + +// export default function subscribeMeshSyncStatusEvents(dataCB, contextIds) { +// const environment = createRelayEnvironment({}); +// return requestSubscription(environment, { +// subscription : meshSyncStatusSubscription, +// variables : { k8scontextIDs : contextIds }, +// onNext : dataCB, +// onError : (error) => console.log(`An error occured:`, error), +// }); +// } diff --git a/examples/next-14/components/graphql/subscriptions/MesheryControllersStatusSubscription.js b/examples/next-14/components/graphql/subscriptions/MesheryControllersStatusSubscription.js new file mode 100644 index 00000000..af8461da --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/MesheryControllersStatusSubscription.js @@ -0,0 +1,22 @@ +import { graphql, requestSubscription } from 'react-relay'; +import { createRelayEnvironment } from '@/lib/relay/RelayEnvironment'; + +const mesheryControllersStatusSubscription = graphql` + subscription MesheryControllersStatusSubscription($k8scontextIDs: [String!]) { + subscribeMesheryControllersStatus(k8scontextIDs: $k8scontextIDs) { + contextId + controller + status + } + } +`; + +export default function subscribeMesheryControllersStatus(dataCB, variables) { + const environment = createRelayEnvironment({}); + return requestSubscription(environment, { + subscription: mesheryControllersStatusSubscription, + variables: { k8scontextIDs: variables }, + onNext: dataCB, + onError: (error) => console.log(`An error occured:`, error), + }); +} diff --git a/examples/next-14/components/graphql/subscriptions/OperatorStatusSubscription.js b/examples/next-14/components/graphql/subscriptions/OperatorStatusSubscription.js new file mode 100644 index 00000000..0761c1fc --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/OperatorStatusSubscription.js @@ -0,0 +1,34 @@ +import { graphql, requestSubscription } from 'react-relay'; +import { createRelayEnvironment } from '@/lib/relay/RelayEnvironment'; + +// not in use +const operatorStatusSubscription = graphql` + subscription OperatorStatusSubscription($k8scontextIDs: [String!]) { + operator: listenToOperatorState(k8scontextIDs: $k8scontextIDs) { + contextID + operatorStatus { + status + version + controllers { + name + version + status + } + error { + code + description + } + } + } + } +`; + +export default function subscribeOperatorStatusEvents(dataCB, contextIds) { + const environment = createRelayEnvironment({}); + return requestSubscription(environment, { + subscription: operatorStatusSubscription, + variables: { k8scontextIDs: contextIds }, + onNext: dataCB, + onError: (error) => console.log(`An error occured:`, error), + }); +} diff --git a/examples/next-14/components/graphql/subscriptions/PerformanceProfilesSubscription.js b/examples/next-14/components/graphql/subscriptions/PerformanceProfilesSubscription.js new file mode 100644 index 00000000..8b1e51aa --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/PerformanceProfilesSubscription.js @@ -0,0 +1,41 @@ +import { graphql, requestSubscription } from 'react-relay'; +import { createRelayEnvironment } from '@/lib/relay/RelayEnvironment'; + +const performanceProfilesSubscription = graphql` + subscription PerformanceProfilesSubscription($selector: PageFilter!) { + subscribePerfProfiles(selector: $selector) { + page + page_size + total_count + profiles { + concurrent_request + created_at + duration + endpoints + id + last_run + load_generators + name + qps + total_results + updated_at + user_id + request_body + request_cookies + request_headers + content_type + service_mesh + metadata + } + } + } +`; +export default function subscribePerformanceProfiles(dataCB, variables) { + const environment = createRelayEnvironment({}); + return requestSubscription(environment, { + subscription: performanceProfilesSubscription, + variables: variables, + onNext: dataCB, + onError: (error) => console.log(`requestSubscription error:`, error), + }); +} diff --git a/examples/next-14/components/graphql/subscriptions/PerformanceResultSubscription.js b/examples/next-14/components/graphql/subscriptions/PerformanceResultSubscription.js new file mode 100644 index 00000000..5493cfe4 --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/PerformanceResultSubscription.js @@ -0,0 +1,34 @@ +import { graphql, requestSubscription } from 'react-relay'; +import { createRelayEnvironment } from '@/lib/relay/RelayEnvironment'; + +const performanceResultSubscription = graphql` + subscription PerformanceResultSubscription($selector: PageFilter!, $profileID: String!) { + subscribePerfResults(selector: $selector, profileID: $profileID) { + page + page_size + total_count + results { + meshery_id + name + mesh + performance_profile + test_id + server_metrics + test_start_time + created_at + user_id + updated_at + runner_results + } + } + } +`; +export default function subscribePerformanceProfiles(dataCB, variables) { + const environment = createRelayEnvironment({}); + return requestSubscription(environment, { + subscription: performanceResultSubscription, + variables: variables, + onNext: dataCB, + onError: (error) => console.log(`requestSubscription error:`, error), + }); +} diff --git a/examples/next-14/components/graphql/subscriptions/__generated__/ClusterResourcesSubscription.graphql.js b/examples/next-14/components/graphql/subscriptions/__generated__/ClusterResourcesSubscription.graphql.js new file mode 100644 index 00000000..a82c2869 --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/__generated__/ClusterResourcesSubscription.graphql.js @@ -0,0 +1,103 @@ +/** + * @generated SignedSource<<7e25c5992afac17ee968aebd9882822f>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "k8scontextIDs" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "namespace" + } +], +v1 = [ + { + "alias": "clusterResources", + "args": [ + { + "kind": "Variable", + "name": "k8scontextIDs", + "variableName": "k8scontextIDs" + }, + { + "kind": "Variable", + "name": "namespace", + "variableName": "namespace" + } + ], + "concreteType": "ClusterResources", + "kind": "LinkedField", + "name": "subscribeClusterResources", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Resource", + "kind": "LinkedField", + "name": "resources", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "kind", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "count", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ClusterResourcesSubscription", + "selections": (v1/*: any*/), + "type": "Subscription", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ClusterResourcesSubscription", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "d3c5e48d338830a81ec808ac6acf5d8a", + "id": null, + "metadata": {}, + "name": "ClusterResourcesSubscription", + "operationKind": "subscription", + "text": "subscription ClusterResourcesSubscription(\n $k8scontextIDs: [String!]\n $namespace: String!\n) {\n clusterResources: subscribeClusterResources(k8scontextIDs: $k8scontextIDs, namespace: $namespace) {\n resources {\n kind\n count\n }\n }\n}\n" + } +}; +})(); + +node.hash = "2722cb19adcd7e786a91856efcff3e1c"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/subscriptions/__generated__/ConfigurationSubscription.graphql.js b/examples/next-14/components/graphql/subscriptions/__generated__/ConfigurationSubscription.graphql.js new file mode 100644 index 00000000..49e7bd42 --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/__generated__/ConfigurationSubscription.graphql.js @@ -0,0 +1,276 @@ +/** + * @generated SignedSource<<913da5338e44a21198d54b3ae19dedf4>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "filterSelector" +}, +v1 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "patternSelector" +}, +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "page", + "storageKey": null +}, +v3 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "page_size", + "storageKey": null +}, +v4 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "total_count", + "storageKey": null +}, +v5 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v6 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v7 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "user_id", + "storageKey": null +}, +v8 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "visibility", + "storageKey": null +}, +v9 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "catalog_data", + "storageKey": null +}, +v10 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "created_at", + "storageKey": null +}, +v11 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updated_at", + "storageKey": null +}, +v12 = [ + { + "alias": "configuration", + "args": [ + { + "kind": "Variable", + "name": "filterSelector", + "variableName": "filterSelector" + }, + { + "kind": "Variable", + "name": "patternSelector", + "variableName": "patternSelector" + } + ], + "concreteType": "ConfigurationPage", + "kind": "LinkedField", + "name": "subscribeConfiguration", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "PatternPageResult", + "kind": "LinkedField", + "name": "patterns", + "plural": false, + "selections": [ + (v2/*: any*/), + (v3/*: any*/), + (v4/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "PatternResult", + "kind": "LinkedField", + "name": "patterns", + "plural": true, + "selections": [ + (v5/*: any*/), + (v6/*: any*/), + (v7/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "pattern_file", + "storageKey": null + }, + (v8/*: any*/), + (v9/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "canSupport", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "errmsg", + "storageKey": null + }, + (v10/*: any*/), + (v11/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "NullString", + "kind": "LinkedField", + "name": "type", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "String", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "Valid", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "FilterPage", + "kind": "LinkedField", + "name": "filters", + "plural": false, + "selections": [ + (v2/*: any*/), + (v3/*: any*/), + (v4/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "FilterResult", + "kind": "LinkedField", + "name": "filters", + "plural": true, + "selections": [ + (v5/*: any*/), + (v6/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "filter_file", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "filter_resource", + "storageKey": null + }, + (v8/*: any*/), + (v9/*: any*/), + (v7/*: any*/), + (v10/*: any*/), + (v11/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "ConfigurationSubscription", + "selections": (v12/*: any*/), + "type": "Subscription", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], + "kind": "Operation", + "name": "ConfigurationSubscription", + "selections": (v12/*: any*/) + }, + "params": { + "cacheID": "114d3745286afe9f521748a330799adc", + "id": null, + "metadata": {}, + "name": "ConfigurationSubscription", + "operationKind": "subscription", + "text": "subscription ConfigurationSubscription(\n $patternSelector: PageFilter!\n $filterSelector: PageFilter!\n) {\n configuration: subscribeConfiguration(patternSelector: $patternSelector, filterSelector: $filterSelector) {\n patterns {\n page\n page_size\n total_count\n patterns {\n id\n name\n user_id\n pattern_file\n visibility\n catalog_data\n canSupport\n errmsg\n created_at\n updated_at\n type {\n String\n Valid\n }\n }\n }\n filters {\n page\n page_size\n total_count\n filters {\n id\n name\n filter_file\n filter_resource\n visibility\n catalog_data\n user_id\n created_at\n updated_at\n }\n }\n }\n}\n" + } +}; +})(); + +node.hash = "7aa8cbbbeec029fbf5f68fff16f3888b"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/subscriptions/__generated__/EventsSubscription.graphql.js b/examples/next-14/components/graphql/subscriptions/__generated__/EventsSubscription.graphql.js new file mode 100644 index 00000000..c277811d --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/__generated__/EventsSubscription.graphql.js @@ -0,0 +1,153 @@ +/** + * @generated SignedSource<<a169ec46d9c112ccac643a26fcc5ee66>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "alias": "event", + "args": null, + "concreteType": "Event", + "kind": "LinkedField", + "name": "subscribeEvents", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "userID", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "actedUpon", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "operationID", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "systemID", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "severity", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "action", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "category", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "metadata", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "deletedAt", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "EventsSubscription", + "selections": (v0/*: any*/), + "type": "Subscription", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "EventsSubscription", + "selections": (v0/*: any*/) + }, + "params": { + "cacheID": "dfb0d28db01886a2b8877f52db0fd0c6", + "id": null, + "metadata": {}, + "name": "EventsSubscription", + "operationKind": "subscription", + "text": "subscription EventsSubscription {\n event: subscribeEvents {\n id\n userID\n actedUpon\n operationID\n systemID\n status\n severity\n action\n category\n description\n metadata\n createdAt\n updatedAt\n deletedAt\n }\n}\n" + } +}; +})(); + +node.hash = "b6a9380e1fcb5b6b417ef482bb98ab7b"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/subscriptions/__generated__/K8sContextSubscription.graphql.js b/examples/next-14/components/graphql/subscriptions/__generated__/K8sContextSubscription.graphql.js new file mode 100644 index 00000000..b99b94c1 --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/__generated__/K8sContextSubscription.graphql.js @@ -0,0 +1,170 @@ +/** + * @generated SignedSource<<b3ff0b1931138b2a628d036eb6f80bd7>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "selector" + } +], +v1 = [ + { + "alias": "k8sContext", + "args": [ + { + "kind": "Variable", + "name": "selector", + "variableName": "selector" + } + ], + "concreteType": "K8sContextsPage", + "kind": "LinkedField", + "name": "subscribeK8sContext", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "total_count", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "K8sContext", + "kind": "LinkedField", + "name": "contexts", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "server", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "owner", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "created_by", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "meshery_instance_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "kubernetes_server_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "deployment_type", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updated_at", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "created_at", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "version", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "connection_id", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "K8sContextSubscription", + "selections": (v1/*: any*/), + "type": "Subscription", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "K8sContextSubscription", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "6c554db6a024337ed225dbb949aa970f", + "id": null, + "metadata": {}, + "name": "K8sContextSubscription", + "operationKind": "subscription", + "text": "subscription K8sContextSubscription(\n $selector: PageFilter!\n) {\n k8sContext: subscribeK8sContext(selector: $selector) {\n total_count\n contexts {\n id\n name\n server\n owner\n created_by\n meshery_instance_id\n kubernetes_server_id\n deployment_type\n updated_at\n created_at\n version\n connection_id\n }\n }\n}\n" + } +}; +})(); + +node.hash = "8b7ae007f5dced76f0d0b1b3c90a4525"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/subscriptions/__generated__/MeshModelSummarySubscription.graphql.js b/examples/next-14/components/graphql/subscriptions/__generated__/MeshModelSummarySubscription.graphql.js new file mode 100644 index 00000000..9508191b --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/__generated__/MeshModelSummarySubscription.graphql.js @@ -0,0 +1,104 @@ +/** + * @generated SignedSource<<b2d0207b1050ec5ac932b0306d9186cf>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "selector" + } +], +v1 = [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "count", + "storageKey": null + } +], +v2 = [ + { + "alias": "meshmodelSummary", + "args": [ + { + "kind": "Variable", + "name": "selector", + "variableName": "selector" + } + ], + "concreteType": "MeshModelSummary", + "kind": "LinkedField", + "name": "subscribeMeshModelSummary", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "MeshModelComponent", + "kind": "LinkedField", + "name": "components", + "plural": true, + "selections": (v1/*: any*/), + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "MeshModelRelationship", + "kind": "LinkedField", + "name": "relationships", + "plural": true, + "selections": (v1/*: any*/), + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "MeshModelSummarySubscription", + "selections": (v2/*: any*/), + "type": "Subscription", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "MeshModelSummarySubscription", + "selections": (v2/*: any*/) + }, + "params": { + "cacheID": "458b92d09a21e56a16ddbc316c2f1596", + "id": null, + "metadata": {}, + "name": "MeshModelSummarySubscription", + "operationKind": "subscription", + "text": "subscription MeshModelSummarySubscription(\n $selector: MeshModelSummarySelector!\n) {\n meshmodelSummary: subscribeMeshModelSummary(selector: $selector) {\n components {\n name\n count\n }\n relationships {\n name\n count\n }\n }\n}\n" + } +}; +})(); + +node.hash = "f9ce6171759cd696ee275c65c930974b"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/subscriptions/__generated__/MeshSyncEventsSubscription.graphql.js b/examples/next-14/components/graphql/subscriptions/__generated__/MeshSyncEventsSubscription.graphql.js new file mode 100644 index 00000000..b6d89142 --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/__generated__/MeshSyncEventsSubscription.graphql.js @@ -0,0 +1,103 @@ +/** + * @generated SignedSource<<b5265e02bc691cfba41a29225518a02f>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "eventTypes" +}, +v1 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "k8scontextIDs" +}, +v2 = [ + { + "alias": "meshsyncevents", + "args": [ + { + "kind": "Variable", + "name": "eventTypes", + "variableName": "eventTypes" + }, + { + "kind": "Variable", + "name": "k8scontextIDs", + "variableName": "k8scontextIDs" + } + ], + "concreteType": "MeshSyncEvent", + "kind": "LinkedField", + "name": "subscribeMeshSyncEvents", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "type", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "object", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "contextId", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "MeshSyncEventsSubscription", + "selections": (v2/*: any*/), + "type": "Subscription", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], + "kind": "Operation", + "name": "MeshSyncEventsSubscription", + "selections": (v2/*: any*/) + }, + "params": { + "cacheID": "587f7af94d634bb28ea91b1790e28e1f", + "id": null, + "metadata": {}, + "name": "MeshSyncEventsSubscription", + "operationKind": "subscription", + "text": "subscription MeshSyncEventsSubscription(\n $k8scontextIDs: [String!]\n $eventTypes: [MeshSyncEventType!]\n) {\n meshsyncevents: subscribeMeshSyncEvents(k8scontextIDs: $k8scontextIDs, eventTypes: $eventTypes) {\n type\n object\n contextId\n }\n}\n" + } +}; +})(); + +node.hash = "8d4a467a34c136646e2af2ec3107a204"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/subscriptions/__generated__/MesheryControllersStatusSubscription.graphql.js b/examples/next-14/components/graphql/subscriptions/__generated__/MesheryControllersStatusSubscription.graphql.js new file mode 100644 index 00000000..3c4bb1fe --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/__generated__/MesheryControllersStatusSubscription.graphql.js @@ -0,0 +1,89 @@ +/** + * @generated SignedSource<<ed02c176db233601ebb7c92a33710c62>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "k8scontextIDs" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "k8scontextIDs", + "variableName": "k8scontextIDs" + } + ], + "concreteType": "MesheryControllersStatusListItem", + "kind": "LinkedField", + "name": "subscribeMesheryControllersStatus", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "contextId", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "controller", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "MesheryControllersStatusSubscription", + "selections": (v1/*: any*/), + "type": "Subscription", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "MesheryControllersStatusSubscription", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "2f51de3afecd08d2d6316973805b3890", + "id": null, + "metadata": {}, + "name": "MesheryControllersStatusSubscription", + "operationKind": "subscription", + "text": "subscription MesheryControllersStatusSubscription(\n $k8scontextIDs: [String!]\n) {\n subscribeMesheryControllersStatus(k8scontextIDs: $k8scontextIDs) {\n contextId\n controller\n status\n }\n}\n" + } +}; +})(); + +node.hash = "5a93ffadfcfbf8ea14d9bac0fe6b50f3"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/subscriptions/__generated__/OperatorStatusSubscription.graphql.js b/examples/next-14/components/graphql/subscriptions/__generated__/OperatorStatusSubscription.graphql.js new file mode 100644 index 00000000..f9f0c391 --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/__generated__/OperatorStatusSubscription.graphql.js @@ -0,0 +1,147 @@ +/** + * @generated SignedSource<<25878a5479eea4a4697a737a7eb27f59>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "k8scontextIDs" + } +], +v1 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null +}, +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "version", + "storageKey": null +}, +v3 = [ + { + "alias": "operator", + "args": [ + { + "kind": "Variable", + "name": "k8scontextIDs", + "variableName": "k8scontextIDs" + } + ], + "concreteType": "OperatorStatusPerK8sContext", + "kind": "LinkedField", + "name": "listenToOperatorState", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "contextID", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "OperatorStatus", + "kind": "LinkedField", + "name": "operatorStatus", + "plural": false, + "selections": [ + (v1/*: any*/), + (v2/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "OperatorControllerStatus", + "kind": "LinkedField", + "name": "controllers", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + (v2/*: any*/), + (v1/*: any*/) + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "Error", + "kind": "LinkedField", + "name": "error", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "code", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "OperatorStatusSubscription", + "selections": (v3/*: any*/), + "type": "Subscription", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "OperatorStatusSubscription", + "selections": (v3/*: any*/) + }, + "params": { + "cacheID": "8a1bb7537702e43181f395fdcaeceaa0", + "id": null, + "metadata": {}, + "name": "OperatorStatusSubscription", + "operationKind": "subscription", + "text": "subscription OperatorStatusSubscription(\n $k8scontextIDs: [String!]\n) {\n operator: listenToOperatorState(k8scontextIDs: $k8scontextIDs) {\n contextID\n operatorStatus {\n status\n version\n controllers {\n name\n version\n status\n }\n error {\n code\n description\n }\n }\n }\n}\n" + } +}; +})(); + +node.hash = "5728620b5666bd13a414080f9d90778e"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/subscriptions/__generated__/PerformanceProfilesSubscription.graphql.js b/examples/next-14/components/graphql/subscriptions/__generated__/PerformanceProfilesSubscription.graphql.js new file mode 100644 index 00000000..5763c4e1 --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/__generated__/PerformanceProfilesSubscription.graphql.js @@ -0,0 +1,226 @@ +/** + * @generated SignedSource<<a432edc018f0c0e1eba7422e44366bc3>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "selector" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "selector", + "variableName": "selector" + } + ], + "concreteType": "PerfPageProfiles", + "kind": "LinkedField", + "name": "subscribePerfProfiles", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "page", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "page_size", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "total_count", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "PerfProfile", + "kind": "LinkedField", + "name": "profiles", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "concurrent_request", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "created_at", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "duration", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endpoints", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "last_run", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "load_generators", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "qps", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "total_results", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updated_at", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "user_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "request_body", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "request_cookies", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "request_headers", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "content_type", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "service_mesh", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "metadata", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "PerformanceProfilesSubscription", + "selections": (v1/*: any*/), + "type": "Subscription", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "PerformanceProfilesSubscription", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "5f6c02d0e3a568b9f4be8793665cb275", + "id": null, + "metadata": {}, + "name": "PerformanceProfilesSubscription", + "operationKind": "subscription", + "text": "subscription PerformanceProfilesSubscription(\n $selector: PageFilter!\n) {\n subscribePerfProfiles(selector: $selector) {\n page\n page_size\n total_count\n profiles {\n concurrent_request\n created_at\n duration\n endpoints\n id\n last_run\n load_generators\n name\n qps\n total_results\n updated_at\n user_id\n request_body\n request_cookies\n request_headers\n content_type\n service_mesh\n metadata\n }\n }\n}\n" + } +}; +})(); + +node.hash = "4444030b4fe1fdb502b3e6036ccf6fd1"; + +module.exports = node; diff --git a/examples/next-14/components/graphql/subscriptions/__generated__/PerformanceResultSubscription.graphql.js b/examples/next-14/components/graphql/subscriptions/__generated__/PerformanceResultSubscription.graphql.js new file mode 100644 index 00000000..8a320a5e --- /dev/null +++ b/examples/next-14/components/graphql/subscriptions/__generated__/PerformanceResultSubscription.graphql.js @@ -0,0 +1,191 @@ +/** + * @generated SignedSource<<350308d6f756916bb1283003d2b046b5>> + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +var node = (function(){ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "profileID" +}, +v1 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "selector" +}, +v2 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "profileID", + "variableName": "profileID" + }, + { + "kind": "Variable", + "name": "selector", + "variableName": "selector" + } + ], + "concreteType": "PerfPageResult", + "kind": "LinkedField", + "name": "subscribePerfResults", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "page", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "page_size", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "total_count", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "MesheryResult", + "kind": "LinkedField", + "name": "results", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "meshery_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "mesh", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "performance_profile", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "test_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "server_metrics", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "test_start_time", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "created_at", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "user_id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updated_at", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "runner_results", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "PerformanceResultSubscription", + "selections": (v2/*: any*/), + "type": "Subscription", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v1/*: any*/), + (v0/*: any*/) + ], + "kind": "Operation", + "name": "PerformanceResultSubscription", + "selections": (v2/*: any*/) + }, + "params": { + "cacheID": "fa344fe9e839347da9809ab6a307034a", + "id": null, + "metadata": {}, + "name": "PerformanceResultSubscription", + "operationKind": "subscription", + "text": "subscription PerformanceResultSubscription(\n $selector: PageFilter!\n $profileID: String!\n) {\n subscribePerfResults(selector: $selector, profileID: $profileID) {\n page\n page_size\n total_count\n results {\n meshery_id\n name\n mesh\n performance_profile\n test_id\n server_metrics\n test_start_time\n created_at\n user_id\n updated_at\n runner_results\n }\n }\n}\n" + } +}; +})(); + +node.hash = "4cd62dfb1b40f60dbc14b2ad7ffea32e"; + +module.exports = node; diff --git a/examples/next-14/icons/AlertIcon/index.jsx b/examples/next-14/icons/AlertIcon/index.jsx new file mode 100644 index 00000000..f4173635 --- /dev/null +++ b/examples/next-14/icons/AlertIcon/index.jsx @@ -0,0 +1,26 @@ +import SvgIcon from '@mui/material/SvgIcon'; + +/** + * Function component for rendering an alert icon. + * @param {import("../type").IconProps} props - Icon props. + * @returns {JSX.Element} - Alert icon SVG element. + */ +export function AlertIcon({ width = '24', height = '24', fill = 'currentColor', ...props }) { + return ( + <SvgIcon + viewBox="0 0 20 20" + xmlns="http://www.w3.org/2000/svg" + height={height} + width={width} + fill="#fff" + style={props.style} + > + <path + d="M11.6042 11.6667H9.89591V7.49999H11.6042V11.6667ZM11.6042 15H9.89591V13.3333H11.6042V15ZM1.35425 17.5H20.1459L10.7501 1.66666L1.35425 17.5Z" + fill={fill} + /> + </SvgIcon> + ); +} + +export default AlertIcon; diff --git a/examples/next-14/icons/ContentFilterIcon/index.jsx b/examples/next-14/icons/ContentFilterIcon/index.jsx new file mode 100644 index 00000000..0fe6545b --- /dev/null +++ b/examples/next-14/icons/ContentFilterIcon/index.jsx @@ -0,0 +1,30 @@ +import SvgIcon from '@mui/material/SvgIcon'; + +/** + * Function component for rendering a content filter icon. + * @param {import("../type").IconProps} props - Icon props. + * @returns {JSX.Element} - Content filter icon SVG element. + */ +export function ContentFilterIcon({ width = '24', height = '24', ...props }) { + return ( + <SvgIcon + viewBox="0 0 24 24" + xmlns="http://www.w3.org/2000/svg" + width={width} + height={height} + // fill={props.fill} + style={{ ...props.style }} + {...props} + > + <path + fillRule="evenodd" + clipRule="evenodd" + d="M10 18H14V16H10V18ZM3 6V8H21V6H3ZM6 13H18V11H6V13Z" + fillOpacity=".54" + // fill={props.fill} + /> + </SvgIcon> + ); +} + +export default ContentFilterIcon; diff --git a/examples/next-14/icons/CrossCircleIcon/index.jsx b/examples/next-14/icons/CrossCircleIcon/index.jsx new file mode 100644 index 00000000..88c5fade --- /dev/null +++ b/examples/next-14/icons/CrossCircleIcon/index.jsx @@ -0,0 +1,27 @@ +import SvgIcon from '@mui/material/SvgIcon'; + +/** + * Function component for rendering a cross circle icon. + * @param {import("../type").IconProps} props - Icon props. + * @returns {JSX.Element} - Cross circle icon SVG element. + */ +export function CrossCircleIcon({ width = '24', height = '24', fill = 'currentColor', ...props }) { + return ( + <SvgIcon + viewBox="0 0 24 24" + xmlns="http://www.w3.org/2000/svg" + width={width} + height={height} + fill={fill} + style={{ ...props.style }} + {...props} + > + <path + d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2Zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59Z" + fillOpacity=".54" + /> + </SvgIcon> + ); +} + +export default CrossCircleIcon; diff --git a/examples/next-14/icons/ErrorIcon/index.jsx b/examples/next-14/icons/ErrorIcon/index.jsx new file mode 100644 index 00000000..e6e58cfd --- /dev/null +++ b/examples/next-14/icons/ErrorIcon/index.jsx @@ -0,0 +1,24 @@ +import SvgIcon from '@mui/material/SvgIcon'; + +/** + * Function component for rendering an info icon. + * @param {import("../type").IconProps} props - Icon props. + * @returns {JSX.Element} - Info icon SVG element. + */ +export function ErrorIcon({ width = '24', height = '24', fill = 'currentColor', ...props }) { + return ( + <SvgIcon + viewBox="0 0 24 24" + xmlns="http://www.w3.org/2000/svg" + height={height} + width={width} + fill={fill} + style={props.style} + > + <path d="M0 0h24v24H0z" fill="none" /> + <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z" /> + </SvgIcon> + ); +} + +export default ErrorIcon; diff --git a/examples/next-14/icons/GrafanaIcon/index.jsx b/examples/next-14/icons/GrafanaIcon/index.jsx new file mode 100644 index 00000000..8c75e5ed --- /dev/null +++ b/examples/next-14/icons/GrafanaIcon/index.jsx @@ -0,0 +1,44 @@ +import SvgIcon from '@mui/material/SvgIcon'; + +/** + * Function component for rendering a Prometheus icon. + * @param {{ isActive: boolean | undefined }} props - Props for the Prometheus icon component. + * @returns {JSX.Element} - Grafana icon SVG element. + */ +export function GrafanaIcon({ isActive }) { + return ( + <SvgIcon + sx={{ + width: '3rem', + height: 'auto', + filter: isActive ? null : 'grayscale(1)', + }} + viewBox="0 0 50 52" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M48.7179 22.963C48.6325 22.094 48.49 21.0969 48.2051 19.9858C47.9202 18.8889 47.4929 17.6781 46.8661 16.4245C46.2393 15.1709 45.4273 13.8746 44.3732 12.6068C43.9601 12.1083 43.5043 11.6239 43.0199 11.1539C43.7464 8.26211 42.1367 5.75499 42.1367 5.75499C39.359 5.58405 37.5926 6.62394 36.9373 7.09402C36.8233 7.05129 36.7236 6.99431 36.6097 6.95157C36.1396 6.76639 35.6553 6.5812 35.1424 6.42451C34.6439 6.26781 34.131 6.12536 33.604 5.99716C33.0769 5.86895 32.5498 5.76924 32.0085 5.68377C31.9088 5.66952 31.8233 5.65528 31.7236 5.64103C30.5128 1.76639 27.037 0.142456 27.037 0.142456C23.1481 2.60684 22.4216 6.05414 22.4216 6.05414C22.4216 6.05414 22.4074 6.12536 22.3789 6.25357C22.1652 6.31055 21.9516 6.38177 21.7379 6.43875C21.4387 6.52422 21.1396 6.63818 20.8547 6.75214C20.5555 6.8661 20.2706 6.98006 19.9715 7.10827C19.3875 7.36468 18.8034 7.64958 18.2336 7.96297C17.6781 8.27636 17.1367 8.61824 16.6097 8.97436C16.5385 8.94587 16.4672 8.91738 16.4672 8.91738C11.0826 6.8661 6.31053 9.33049 6.31053 9.33049C5.86893 15.057 8.46153 18.661 8.97435 19.3162C8.84614 19.6724 8.73218 20.0285 8.61822 20.3846C8.21936 21.6809 7.92022 23.0057 7.73503 24.3875C7.70654 24.5869 7.67805 24.7863 7.66381 24.9858C2.67805 27.4501 1.21082 32.4786 1.21082 32.4786C5.35611 37.2507 10.1994 37.5499 10.1994 37.5499L10.2137 37.5356C10.8262 38.6325 11.5385 39.6724 12.3362 40.6553C12.6781 41.0684 13.0199 41.453 13.3903 41.8376C11.8803 46.1681 13.604 49.7578 13.604 49.7578C18.2194 49.9288 21.2535 47.735 21.8946 47.2365C22.3504 47.3932 22.8205 47.5356 23.2906 47.6496C24.7151 48.0199 26.1681 48.2336 27.6211 48.2906C27.9772 48.3048 28.3476 48.3191 28.7037 48.3048H28.8746H28.9886H29.2165L29.4444 48.2906V48.3048C31.6239 51.4103 35.4416 51.8519 35.4416 51.8519C38.1624 48.9886 38.3191 46.1396 38.3191 45.5271C38.3191 45.5271 38.3191 45.5128 38.3191 45.4843C38.3191 45.4274 38.3191 45.3989 38.3191 45.3989C38.3191 45.3561 38.3191 45.3134 38.3191 45.2707C38.8889 44.8718 39.4302 44.4445 39.943 43.9744C41.0256 42.9915 41.98 41.8661 42.7778 40.6553C42.849 40.5413 42.9202 40.4274 42.9914 40.3134C46.0684 40.4843 48.2479 38.4046 48.2479 38.4046C47.735 35.1994 45.9117 33.6325 45.5271 33.3333C45.5271 33.3333 45.5128 33.3191 45.4843 33.3048C45.4558 33.2906 45.4558 33.2764 45.4558 33.2764C45.4416 33.2621 45.4131 33.2479 45.3846 33.2336C45.3988 33.0342 45.4131 32.849 45.4273 32.6496C45.4558 32.3077 45.4558 31.9516 45.4558 31.6097V31.3533V31.2251V31.1539C45.4558 31.0684 45.4558 31.0969 45.4558 31.0684L45.4416 30.8547L45.4273 30.5698C45.4273 30.4701 45.4131 30.3846 45.3989 30.2992C45.3846 30.2137 45.3846 30.114 45.3704 30.0285L45.3419 29.7578L45.2991 29.4872C45.2422 29.1311 45.1852 28.7892 45.0997 28.4331C44.7721 27.0513 44.2308 25.7407 43.5328 24.5584C42.8205 23.3761 41.9373 22.3362 40.9259 21.453C39.9288 20.5698 38.8034 19.8576 37.6353 19.3305C36.453 18.8034 35.2279 18.4615 34.0028 18.3048C33.3903 18.2194 32.7778 18.1909 32.1652 18.2051H31.9373H31.8803C31.8661 18.2051 31.7949 18.2051 31.8091 18.2051H31.7094L31.4815 18.2194C31.396 18.2194 31.3105 18.2336 31.2393 18.2336C30.9259 18.2621 30.6125 18.3048 30.3134 18.3618C29.0883 18.5897 27.9345 19.0313 26.9231 19.6439C25.9117 20.2564 25.0285 21.0114 24.3162 21.8661C23.604 22.7208 23.0484 23.6752 22.6638 24.6581C22.2792 25.641 22.0655 26.6667 22.0085 27.6496C21.9943 27.8917 21.9943 28.1482 21.9943 28.3903C21.9943 28.4473 21.9943 28.5185 21.9943 28.5755L22.0085 28.7749C22.0228 28.8889 22.0228 29.0171 22.037 29.1311C22.0798 29.6296 22.1795 30.114 22.3077 30.5698C22.5783 31.4957 23.0057 32.3362 23.5328 33.0484C24.0598 33.7607 24.7008 34.3447 25.3704 34.8148C26.0399 35.2707 26.7664 35.5983 27.4786 35.812C28.1909 36.0256 28.9031 36.1111 29.5726 36.1111C29.6581 36.1111 29.7436 36.1111 29.8148 36.1111C29.8575 36.1111 29.9003 36.1111 29.943 36.1111C29.9857 36.1111 30.0285 36.1111 30.0712 36.0969C30.1424 36.0969 30.2137 36.0826 30.2849 36.0826C30.2991 36.0826 30.3276 36.0826 30.3419 36.0684L30.4131 36.0541C30.4558 36.0541 30.4986 36.0399 30.5413 36.0399C30.6268 36.0256 30.698 36.0114 30.7835 35.9972C30.8689 35.9829 30.9402 35.9687 31.0114 35.9402C31.1681 35.9117 31.3105 35.8547 31.453 35.812C31.7379 35.7123 32.0228 35.5983 32.2649 35.4701C32.5214 35.3419 32.7493 35.1852 32.9772 35.0427C33.0342 35 33.1054 34.9573 33.1624 34.9003C33.3903 34.7151 33.433 34.3732 33.2479 34.1453C33.0912 33.9459 32.8063 33.8889 32.5783 34.0171C32.5214 34.0456 32.4644 34.0741 32.4074 34.1026C32.208 34.2023 32.0085 34.2878 31.7949 34.359C31.5812 34.4302 31.3533 34.4872 31.1253 34.5299C31.0114 34.5442 30.8974 34.5584 30.7692 34.5727C30.7122 34.5727 30.6553 34.5869 30.584 34.5869C30.5271 34.5869 30.4558 34.5869 30.4131 34.5869C30.3561 34.5869 30.2991 34.5869 30.2422 34.5869C30.1709 34.5869 30.0997 34.5869 30.0285 34.5727C30.0285 34.5727 29.9857 34.5727 30.0142 34.5727H29.9857H29.943C29.9145 34.5727 29.8718 34.5727 29.8433 34.5584C29.7721 34.5442 29.7151 34.5442 29.6439 34.5299C29.1168 34.4587 28.5897 34.302 28.0912 34.0741C27.5783 33.8462 27.094 33.5328 26.6524 33.1339C26.2108 32.735 25.8262 32.265 25.5271 31.7237C25.2279 31.1823 25.0142 30.5841 24.9145 29.9573C24.8718 29.6439 24.8433 29.3162 24.8575 29.0029C24.8575 28.9174 24.8718 28.8319 24.8718 28.7464C24.8718 28.7749 24.8718 28.7322 24.8718 28.7322V28.7037V28.6325C24.8718 28.5897 24.886 28.547 24.886 28.5043C24.9003 28.3333 24.9288 28.1624 24.9573 27.9915C25.1994 26.6239 25.8832 25.2849 26.9373 24.2735C27.208 24.0171 27.4929 23.7892 27.792 23.5755C28.0912 23.3618 28.4188 23.1766 28.7607 23.0199C29.1026 22.8633 29.4444 22.735 29.8148 22.6353C30.1709 22.5356 30.5413 22.4786 30.9259 22.4359C31.1111 22.4217 31.2963 22.4074 31.4957 22.4074C31.5527 22.4074 31.5812 22.4074 31.6239 22.4074H31.7806H31.8803C31.9231 22.4074 31.8803 22.4074 31.8946 22.4074H31.9373L32.094 22.4217C32.5071 22.4501 32.906 22.5071 33.3048 22.6068C34.1026 22.7778 34.886 23.0769 35.6125 23.4758C37.0655 24.2878 38.3048 25.5413 39.0598 27.0513C39.4444 27.8063 39.7151 28.6182 39.8433 29.4587C39.8718 29.6724 39.9003 29.886 39.9145 30.0997L39.9288 30.2564L39.943 30.4131C39.943 30.4701 39.943 30.5271 39.943 30.5698C39.943 30.6268 39.943 30.6838 39.943 30.7265V30.869V31.0256C39.943 31.1254 39.9288 31.2963 39.9288 31.396C39.9145 31.6239 39.886 31.8661 39.8575 32.094C39.829 32.3219 39.7863 32.5499 39.7436 32.7778C39.7008 33.0057 39.6439 33.2336 39.5869 33.4473C39.4729 33.8889 39.3305 34.3305 39.1595 34.7721C38.8177 35.6268 38.3618 36.453 37.8205 37.208C36.7236 38.718 35.2279 39.943 33.5185 40.7265C32.6638 41.1111 31.7664 41.396 30.8404 41.5385C30.3846 41.6239 29.9145 41.6667 29.4444 41.6809H29.359H29.2877H29.131H28.9031H28.7892C28.8461 41.6809 28.7749 41.6809 28.7749 41.6809H28.7322C28.4758 41.6809 28.2336 41.6667 27.9772 41.6382C26.98 41.567 25.9971 41.3818 25.0285 41.1111C24.0741 40.8405 23.1481 40.4558 22.2649 40C20.5128 39.0598 18.9316 37.7778 17.7065 36.2251C17.094 35.4558 16.5527 34.6154 16.1111 33.7464C15.6695 32.8775 15.3134 31.9516 15.057 31.0256C14.8006 30.0855 14.6439 29.1311 14.5726 28.1624L14.5584 27.9772V27.9345V27.8917V27.8063V27.6496V27.6068V27.5499V27.4359V27.208V27.1652C14.5584 27.1652 14.5584 27.1795 14.5584 27.151V27.0655C14.5584 26.9516 14.5584 26.8234 14.5584 26.7094C14.5726 26.2393 14.6154 25.7407 14.6724 25.2564C14.7293 24.7721 14.8148 24.2735 14.9145 23.7892C15.0142 23.3048 15.1282 22.8205 15.2706 22.3362C15.5413 21.3818 15.8832 20.4558 16.282 19.5869C17.094 17.849 18.1481 16.2963 19.4159 15.057C19.7293 14.7436 20.057 14.4587 20.3988 14.1738C20.7407 13.9031 21.0969 13.6467 21.4672 13.4046C21.8234 13.1624 22.208 12.9487 22.5926 12.7493C22.7778 12.6496 22.9772 12.5499 23.1766 12.4644C23.2763 12.4217 23.3761 12.3789 23.4758 12.3362C23.5755 12.2935 23.6752 12.2507 23.7749 12.208C24.1738 12.037 24.5869 11.8946 25.0142 11.7664C25.1139 11.7379 25.2279 11.7094 25.3276 11.6667C25.4273 11.6382 25.5413 11.6097 25.641 11.5812C25.8547 11.5242 26.0684 11.4672 26.282 11.4245C26.3818 11.396 26.4957 11.3818 26.6097 11.3533C26.7236 11.3248 26.8234 11.3105 26.9373 11.2821C27.0513 11.2678 27.151 11.2393 27.2649 11.2251L27.4216 11.1966L27.5926 11.1681C27.7065 11.1539 27.8063 11.1396 27.9202 11.1254C28.0484 11.1111 28.1624 11.0969 28.2906 11.0826C28.3903 11.0684 28.5612 11.0541 28.661 11.0399C28.7322 11.0256 28.8177 11.0256 28.8889 11.0114L29.0456 10.9972L29.1168 10.9829H29.2023C29.3305 10.9687 29.4444 10.9687 29.5726 10.9544L29.7578 10.9402C29.7578 10.9402 29.829 10.9402 29.7721 10.9402H29.8148H29.9003C30 10.9402 30.1139 10.9259 30.2137 10.9259C30.6268 10.9117 31.0541 10.9117 31.4672 10.9259C32.2934 10.9544 33.1054 11.0541 33.8889 11.1966C35.4701 11.4957 36.9516 11.9943 38.3048 12.6638C39.6581 13.3191 40.8547 14.1311 41.9088 15.0143C41.98 15.0712 42.037 15.1282 42.1083 15.1852C42.1652 15.2422 42.2365 15.2992 42.2934 15.3561C42.4216 15.4701 42.5356 15.5841 42.6638 15.698C42.792 15.812 42.906 15.9259 43.0199 16.0399C43.1339 16.1539 43.2479 16.2678 43.3618 16.396C43.8034 16.8661 44.2165 17.3362 44.5869 17.8205C45.3276 18.7749 45.9259 19.7436 46.396 20.6553C46.4245 20.7123 46.453 20.7692 46.4815 20.8262C46.51 20.8832 46.5384 20.9402 46.5669 20.9972C46.6239 21.1111 46.6809 21.2251 46.7236 21.339C46.7806 21.453 46.8234 21.5527 46.8803 21.6667C46.9231 21.7806 46.98 21.8803 47.0228 21.9943C47.1937 22.4217 47.3647 22.8348 47.4929 23.2194C47.7065 23.8462 47.8632 24.4017 47.9914 24.886C48.0342 25.0855 48.2194 25.2137 48.4188 25.1852C48.6325 25.1709 48.7892 25 48.7892 24.7863C48.8034 24.2735 48.7892 23.661 48.7179 22.963Z" + fill="url(#paint0_linear)" + /> + <defs> + <linearGradient + id="paint0_linear" + x1="25" + y1="63.4608" + x2="25" + y2="16.2443" + gradientUnits="userSpaceOnUse" + > + <stop stopColor="#FFF100" /> + <stop offset="1" stopColor="#F05A28" /> + </linearGradient> + <clipPath id="clip0"> + <rect width="50" height="51.9943" fill="white" /> + </clipPath> + </defs> + </SvgIcon> + ); +} + +export default GrafanaIcon; diff --git a/examples/next-14/icons/InfoIcon/index.jsx b/examples/next-14/icons/InfoIcon/index.jsx new file mode 100644 index 00000000..d7430ebc --- /dev/null +++ b/examples/next-14/icons/InfoIcon/index.jsx @@ -0,0 +1,31 @@ +import SvgIcon from '@mui/material/SvgIcon'; + +/** + * Function component for rendering an info icon. + * @param {import("../type").IconProps} props - Icon props. + * @returns {JSX.Element} - Info icon SVG element. + */ +export function InfoIcon({ width = '24', height = '24', fill = 'currentColor', ...props }) { + return ( + <SvgIcon + xmlns="http://www.w3.org/2000/svg" + width={width} + height={height} + style={props.style} + viewBox="0 0 20 20" + fill="none" + > + <path + d="M10.0003 1.66666C5.40033 1.66666 1.66699 5.39999 1.66699 9.99999C1.66699 14.6 5.40033 18.3333 10.0003 18.3333C14.6003 18.3333 18.3337 14.6 18.3337 9.99999C18.3337 5.39999 14.6003 1.66666 10.0003 1.66666ZM10.8337 14.1667H9.16699V9.16666H10.8337V14.1667ZM10.8337 7.49999H9.16699V5.83332H10.8337V7.49999Z" + fill={fill} + /> + <defs> + <clipPath id="clip0_19460_1750"> + <rect width={width} height={height} fill="none" /> + </clipPath> + </defs> + </SvgIcon> + ); +} + +export default InfoIcon; diff --git a/examples/next-14/icons/MesheryIcon/index.jsx b/examples/next-14/icons/MesheryIcon/index.jsx new file mode 100644 index 00000000..31a726c0 --- /dev/null +++ b/examples/next-14/icons/MesheryIcon/index.jsx @@ -0,0 +1,69 @@ +import { SvgIcon } from '@mui/material'; +import { useTheme } from '@mui/material/styles'; + +function MesheryIconBase({ ...props }) { + const { + width = '28px', + height = '28px', + // fill = "currentColor", + primaryFill = '#00b39f', + secondaryFill = '#00d3a9', + onClick, + className, + color = 'unset', + fontSize = 'unset', + style, + } = props; + + const theme = useTheme(); + + const fill = theme.palette.mode === 'dark' ? primaryFill : secondaryFill; + + return ( + <SvgIcon + component={'SvgIconsvg'} + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 134.95 135.02" + width={width} + height={height} + fill={fill} + onClick={onClick} + className={className} + color={color} + fontSize={fontSize} + style={style} + > + <polygon fill={primaryFill} points="69.49 31.82 69.49 64.07 97.44 47.89 69.49 31.82" /> + <polygon fill={primaryFill} points="69.49 70.81 69.49 103.22 97.7 87.09 69.49 70.81" /> + <polygon fill={secondaryFill} points="65.47 63.85 65.47 32.09 37.87 47.92 65.47 63.85" /> + <path fill={secondaryFill} d="M10.1,103.1a67.79,67.79,0,0,0,21.41,21.55V90.71Z" /> + <polygon fill={secondaryFill} points="65.47 103.06 65.47 71.05 37.8 87.07 65.47 103.06" /> + <polygon fill={primaryFill} points="35.54 122.63 63.56 106.61 35.54 90.41 35.54 122.63" /> + <polygon fill={secondaryFill} points="99.61 122.8 99.61 90.63 71.63 106.63 99.61 122.8" /> + <path fill={secondaryFill} d="M127,99.37a67.22,67.22,0,0,0,7.91-28.94L105.78,87.11Z" /> + <polygon fill={primaryFill} points="103.64 83.69 131.76 67.61 103.64 51.45 103.64 83.69" /> + <polygon fill={secondaryFill} points="99.61 44.5 99.61 12.52 71.76 28.49 99.61 44.5" /> + <polygon fill={secondaryFill} points="99.61 83.55 99.61 51.28 71.7 67.44 99.61 83.55" /> + <polygon fill={secondaryFill} points="67.48 135.02 67.49 135.02 67.48 135.02 67.48 135.02" /> + <polygon fill={primaryFill} points="35.54 51.22 35.54 83.73 63.66 67.45 35.54 51.22" /> + <path fill={secondaryFill} d="M65.47,0A67.2,67.2,0,0,0,35.83,7.83l29.64,17Z" /> + <polygon fill={primaryFill} points="35.54 12.3 35.54 44.62 63.68 28.48 35.54 12.3" /> + <path fill={secondaryFill} d="M31.51,10.34A67.89,67.89,0,0,0,10.1,31.89L31.51,44.25Z" /> + <path fill={primaryFill} d="M99.43,8A67.23,67.23,0,0,0,69.49,0V25.15Z" /> + <path fill={primaryFill} d="M0,69.87A67.27,67.27,0,0,0,8.07,99.63L29.76,87.07Z" /> + <path fill={primaryFill} d="M8.07,35.37A67.16,67.16,0,0,0,0,65L29.79,47.91Z" /> + <path fill={secondaryFill} d="M35.78,127.13A67.13,67.13,0,0,0,65.47,135V110.15Z" /> + <path fill={primaryFill} d="M124.92,32a67.9,67.9,0,0,0-21.28-21.52V44.3Z" /> + <path fill={primaryFill} d="M103.64,124.54A68,68,0,0,0,125,102.86L103.64,90.52Z" /> + <path fill={secondaryFill} d="M135,64.81a67.06,67.06,0,0,0-8-29.35L105.49,47.88Z" /> + <path fill={primaryFill} d="M69.49,135a67.12,67.12,0,0,0,29.63-7.83L69.49,110Z" /> + <polygon fill={secondaryFill} points="31.51 83.44 31.51 51.56 3.83 67.43 31.51 83.44" /> + </SvgIcon> + ); +} + +export function MesheryIcon() { + return <SvgIcon component={MesheryIconBase} />; +} + +export default MesheryIcon; diff --git a/examples/next-14/icons/PrometheusIcon/index.jsx b/examples/next-14/icons/PrometheusIcon/index.jsx new file mode 100644 index 00000000..5a7ac104 --- /dev/null +++ b/examples/next-14/icons/PrometheusIcon/index.jsx @@ -0,0 +1,33 @@ +import SvgIcon from '@mui/material/SvgIcon'; + +/** + * Function component for rendering a Prometheus icon. + * @param {{ isActive: boolean | undefined }} props - Props for the Prometheus icon component. + * @returns {JSX.Element} - Prometheus icon SVG element. + */ +export function PrometheusIcon({ isActive }) { + return ( + <SvgIcon + sx={{ + width: '3rem', + height: 'auto', + filter: isActive ? null : 'grayscale(1)', + }} + viewBox="0 0 50 50" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M24.5667 0.289185C10.9995 0.289185 0 11.2873 0 24.855C0 38.4222 10.9995 49.4213 24.5667 49.4213C38.1339 49.4213 49.1329 38.4222 49.1329 24.855C49.1329 11.2873 38.1335 0.289185 24.5667 0.289185V0.289185ZM24.5667 46.2669C20.7066 46.2669 17.5769 43.6883 17.5769 40.5084H31.5564C31.5564 43.6879 28.4268 46.2669 24.5667 46.2669ZM36.1115 38.6013H13.0206V34.4143H36.112V38.6013H36.1115ZM36.0287 32.2592H13.0865C13.0102 32.1712 12.9321 32.0845 12.8584 31.9952C10.4948 29.1253 9.93818 27.627 9.39757 26.1001C9.38847 26.0498 12.2636 26.6875 14.3025 27.1462C14.3025 27.1462 15.3516 27.389 16.8855 27.6686C15.4128 25.9423 14.5383 23.7478 14.5383 21.5047C14.5383 16.5803 18.3152 12.2771 16.9527 8.79889C18.2788 8.90684 19.6973 11.5977 19.7931 15.8051C21.203 13.8569 21.793 10.2989 21.793 8.11739C21.793 5.85871 23.2813 3.235 24.77 3.14526C23.443 5.33241 25.1138 7.20741 26.5991 11.8587C27.1561 13.6058 27.085 16.546 27.5151 18.4106C27.6577 14.5379 28.3236 8.88733 30.7804 6.93646C29.6966 9.39326 30.9408 12.4674 31.7919 13.9453C33.1648 16.3297 33.9972 18.1362 33.9972 21.5528C33.9972 23.8436 33.1514 26.0004 31.7247 27.6864C33.3469 27.382 34.4672 27.1076 34.4672 27.1076L39.7354 26.0797C39.7358 26.0793 38.9702 29.2276 36.0287 32.2592Z" + fill="#E6522C" + /> + <defs> + <clipPath id="clip0"> + <rect width="50" height="49.4221" fill="white" /> + </clipPath> + </defs> + </SvgIcon> + ); +} + +export default PrometheusIcon; diff --git a/examples/next-14/icons/ReadIcon/index.jsx b/examples/next-14/icons/ReadIcon/index.jsx new file mode 100644 index 00000000..9e922236 --- /dev/null +++ b/examples/next-14/icons/ReadIcon/index.jsx @@ -0,0 +1,30 @@ +import SvgIcon from '@mui/material/SvgIcon'; + +/** + * Function component for rendering a read icon. + * @param {import("../type").IconProps} props - Icon props. + * @returns {JSX.Element} - Read icon SVG element. + */ +export function ReadIcon({ width = '24', height = '24', fill = 'currentColor', ...props }) { + return ( + <SvgIcon + viewBox="0 0 20 19" + xmlns="http://www.w3.org/2000/svg" + width={width} + height={height} + x="0px" + y="0px" + fill={fill} + style={{ ...props.style }} + {...props} + > + <path + d="M20,7c0-0.7-0.4-1.3-0.9-1.7L10,0L1,5.3C0.4,5.7,0,6.3,0,7v10c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2L20,7z M10,12L1.7,6.8 + L10,2l8.3,4.8L10,12z" + fill={fill} + /> + </SvgIcon> + ); +} + +export default ReadIcon; diff --git a/examples/next-14/icons/type.js b/examples/next-14/icons/type.js new file mode 100644 index 00000000..b6b219c9 --- /dev/null +++ b/examples/next-14/icons/type.js @@ -0,0 +1,12 @@ +import React from 'react'; + +/** + * Props for custom icon component. + * @typedef {Object} IconProps + * @property {string} [color] - Color of the icon. + * @property {string} [title] - Title for accessibility. + * @property {number|string} [width] - Width of the icon. + * @property {number|string} [height] - Height of the icon. + * @property {string} [fill] - Fill color of the icon. + * @property {React.SVGProps<SVGSVGElement>} [children] - SVG children elements. + */ diff --git a/examples/next-14/jsconfig.json b/examples/next-14/jsconfig.json new file mode 100644 index 00000000..2a2e4b3b --- /dev/null +++ b/examples/next-14/jsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "paths": { + "@/*": ["./*"] + } + } +} diff --git a/examples/next-14/lib/hooks/useDashboardRouter.jsx b/examples/next-14/lib/hooks/useDashboardRouter.jsx new file mode 100644 index 00000000..7a34405f --- /dev/null +++ b/examples/next-14/lib/hooks/useDashboardRouter.jsx @@ -0,0 +1,33 @@ +import { useRouter } from 'next/navigation'; + +export const useDashboardRouter = () => { + const router = useRouter(); + const { query, push: pushRoute, route } = router; + + const resourceCategory = query && query.resourceCategory ? query.resourceCategory : 'Overview'; + const selectedResource = query && query.resource; + + const changeResourceTab = (resourceCategory) => { + if (query.resourceCategory === resourceCategory) { + return; + } + pushRoute( + `${route}?resourceCategory=${resourceCategory || query.resourceCategory}`, + undefined, + { shallow: true }, + ); + }; + + const handleChangeSelectedResource = (resource) => { + if (query.resource === resource) { + return; + } + pushRoute(`${route}?resourceCategory=${resourceCategory}&resource=${resource}`, undefined, { + shallow: true, + }); + }; + + return { resourceCategory, changeResourceTab, selectedResource, handleChangeSelectedResource }; +}; + +export default useDashboardRouter; diff --git a/examples/next-14/lib/hooks/useFetchUserData.jsx b/examples/next-14/lib/hooks/useFetchUserData.jsx new file mode 100644 index 00000000..ce2a49a0 --- /dev/null +++ b/examples/next-14/lib/hooks/useFetchUserData.jsx @@ -0,0 +1,34 @@ +/** + * React Custom Hook + * useFetchUserData + * @TODO add dispatch + */ +import { useEffect, useState } from 'react'; + +import dataFetch from '@/utils/dataFetch'; + +const useFetchUserData = (url, options = {}) => { + const [user, setUser] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchUser = async () => { + try { + const userData = await dataFetch('/api/user', { + credentials: 'same-origin', + }); + setUser(userData); + setLoading(false); + } catch (e) { + setError(e); + setLoading(false); + } + }; + fetchUser(); + }, []); + + return { user, loading, error }; +}; + +export default useFetchUserData; diff --git a/examples/next-14/lib/hooks/useKubernetes.jsx b/examples/next-14/lib/hooks/useKubernetes.jsx new file mode 100644 index 00000000..97e0b386 --- /dev/null +++ b/examples/next-14/lib/hooks/useKubernetes.jsx @@ -0,0 +1,107 @@ +import { useDispatch } from 'react-redux'; +import { updateProgress } from '../redux/features/progress/progress.slice'; +import { useNotification } from './useNotification'; +import { NOTIFICATION_EVENT_TYPES } from '@/utils/constants/notification'; + +/** + * Function signature for a notification function. + * @typedef {Object} NotifyFunction + * @property {string} message - The message to be displayed in the notification. + * @property {string} [details] - Additional details to be displayed in the notification. + * @property {string} event_type - The type of event for the notification. + */ + +/** + * Function signature for a callback function. + * @template T + * @callback CallbackFunction + * @param {T} arg - The argument for the callback function. + */ + +/** + * Arguments for generating a success handler. + * @template T + * @typedef {Object} SuccessHandlerGeneratorArgs + * @property {NotifyFunction} notify - The notification function. + * @property {string} msg - The message to be displayed in the success notification. + * @property {CallbackFunction<T>} [cb] - Optional callback function to be executed. + */ + +/** + * Arguments for generating an error handler. + * @typedef {Object} ErrorHandlerGeneratorArgs + * @property {NotifyFunction} notify - The notification function. + * @property {string} msg - The message to be displayed in the error notification. + * @property {CallbackFunction<any>} [cb] - Optional callback function to be executed. + */ + +/** + * Generates a success handler. + * @template T + * @param {SuccessHandlerGeneratorArgs<T>} param0 - Arguments for generating the success handler. + * @returns {CallbackFunction<T>} - The generated success handler. + */ +export const successHandlerGenerator = + ({ notify, msg, cb }) => + (res) => { + if (res !== undefined) { + if (cb !== undefined) cb(res); + if (typeof res == 'object') { + res = JSON.stringify(res); + } + notify({ + message: `${msg}`, + details: `${res}`, + event_type: NOTIFICATION_EVENT_TYPES.SUCCESS, + }); + } + }; + +/** + * Generates an error handler. + * @param {ErrorHandlerGeneratorArgs} param0 - Arguments for generating the error handler. + * @returns {CallbackFunction<any>} - The generated error handler. + */ +export const errorHandlerGenerator = + ({ notify, msg, cb }) => + (err) => { + if (cb !== undefined) cb(err); + err = typeof err !== 'string' ? err.toString() : err; + notify({ + message: `${msg}`, + details: err, + event_type: NOTIFICATION_EVENT_TYPES.ERROR, + }); + }; + +/** + * Custom hook for handling Kubernetes operations. + * @returns {Function} - Function to ping Kubernetes. + */ +export default function useKubernetes() { + const { notify } = useNotification(); + const dispatch = useDispatch(); + + /** + * Function to ping a Kubernetes server. + * @param {string} name - The name of the Kubernetes context. + * @param {string} server - The server URL of the Kubernetes context. + * @param {string} connectionID - The ID of the Kubernetes connection. + */ + const ping = (name, server, connectionID) => { + dispatch(updateProgress({ showProgress: true })); + pingKubernetes( + successHandlerGenerator( + { notify, msg: `Kubernetes context ${name} at ${server} pinged` }, + () => dispatch(updateProgress({ showProgress: false })), + ), + errorHandlerGenerator( + { notify, msg: `Kubernetes context ${name} at ${server} not reachable` }, + () => dispatch(updateProgress({ showProgress: false })), + ), + connectionID, + ); + }; + + return ping; +} diff --git a/examples/next-14/lib/hooks/useMeshModelComponents.jsx b/examples/next-14/lib/hooks/useMeshModelComponents.jsx new file mode 100644 index 00000000..2be1a3ac --- /dev/null +++ b/examples/next-14/lib/hooks/useMeshModelComponents.jsx @@ -0,0 +1,202 @@ +import _ from 'lodash'; + +export const WILDCARD_V = 'All Versions'; + +import { + fetchCategories, + getComponentFromModelApi, + getModelFromCategoryApi, + getVersionedComponentFromModel, +} from '../../api/meshmodel'; +import { compose } from 'lodash/fp'; +import { useEffect, useState } from 'react'; +import getMostRecentVersion, { + versionSortComparatorFn, + sortAndGroupVersionsInModel, +} from '../versionSort'; + +const handleError = (e) => { + console.error('MeshModel axios error ocurred', e); +}; + +function componentToLatestApiVersion(components) { + const componentToAPiVersionMap = {}; // this is for storing all the apiVersions of similar components in order to get the most recent at the end + + [...components].forEach((component) => { + if (componentToAPiVersionMap?.[component.kind]) { + componentToAPiVersionMap[component.kind] = [ + ...componentToAPiVersionMap[component.kind], + component.apiVersion, + ]; + } else { + componentToAPiVersionMap[component.kind] = [component.apiVersion]; + } + }); + + Object.keys(componentToAPiVersionMap).forEach((key) => { + componentToAPiVersionMap[key] = getMostRecentVersion(componentToAPiVersionMap[key]); + }); + + return componentToAPiVersionMap; +} + +function removeDuplicateMeshModelComponents(components) { + const componentClone = [...components]; + const cmpToApiVersion = componentToLatestApiVersion(componentClone); + + // component kind set keeps track of redudan components + const componentKindUniqueSet = new Set(); + + return componentClone + .filter(({ kind }) => { + // filter unique components + // already found in the unique set, means that it is already filtered + if (componentKindUniqueSet.has(kind)) { + return false; + } + + componentKindUniqueSet.add(kind); + return true; + }) + .map((component) => ({ + // on all unique components, set the apiVersion to latest one + ...component, + apiVersion: cmpToApiVersion[component.kind] || component.apiVersion, // fallback in case of mishap + })); +} + +function sortMeshModelComponents(components) { + return [...components].sort((a, b) => a.kind.localeCompare(b.kind)); +} + +export const removeDuplicatesAndSortByAlphabet = _.flowRight( + sortMeshModelComponents, + removeDuplicateMeshModelComponents, +); + +// processing includes sorting and deduplicating components +function getProcessedMeshModelResponseData(meshModelResponse) { + return [...meshModelResponse] + .map((meshmodel) => ({ + ...meshmodel, + components: removeDuplicatesAndSortByAlphabet(meshmodel.components), + })) + .sort((modelA, modelB) => versionSortComparatorFn(modelA.version, modelB.version)) + .reverse(); // sort the versions in reverse order +} + +function deduplicatedListOfComponentsFromAllVersions(components) { + const uniqueComponents = [...new Set(components.map((comp) => comp.kind))]; + return uniqueComponents.map((compKind) => components.find((c) => c.kind === compKind)); +} + +function groupComponentsByVersion(components) { + const versions = [...new Set(components.map((component) => component.model.version))]; + + if (versions.length > 1) { + return [ + { + version: WILDCARD_V, + components: deduplicatedListOfComponentsFromAllVersions(components), + }, + ...versions.map((version) => ({ + version: version, + components: components.filter((component) => component.model.version === version), + })), + ]; + } + + // don't attach the wildcards + return versions.map((version) => ({ + version: version, + components: components.filter((component) => component.model.version === version), + })); +} + +const getProcessedComponentsData = compose( + getProcessedMeshModelResponseData, + groupComponentsByVersion, +); + +function convertToArray(item) { + if (Array.isArray(item)) return item; + + return [item]; +} + +export function useMeshModelComponents() { + const [meshmodelComponents, setMeshModelComponents] = useState({}); + const [categories, setCategories] = useState([]); + const [models, setModels] = useState({}); + + useEffect(() => { + fetchCategories() + .then((categoryJson) => { + setCategories( + categoryJson.categories.sort((catA, catB) => catA.name.localeCompare(catB.name)), + ); + }) + .catch(handleError); + }, []); + + async function getModelFromCategory(category) { + // already fetched the models from catgory and stored + if (models[category]) { + return; + } + + getModelFromCategoryApi(category) + .then((response) => { + setModels( + Object.assign( + { ...models }, + { + [category]: sortAndGroupVersionsInModel(response.models), + }, + ), + ); + }) + .catch(handleError); + } + + async function getComponentsFromModel(modelName, version) { + if (!version) { + if (!meshmodelComponents[modelName]) { + const modelData = await getComponentFromModelApi(modelName); + + setMeshModelComponents( + Object.assign( + { ...meshmodelComponents }, + { + [modelName]: getProcessedComponentsData(modelData.components), + }, + ), + ); + } + return; + } + + if ( + !meshmodelComponents[modelName] || + !convertToArray(meshmodelComponents[modelName])?.find((model) => model.version === version) + ) { + const modelData = await getVersionedComponentFromModel(modelName, version); + setMeshModelComponents( + Object.assign( + { ...meshmodelComponents }, + { + [modelName]: getProcessedComponentsData(modelData.components), + }, + ), + ); + } + } + + return { + models, + meshmodelComponents, + getModelFromCategory, + getComponentsFromModel, + categories, + }; +} diff --git a/examples/next-14/lib/hooks/useNotification.jsx b/examples/next-14/lib/hooks/useNotification.jsx new file mode 100644 index 00000000..9f891886 --- /dev/null +++ b/examples/next-14/lib/hooks/useNotification.jsx @@ -0,0 +1,106 @@ +import React from 'react'; +import { CloseIcon, BellIcon } from '@layer5/sistent'; +import { ToggleButtonGroup, IconButton } from '@layer5/sistent'; +import { AddClassRecursively } from '@/utils/Elements'; +import { v4 } from 'uuid'; +import { store as rtkStore } from '../redux'; +import { useSnackbar } from 'notistack'; +import { NOTIFICATION_CENTER_TOGGLE_CLASS } from '@/components/NotificationCenter/constants/notification'; +import { toggleNotificationCenter } from '../redux/features/events/events.slice'; +import moment from 'moment'; + +/** + * A React hook to facilitate emitting events from the client. + * The hook takes care of storing the events on the client through Redux + * and also notifying the user through snackbars and the notification center. + * + * @returns {Object} An object with the `notify` property. + */ +export const useNotification = () => { + const x = useSnackbar(); + const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + + /** + * Opens an event in the notification center. + * + * @param {string} eventId - The ID of the event to be opened. + */ + const openEvent = (eventId) => { + rtkStore.dispatch(toggleNotificationCenter()); + }; + + /** + * Notifies and stores the event. + * + * @param {Object} options - Options for the event notification. + * @param {string} options.id - A unique ID for the event. If not provided, a random ID will be generated. + * @param {string} options.message - Summary of the event. + * @param {string} options.details - Description of the event. + * @param {Object} options.event_type - The type of the event. + * @param {number} options.timestamp - UTC timestamp for the event. If not provided, it is generated on the client. + * @param {Object} options.customEvent - Additional properties related to the event. + * @param {boolean} options.showInNotificationCenter - Whether to show the event in the notification center. Defaults to `true`. + * @param {boolean} options.pushToServer - Whether to push the event to the server. Defaults to `false`. + */ + const notify = ({ + id = null, + message, + details = null, + event_type, + timestamp = null, + customEvent = null, + showInNotificationCenter = false, + pushToServer = false, + }) => { + timestamp = timestamp ?? moment.utc().valueOf(); + id = id || v4(); + + enqueueSnackbar(message, { + //NOTE: Need to Consolidate the variant and event_type + variant: typeof event_type === 'string' ? event_type : event_type?.type, + action: function Action(key) { + return ( + <ToggleButtonGroup> + {showInNotificationCenter && ( + <AddClassRecursively className={NOTIFICATION_CENTER_TOGGLE_CLASS}> + <IconButton + key={`openevent-${id}`} + aria-label="Open" + color="inherit" + onClick={() => openEvent(id)} + > + <BellIcon {...iconMedium} /> + </IconButton> + </AddClassRecursively> + )} + <IconButton + key={`closeevent-${id}`} + aria-label="Close" + color="inherit" + onClick={() => closeSnackbar(key)} + > + <CloseIcon style={iconMedium} /> + </IconButton> + </ToggleButtonGroup> + ); + }, + }); + }; + + return { + notify, + }; +}; + +/** + * A higher-order component that provides the `notify` function as a prop to a class-based component. + * + * @param {React.Component} Component - The class-based component to be wrapped. + * @returns {React.Component} The wrapped component with the `notify` prop. + */ +export function withNotify(Component) { + return function WrappedWithNotify(props) { + const { notify } = useNotification(); + return <Component {...props} notify={notify} />; + }; +} diff --git a/examples/next-14/lib/hooks/usePreventUserFromLeavingPage.jsx b/examples/next-14/lib/hooks/usePreventUserFromLeavingPage.jsx new file mode 100644 index 00000000..f6198314 --- /dev/null +++ b/examples/next-14/lib/hooks/usePreventUserFromLeavingPage.jsx @@ -0,0 +1,43 @@ +import SingletonRouter, { Router } from 'next/router'; +import React from 'react'; + +/** + * Restrict the user to navigate away to another page + * @param {bool} preventLeave + * @returns + */ +export default function usePreventUserFromLeavingPage(preventLeave) { + const confirmationMsg = 'You might have some unsaved changes. Are you sure you want to leave?'; + const [shouldPreventLeaving, setShouldPreventLeaving] = React.useState(!!preventLeave); + + React.useEffect(() => { + // Prevents tab quit / tab refresh + if (shouldPreventLeaving) { + // Adding window alert if the shop quits without saving + window.onbeforeunload = function () { + return confirmationMsg; + }; + } else { + window.onbeforeunload = () => {}; + } + + if (shouldPreventLeaving) { + // Prevents next routing + SingletonRouter.router.change = (...args) => { + if (confirm(confirmationMsg)) { + return Router.prototype.change.apply(SingletonRouter.router, args); + } else { + /* eslint-disable */ + return new Promise((resolve, reject) => resolve(false)); + } + }; + } + + // unmount + return () => { + delete SingletonRouter.router.change; + }; + }, [shouldPreventLeaving]); + + return setShouldPreventLeaving; +} diff --git a/examples/next-14/lib/hooks/useStateCallback.jsx b/examples/next-14/lib/hooks/useStateCallback.jsx new file mode 100644 index 00000000..c09566f7 --- /dev/null +++ b/examples/next-14/lib/hooks/useStateCallback.jsx @@ -0,0 +1,31 @@ +import React from 'react'; + +function useStateCallback(initState, changeTrackCB) { + const [state, _setState] = React.useState(initState); + const stateRef = React.useRef(initState); + + const callbackRef = React.useRef(); + const changeTrackCBRef = React.useRef(changeTrackCB); + const isFirstCBCall = React.useRef(true); + + React.useEffect(() => { + if (isFirstCBCall.current) isFirstCBCall.current = false; + else { + callbackRef.current?.(state); + changeTrackCBRef.current?.(state); + } + }, [state]); + + const setState = (state, callback) => { + callbackRef.current = callback; + + stateRef.current = state; + _setState(state); + }; + + const getStateRefValue = () => stateRef.current; + + return [state, setState, getStateRefValue]; +} + +export default useStateCallback; diff --git a/examples/next-14/lib/hooks/useTelemetry.jsx b/examples/next-14/lib/hooks/useTelemetry.jsx new file mode 100644 index 00000000..e69de29b diff --git a/examples/next-14/lib/hooks/useUpdateMetadata.jsx b/examples/next-14/lib/hooks/useUpdateMetadata.jsx new file mode 100644 index 00000000..121e06cd --- /dev/null +++ b/examples/next-14/lib/hooks/useUpdateMetadata.jsx @@ -0,0 +1,38 @@ +/** + * React Custom Hook + * useUpdateMetadata + * 1. update the page path + * 2. update the page title + * 3. update the beta badge status + */ +import { useReducer } from 'react'; +import pageSlice, { + updateBadgeStatus, + updatePathTitle, + updatePagePath, +} from '../redux/features/page/page.slice'; + +const pageReducer = pageSlice.reducer; + +export const useUpdateMetadata = () => { + const [state, dispatch] = useReducer(pageReducer, pageReducer.initialState); + + const setPagePath = (path) => { + dispatch(updatePagePath({ path })); + }; + + const setPageTite = (title) => { + dispatch(updatePathTitle({ title })); + }; + + const setBadgeStatus = (badge) => { + dispatch(updateBadgeStatus({ badge })); + }; + + return { + state, + setPagePath, + setPageTite, + setBadgeStatus, + }; +}; diff --git a/examples/next-14/lib/redux/features/config/k8sConfig.slice.js b/examples/next-14/lib/redux/features/config/k8sConfig.slice.js new file mode 100644 index 00000000..5844c924 --- /dev/null +++ b/examples/next-14/lib/redux/features/config/k8sConfig.slice.js @@ -0,0 +1,70 @@ +import { promisifiedDataFetch } from '@/utils/dataFetch'; +import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { K8sConfigState } from '../../types'; +import { deleteKubernetesConfig } from './k8sConfig.thunk'; + +/** + * Interface for providing extra arguments to async thunk functions. + * @interface ExtraArgument + * @property {(data: any) => void} successCallback - Callback function to handle success. + * @property {(error: any) => void} errorCallback - Callback function to handle error. + */ + +/** + * Async thunk to load active Kubernetes contexts. + */ +export const loadActiveK8sContexts = createAsyncThunk( + 'kubernetes/loadActiveContexts', + async (_, { rejectWithValue }) => { + try { + const res = await promisifiedDataFetch('/api/system/sync'); + + if (res?.k8sConfig) { + return res.k8sConfig; + } else { + throw new Error('No Kubernetes configurations found'); + } + } catch (error) { + console.error('An error occurred while loading k8sconfig', error); + return rejectWithValue(error?.message); + } + }, +); + +/** + * Initial state for the Kubernetes configuration slice. + * @type {K8sConfigState} + */ +const initialState = { + k8sConfig: [], +}; + +/** + * Slice for managing Kubernetes configuration. + */ +const k8sConfigSlice = createSlice({ + name: 'k8sConfig', + initialState, + reducers: { + /** + * Reducer to update Kubernetes configuration. + * @param {K8sConfigState} state - Current state. + * @param {PayloadAction<K8sConfigState>} action - Payload action. + */ + updateK8SConfig: (state, action) => { + return action.payload.k8sConfig; + }, + }, + extraReducers: (builder) => { + builder + .addCase(loadActiveK8sContexts.fulfilled, (state, action) => { + return action.payload; + }) + .addCase(deleteKubernetesConfig.fulfilled, (state, action) => { + return action.payload; + }); + }, +}); + +export const { updateK8SConfig } = k8sConfigSlice.actions; +export default k8sConfigSlice; diff --git a/examples/next-14/lib/redux/features/config/k8sConfig.thunk.js b/examples/next-14/lib/redux/features/config/k8sConfig.thunk.js new file mode 100644 index 00000000..02ba2d17 --- /dev/null +++ b/examples/next-14/lib/redux/features/config/k8sConfig.thunk.js @@ -0,0 +1,154 @@ +import dataFetch from '@/utils/dataFetch'; +import { createAsyncThunk } from '@reduxjs/toolkit'; +import { updateK8SConfig } from './k8sConfig.slice'; +import { NOTIFICATION_EVENT_TYPES } from '@/utils/constants/notification'; + +/** + * Async thunk to ping a Kubernetes connection. + * @param {string} connectionId - The ID of the Kubernetes connection to ping. + * @param {object} thunkAPI - The Redux Thunk API. + */ +export const pingKubernetes = createAsyncThunk( + 'kubernetes/ping', + async (connectionId, { dispatch }) => { + try { + const res = await dataFetch(`/api/system/kubernetes/ping?connection_id=${connectionId}`, { + credentials: 'include', + }); + + // Dispatch the result to update the state + dispatch(updateK8SConfig({ k8sConfig: res })); + } catch (error) { + console.error('Error pinging Kubernetes:', error); + } + }, +); + +/** + * Async thunk to delete a Kubernetes configuration. + * @param {string} connectionId - The ID of the Kubernetes configuration to delete. + * @param {object} thunkAPI - The Redux Thunk API. + */ +export const deleteKubernetesConfig = createAsyncThunk( + 'kubernetes/deleteConfig', + async (connectionId, { dispatch }) => { + try { + const res = await dataFetch(`/api/system/kubernetes/contexts/${connectionId}`, { + method: 'DELETE', + credentials: 'include', + }); + + // Dispatch the result to update the state + dispatch(updateK8SConfig({ k8sConfig: res })); + } catch (error) { + console.error('Error deleting Kubernetes config:', error); + } + }, +); + +/** + * Arguments for fetching Kubernetes contexts. + * @typedef {object} FetchContextsArgs + * @property {Function} updateProgress - Function to update progress. + * @property {string} k8sfile - The Kubernetes file. + */ + +/** + * Async thunk to fetch Kubernetes contexts. + */ +export const fetchContexts = createAsyncThunk( + 'kubernetes/fetchContexts', + async ({ updateProgress, k8sfile }) => { + try { + const formData = new FormData(); + formData.append('k8sfile', k8sfile); + + updateProgress({ showProgress: true }); + + const result = await dataFetch('/api/system/kubernetes/contexts', { + method: 'POST', + credentials: 'include', + body: formData, + }); + + updateProgress({ showProgress: false }); + + if (typeof result !== 'undefined') { + let ctName = ''; + result.forEach(({ contextName, currentContext }) => { + if (currentContext) { + ctName = contextName; + } + }); + + return { result, currentContextName: ctName }; + } + + throw new Error('Unexpected result from server'); + } catch (error) { + console.error('Error fetching Kubernetes contexts:', error); + throw error; // Propagate the error so it can be handled by the rejected action + } + }, +); + +/** + * Arguments for submitting Kubernetes configuration. + * @typedef {object} SubmitConfigArgs + * @property {Function} notify - Function to notify. + * @property {Function} updateProgress - Function to update progress. + * @property {string} contextName - The context name. + * @property {string} k8sfile - The Kubernetes file. + */ + +/** + * Async thunk to submit Kubernetes configuration. + */ +export const submitConfig = createAsyncThunk( + 'kubernetes/submitConfig', + async ({ notify, updateProgress, contextName, k8sfile }) => { + try { + const inClusterConfigForm = false; + const formData = new FormData(); + formData.append('inClusterConfig', inClusterConfigForm ? 'on' : ''); + + if (!inClusterConfigForm) { + formData.append('contextName', contextName); + formData.append('k8sfile', k8sfile); + } + + updateProgress({ showProgress: true }); + + const result = await dataFetch('/api/system/kubernetes', { + method: 'POST', + credentials: 'include', + body: formData, + }); + + updateProgress({ showProgress: false }); + + if (typeof result !== 'undefined') { + notify({ + message: 'Kubernetes config was validated!', + event_type: NOTIFICATION_EVENT_TYPES.SUCCESS, + }); + + // Dispatch the result to update the state + return updateK8SConfig({ + k8sConfig: { + inClusterConfig: inClusterConfigForm, + k8sfile, + contextName: result.contextName, + clusterConfigured: true, + configuredServer: result.configuredServer, + }, + }); + } + + throw new Error('Unexpected result from server'); + } catch (error) { + console.error('Error submitting Kubernetes config:', error); + throw error; // Propagate the error so it can be handled by the rejected action + } + }, +); diff --git a/examples/next-14/lib/redux/features/connection/connection.slice.js b/examples/next-14/lib/redux/features/connection/connection.slice.js new file mode 100644 index 00000000..ba6be709 --- /dev/null +++ b/examples/next-14/lib/redux/features/connection/connection.slice.js @@ -0,0 +1,24 @@ +import { createSlice } from '@reduxjs/toolkit'; +import { ConnectionState } from '../../types'; + +/** + * Initial state for the connection slice. + * @type {ConnectionState} + */ +const initialState = { + connectionMetadataState: null, +}; + +const connectionSlice = createSlice({ + name: 'connection', + initialState, + reducers: { + setConnectionMetadata: (state, action) => { + state.connectionMetadataState = action.payload.connectionMetadataState; + }, + }, +}); + +export const { setConnectionMetadata } = connectionSlice.actions; + +export default connectionSlice; diff --git a/examples/next-14/lib/redux/features/contexts/contexts.slice.js b/examples/next-14/lib/redux/features/contexts/contexts.slice.js new file mode 100644 index 00000000..8e759101 --- /dev/null +++ b/examples/next-14/lib/redux/features/contexts/contexts.slice.js @@ -0,0 +1,48 @@ +import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; + +// Define the async thunk for fetching contexts +export const fetchContextsAsync = createAsyncThunk( + 'contexts/fetchContexts', + async (params, { rejectWithValue }) => { + try { + const { number = 10, search = '' } = params; + const response = await promisifiedDataFetch( + `/api/system/kubernetes/contexts?pagesize=${number}&search=${encodeURIComponent(search)}`, + ); + return response; + } catch (error) { + // Handle errors and provide additional information if needed + return rejectWithValue(error.message || 'Failed to fetch contexts'); + } + }, +); + +// Define the initial state +const initialState = { + contexts: [], + status: 'idle', + error: null, +}; + +// Create a slice +const contextsSlice = createSlice({ + name: 'contexts', + initialState, + reducers: {}, + extraReducers: (builder) => { + builder + .addCase(fetchContextsAsync.pending, (state) => { + state.status = 'loading'; + }) + .addCase(fetchContextsAsync.fulfilled, (state, action) => { + state.status = 'succeeded'; + state.contexts = action.payload; + }) + .addCase(fetchContextsAsync.rejected, (state, action) => { + state.status = 'failed'; + state.error = action.payload; + }); + }, +}); + +export default contextsSlice; diff --git a/examples/next-14/lib/redux/features/events/events.slice.js b/examples/next-14/lib/redux/features/events/events.slice.js new file mode 100644 index 00000000..5d57806d --- /dev/null +++ b/examples/next-14/lib/redux/features/events/events.slice.js @@ -0,0 +1,120 @@ +import { SEVERITY, STATUS } from '@/components/NotificationCenter/constants/notification'; +import { createEntityAdapter, createSlice } from '@reduxjs/toolkit'; + +const initialState = { + current_view: { + page: 1, + page_size: 10, + filters: { + initial: true, + }, + has_more: true, + }, + + isNotificationCenterOpen: false, +}; + +const defaultEventProperties = { + severity: SEVERITY.INFO, + status: STATUS.UNREAD, +}; + +const eventsEntityAdapter = createEntityAdapter({ + selectId: (event) => event.id, + //sort based on update_at timestamp(utc) + sortComparer: (a, b) => { + if (b?.created_at?.localeCompare && a?.created_at?.localeCompare) { + return b.created_at?.localeCompare(a.created_at); + } + return 0; + }, +}); + +export const eventsSlice = createSlice({ + name: 'events', + initialState: eventsEntityAdapter.getInitialState(initialState), + reducers: { + clearEvents: (state) => { + state.events = []; + }, + + setEvents: (state, action) => { + eventsEntityAdapter.removeAll(state); + eventsEntityAdapter.addMany(state, action.payload); + + state.current_view.has_more = action.payload.length == 0 ? false : true; + }, + + pushEvents: (state, action) => { + eventsEntityAdapter.addMany(state, action.payload); + state.current_view.has_more = action.payload.length == 0 ? false : true; + }, + + pushEvent: (state, action) => { + const event = { + ...action.payload, + severity: action.payload?.severity?.trim() || defaultEventProperties.severity, + status: action.payload?.status?.trim() || defaultEventProperties.status, + }; + eventsEntityAdapter.addOne(state, event); + // state.events = [event, ...state.events] + }, + + updateEvent: eventsEntityAdapter.updateOne, + updateEvents: eventsEntityAdapter.updateMany, + updateIsEventChecked: (state, { payload }) => { + const { id, value } = payload; + eventsEntityAdapter.updateOne(state, { + id, + changes: { + checked: value, + }, + }); + }, + + updateCheckAllEvents: (state, { payload }) => { + const updates = Object.keys(state.entities).map((id) => ({ + id, + changes: { + checked: payload, + }, + })); + console.log('updates', updates); + eventsEntityAdapter.updateMany(state, updates); + }, + + clearCurrentView: (state) => { + state.current_view = initialState.current_view; + state.events = []; + }, + + setCurrentView: (state, action) => { + state.current_view = action.payload; + }, + + toggleNotificationCenter: (state) => { + state.isNotificationCenterOpen = !state.isNotificationCenterOpen; + }, + + closeNotificationCenter: (state) => { + state.isNotificationCenterOpen = false; + }, + }, +}); + +export const { + pushEvent, + clearEvents, + setEvents, + clearCurrentView, + updateIsEventChecked, + updateCheckAllEvents, + pushEvents, + setCurrentView, + updateEvent, + toggleNotificationCenter, + closeNotificationCenter, + updateEvents, +} = eventsSlice.actions; + +export default eventsSlice; diff --git a/examples/next-14/lib/redux/features/navigator/nav.slice.js b/examples/next-14/lib/redux/features/navigator/nav.slice.js new file mode 100644 index 00000000..cb4418cc --- /dev/null +++ b/examples/next-14/lib/redux/features/navigator/nav.slice.js @@ -0,0 +1,42 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { NavigatorState } from '../../types'; + +/** + * Initial state for the navigator slice. + * @type {NavigatorState} + */ +const initialState = { + isOpen: false, +}; + +/** + * The navigator slice containing reducers for toggling and setting drawer state. + */ +const navSlice = createSlice({ + name: 'drawer', + initialState, + reducers: { + /** + * Toggles the drawer state. + * @param {NavigatorState} state - Current navigator state. + */ + toggleDrawer: (state) => { + state.isOpen = !state.isOpen; + }, + /** + * Sets the drawer state. + * @param {NavigatorState} state - Current navigator state. + * @param {PayloadAction<boolean>} action - Action containing the new drawer state. + */ + setDrawerOpen: (state, action) => { + state.isOpen = action.payload; + }, + }, +}); + +/** + * Exporting actions from the navigator slice. + */ +export const { toggleDrawer, setDrawerOpen } = navSlice.actions; + +export default navSlice; diff --git a/examples/next-14/lib/redux/features/page/page.slice.js b/examples/next-14/lib/redux/features/page/page.slice.js new file mode 100644 index 00000000..1860fbc6 --- /dev/null +++ b/examples/next-14/lib/redux/features/page/page.slice.js @@ -0,0 +1,59 @@ +import { createSlice } from '@reduxjs/toolkit'; +import { PageState } from '../../types'; + +/** + * Initial state for the page slice. + * @type {PageState} + */ +const initialState = { + path: '', + title: '', + isBeta: false, +}; + +/** + * The page slice containing reducers for updating page information. + */ +const pageSlice = createSlice({ + name: 'page', + initialState, + reducers: { + /** + * Updates the page path. + * @param {PageState} state - Current page state. + * @param {PayloadAction<string>} action - Action containing the new path. + */ + updatePagePath: (state, action) => { + state.path = action.payload; + }, + /** + * Updates the page title. + * @param {PageState} state - Current page state. + * @param {PayloadAction<string>} action - Action containing the new title. + */ + updatePathTitle: (state, action) => { + state.title = action.payload; + }, + /** + * Updates the badge status of the page. + * @param {PageState} state - Current page state. + * @param {PayloadAction<boolean>} action - Action containing the new badge status. + */ + updateBadgeStatus: (state, action) => { + state.isBeta = action.payload; + }, + }, + extraReducers: (builder) => { + builder.addCase(updatePathTitle, (state, action) => { + state.path = action.payload.path; + state.title = action.payload.title; + }); + }, +}); + +/** + * Exporting actions from the page slice. + */ +export const { updatePagePath, updatePathTitle, updateBadgeStatus } = pageSlice.actions; + +export default pageSlice; diff --git a/examples/next-14/lib/redux/features/progress/progress.slice.js b/examples/next-14/lib/redux/features/progress/progress.slice.js new file mode 100644 index 00000000..ae17dc0a --- /dev/null +++ b/examples/next-14/lib/redux/features/progress/progress.slice.js @@ -0,0 +1,35 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { ProgressState } from '../../types'; + +/** + * Initial state for the progress slice. + * @type {ProgressState} + */ +const initialState = { + showProgress: false, +}; + +/** + * The progress slice containing a reducer for updating progress state. + */ +const progressSlice = createSlice({ + name: 'progress', + initialState, + reducers: { + /** + * Updates the progress state. + * @param {ProgressState} state - Current progress state. + * @param {PayloadAction<{ showProgress: boolean }>} action - Action containing the new progress state. + */ + updateProgress: (state, action) => { + state.showProgress = action.payload.showProgress; + }, + }, +}); + +/** + * Exporting action from the progress slice. + */ +export const { updateProgress } = progressSlice.actions; + +export default progressSlice; diff --git a/examples/next-14/lib/redux/features/provider/provider.slice.js b/examples/next-14/lib/redux/features/provider/provider.slice.js new file mode 100644 index 00000000..2ab7974e --- /dev/null +++ b/examples/next-14/lib/redux/features/provider/provider.slice.js @@ -0,0 +1,124 @@ +import { createSlice, createAction, createAsyncThunk } from '@reduxjs/toolkit'; +import { ProvidersState } from '../../types'; + +/** + * Async thunk to fetch providers data. + * @param {void} _ - No parameters needed. + * @param {object} thunkAPI - The Redux Thunk API. + * @returns {Promise<Record<string, any>>} - A promise resolving to the fetched providers data. + */ +export const fetchProviders = createAsyncThunk('providers/fetchProviders', async (_, thunkAPI) => { + try { + const response = await fetch('http://localhost:9081/api/providers', { + method: 'GET', + credentials: 'include', + }); + + // Log the response here + console.log('Response:', response); + + if (!response.ok) { + // Handle non-OK responses + const errorText = await response.text(); + return thunkAPI.rejectWithValue(errorText); + } + + const result = await response.json(); + + // Log the result here + console.log('Result:', result); + + // Assuming the structure you want is nested under the "Meshery" key + const mesheryData = result['Meshery']; + + if (!mesheryData) { + // Handle the case where the structure is not found + return thunkAPI.rejectWithValue('Meshery data not found'); + } + + // Assuming you also want information from the "None" key + const noneData = result['None']; + + if (!noneData) { + // Handle the case where the structure is not found + return thunkAPI.rejectWithValue('None data not found'); + } + + // Extract capabilities from Meshery + const mesheryCapabilities = extractCapabilities(mesheryData); + + // Extract capabilities from None + const noneCapabilities = extractCapabilities(noneData); + + // You can now use mesheryCapabilities and noneCapabilities as needed + console.log('Meshery Capabilities:', mesheryCapabilities); + console.log('None Capabilities:', noneCapabilities); + + return { mesheryData, noneData, mesheryCapabilities, noneCapabilities }; + } catch (error) { + // Handle other errors + console.error('Error in fetchProviders:', error); + return thunkAPI.rejectWithValue(error?.message); + } +}); + +// Helper function to extract capabilities from a provider +/** + * Helper function to extract capabilities from a provider data object. + * @param {Record<string, any>} providerData - The provider data object. + * @returns {any[]} - An array of capabilities extracted from the provider data. + */ +function extractCapabilities(providerData) { + const capabilities = []; + + if (providerData && providerData.capabilities) { + Object.keys(providerData.capabilities).forEach((key) => { + capabilities.push(providerData.capabilities[key]); + }); + } + + return capabilities; +} + +/** + * Initial state for the provider slice. + * @type {ProvidersState} + */ +const initialState = { + providers: undefined, + status: 'idle', + error: null, + selectedProvider: '', +}; + +const providerSlice = createSlice({ + name: 'providers', + initialState, + reducers: {}, + extraReducers: (builder) => { + builder + .addCase(fetchProviders.pending, (state) => { + state.status = 'loading'; + }) + .addCase(fetchProviders.fulfilled, (state, action) => { + state.status = 'succeeded'; + state.providers = action.payload; + }) + .addCase(fetchProviders.rejected, (state, action) => { + state.status = 'failed'; + state.error = action.error.message ?? null; + }) + .addCase(setSelectedProvider, (state, action) => { + state.selectedProvider = action.payload; + }); + }, +}); + +/** + * Action creator to set the selected provider. + * @param {string} payload - The ID of the selected provider. + * @returns {PayloadAction<string>} - The action containing the payload. + */ +export const setSelectedProvider = createAction('providers/setSelectedProvider'); + +export default providerSlice; diff --git a/examples/next-14/lib/redux/features/session/session.slice.js b/examples/next-14/lib/redux/features/session/session.slice.js new file mode 100644 index 00000000..15b7ce64 --- /dev/null +++ b/examples/next-14/lib/redux/features/session/session.slice.js @@ -0,0 +1,57 @@ +import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; +import { SessionState } from '../../types'; + +/** + * Initial state for the session slice. + * @type {SessionState} + */ +const initialState = { + countdown: 3, + sessionData: null, +}; + +/** + * Thunk action creator for fetching session data asynchronously. + * @type {import("@reduxjs/toolkit").AsyncThunk<*, *, {}>} + */ +export const fetchSessionData = createAsyncThunk( + 'session/fetchSessionData', + /** + * Async function to fetch session data. + * @param {*} _ - The payload (not used in this case). + * @param {Object} thunkAPI - The Redux toolkit `thunkAPI` object. + * @returns {Promise<SessionData>} A promise resolving to the session data. + */ + async (_, { getState }) => { + // Access the session data from the Redux store state + const { session } = getState(); + + // If the session data is already available in the Redux store, return it + if (session.sessionData) { + return session.sessionData; + } + + // If the session data is not available, you might need to handle it differently + // For example, you can throw an error or return a default value + + // Throw an error if session data is not available + throw new Error('Session data not available'); + }, +); + +/** + * Slice for managing session-related state. + * @type {import("@reduxjs/toolkit").Slice<SessionState, {}, string>} + */ +const sessionSlice = createSlice({ + name: 'session', + initialState, + reducers: {}, + extraReducers: (builder) => { + builder.addCase(fetchSessionData.fulfilled, (state, action) => { + state.sessionData = action.payload; + }); + }, +}); + +export default sessionSlice; diff --git a/examples/next-14/lib/redux/features/user/user.slice.js b/examples/next-14/lib/redux/features/user/user.slice.js new file mode 100644 index 00000000..c9902dc7 --- /dev/null +++ b/examples/next-14/lib/redux/features/user/user.slice.js @@ -0,0 +1,56 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { UserState } from '../../types'; + +/** + * Initial state for the users slice. + * @type {UserState} + */ +const initialState = { + user: {}, + loading: false, + error: '', +}; + +/** + * The users slice containing reducers for updating user information. + */ +const usersSlice = createSlice({ + name: 'users', + initialState, + reducers: { + /** + * Sets loading to true and clears error when updating user. + * @param {UserState} state - Current user state. + */ + updateUser: (state) => { + state.loading = true; + state.error = ''; + }, + /** + * Updates user information on successful update. + * @param {UserState} state - Current user state. + * @param {PayloadAction<UserState>} action - Action containing the updated user state. + */ + updateUserSuccess: (state, action) => { + state.user = action.payload.user; + state.loading = false; + state.error = ''; + }, + /** + * Updates error on failed user update. + * @param {UserState} state - Current user state. + * @param {PayloadAction<UserState>} action - Action containing the updated user state. + */ + updateUserFailure: (state, action) => { + state.loading = false; + state.error = action.payload.error; + }, + }, +}); + +/** + * Exporting actions from the users slice. + */ +export const { updateUser, updateUserSuccess, updateUserFailure } = usersSlice.actions; + +export default usersSlice; diff --git a/examples/next-14/lib/redux/index.jsx b/examples/next-14/lib/redux/index.jsx new file mode 100644 index 00000000..dada874e --- /dev/null +++ b/examples/next-14/lib/redux/index.jsx @@ -0,0 +1,13 @@ +import { rootReducer } from './root.reducer'; +import { api } from '../rtk-query/config'; +import { configureStore } from '@reduxjs/toolkit'; + +export const store = () => { + const newStore = configureStore({ + reducer: rootReducer, + devTools: true, + middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(api.middleware), + }); + + return newStore; +}; diff --git a/examples/next-14/lib/redux/root.reducer.js b/examples/next-14/lib/redux/root.reducer.js new file mode 100644 index 00000000..07693fae --- /dev/null +++ b/examples/next-14/lib/redux/root.reducer.js @@ -0,0 +1,37 @@ +import { combineReducers } from 'redux'; +import { api } from '../rtk-query/config'; +import navSlice from './features/navigator/nav.slice'; +import pageSlice from './features/page/page.slice'; +import progressSlice from './features/progress/progress.slice'; +import eventsSlice from './features/events/events.slice'; +import usersSlice from './features/user/user.slice'; +import k8sConfigSlice from './features/config/k8sConfig.slice'; +import contextsSlice from './features/contexts/contexts.slice'; +import sessionSlice from './features/session/session.slice'; +import connectionSlice from './features/connection/connection.slice'; + +export const rootReducer = (state, action) => { + const reducers = combineReducers({ + [api.reducerPath]: api.reducer, + // [themeSlice.name]: themeSlice.reducer, + [navSlice.name]: navSlice.reducer, + [usersSlice.name]: usersSlice.reducer, + [sessionSlice.name]: sessionSlice.reducer, + [progressSlice.name]: progressSlice.reducer, + [pageSlice.name]: pageSlice.reducer, + [k8sConfigSlice.name]: k8sConfigSlice.reducer, + [eventsSlice.name]: eventsSlice.reducer, + [contextsSlice.name]: contextsSlice.reducer, + [connectionSlice.name]: connectionSlice.reducer, + }); + if (action.type === 'HYDRATE') { + return reducers( + { + ...state, + ...action.payload, + }, + action, + ); + } + return reducers(state, action); +}; diff --git a/examples/next-14/lib/redux/rtk-query/queries/provider.js b/examples/next-14/lib/redux/rtk-query/queries/provider.js new file mode 100644 index 00000000..f985a5b0 --- /dev/null +++ b/examples/next-14/lib/redux/rtk-query/queries/provider.js @@ -0,0 +1,13 @@ +import { api } from '../config'; + +const providerApi = api.injectEndpoints({ + endpoints: (builder) => ({ + fetchProviders: builder.query({ + query: () => 'providers', + }), + }), +}); + +export const { useFetchProvidersQuery, useLazyFetchProvidersQuery } = providerApi; + +export default providerApi; diff --git a/examples/next-14/lib/redux/selectors.js b/examples/next-14/lib/redux/selectors.js new file mode 100644 index 00000000..07020942 --- /dev/null +++ b/examples/next-14/lib/redux/selectors.js @@ -0,0 +1,29 @@ +import { RootAppState } from './types'; + +/** + * Selector function to determine if the drawer is open. + * @param {RootAppState} state - The root app state. + * @returns {boolean} - True if the drawer is open, otherwise false. + */ +export const isDrawerOpenSelector = (state) => state.drawer.isOpen; + +/** + * Selector function to retrieve the providers from the state. + * @param {RootAppState} state - The root app state. + * @returns {Record<string, any> | undefined} - The providers or undefined if not available. + */ +export const selectProviders = (state) => state.providers; + +/** + * Selector function to retrieve the countdown value from the state. + * @param {RootAppState} state - The root app state. + * @returns {number} - The countdown value. + */ +export const selectCountdown = (state) => state.session.countdown; + +/** + * Selector function to determine if progress is being shown. + * @param {RootAppState} state - The root app state. + * @returns {boolean} - True if progress is being shown, otherwise false. + */ +export const selectShowProgress = (state) => state.progress.showProgress; diff --git a/examples/next-14/lib/redux/types.js b/examples/next-14/lib/redux/types.js new file mode 100644 index 00000000..12946819 --- /dev/null +++ b/examples/next-14/lib/redux/types.js @@ -0,0 +1,110 @@ +/** + * Represents the state of Kubernetes configuration. + * @typedef {Object} K8sConfigState + * @property {string[]} k8sConfig - Array of Kubernetes configurations. + */ + +/** + * Represents the state of the current page. + * @typedef {Object} PageState + * @property {string} path - The path of the current page. + * @property {string} title - The title of the current page. + * @property {boolean} isBeta - Indicates if the page is in beta. + */ + +/** + * Represents the state of progress. + * @typedef {Object} ProgressState + * @property {boolean} showProgress - Indicates whether progress is shown. + */ + +/** + * Represents the state of the application theme. + * @typedef {Object} ThemeState + * @property {boolean} darkTheme - Indicates if the dark theme is enabled. + */ + +/** + * Represents the state of the navigator. + * @typedef {Object} NavigatorState + * @property {boolean} isOpen - Indicates if the navigator is open. + */ + +/** + * Represents the state of the user. + * @typedef {Object} UserState + * @property {Object|null} user - User information. + * @property {boolean} [loading] - Indicates if the user is loading. + * @property {string} [error] - Error message. + */ + +/** + * Represents the state of the providers. + * @typedef {Object} ProvidersState + * @property {Record<string, any>|undefined} providers - Provider information. + * @property {"idle"|"loading"|"succeeded"|"failed"} status - Status of the provider. + * @property {string|null} error - Error message. + * @property {string} selectedProvider - Selected provider. + */ + +/** + * Represents the state of the session. + * @typedef {Object} SessionState + * @property {number} countdown - Countdown timer. + * @property {string|null} sessionData - Session data. + */ + +/** + * Represents the state of the connection. + * @typedef {Object} ConnectionState + * @property {null} connectionMetadataState - State of the connection metadata. + */ + +/** + * Represents the root application state. + * @typedef {Object} RootAppState + * @property {ThemeState} theme - Theme state. + * @property {NavigatorState} drawer - Drawer state. + * @property {UserState} user - User state. + * @property {ProvidersState} providers - Providers state. + * @property {SessionState} session - Session state. + * @property {ProgressState} progress - Progress state. + * @property {PageState} page - Page state. + * @property {K8sConfigState} k8sConfig - Kubernetes configuration state. + */ + +/** + * Represents a new instance of the application store. + * @typedef {Function} NewAppStore + * @returns {RootAppState} - The root application state. + */ + +/** + * Represents a new instance of the application state. + * @typedef {RootAppState} NewAppState + */ + +/** + * Represents an asynchronous action creator. + * @typedef {Function} AppThunk + * @param {...*} [ReturnType] - Return type of the thunk. + * @returns {ThunkAction<ReturnType, NewAppState, unknown, Action>} - Thunk action. + */ + +/** + * The store factory function. + * @type {NewAppStore} + */ +// export type NewAppStore = ReturnType<typeof newStore>; + +/** + * The application state type. + * @type {NewAppState} + */ +// export type NewAppState = ReturnType<NewAppStore["getState"]>; + +/** + * Represents a thunk action creator. + * @type {AppThunk} + */ +// export type AppThunk<ReturnType = void> = ThunkAction<ReturnType, NewAppState, unknown, Action>; diff --git a/examples/next-14/lib/relay/RelayEnvironment.jsx b/examples/next-14/lib/relay/RelayEnvironment.jsx new file mode 100644 index 00000000..1a310a4a --- /dev/null +++ b/examples/next-14/lib/relay/RelayEnvironment.jsx @@ -0,0 +1,54 @@ +import { promisifiedDataFetch } from '@/utils/dataFetch'; +import { createClient } from 'graphql-ws'; +import { Environment, Network, Observable, RecordSource, Store } from 'relay-runtime'; + +function fetchQuery(operation, variables) { + return promisifiedDataFetch('/api/system/graphql/query', { + method: 'POST', + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query: operation.text, + variables, + }), + }); +} + +export let subscriptionClient; + +if (typeof window !== 'undefined') { + const isWss = window.location.protocol === 'https:'; + const wsProtocol = isWss ? 'wss://' : 'ws://'; + subscriptionClient = createClient({ + url: wsProtocol + window.location.host + '/api/system/graphql/query', + }); +} + +function fetchOrSubscribe(operation, variables) { + return Observable.create((sink) => { + if (!operation.text) { + return sink.error(new Error('Operation text cannot be empty')); + } + return subscriptionClient.subscribe( + { + operationName: operation.name, + query: operation.text, + variables, + }, + sink, + ); + }); +} + +export const serializeRelayEnvironment = (environment) => { + return environment.getStore().getSource().toJSON(); +}; + +export const createRelayEnvironment = () => { + return new Environment({ + store: new Store(new RecordSource()), + network: Network.create(fetchQuery, fetchOrSubscribe), + }); +}; diff --git a/examples/next-14/lib/rtk-query/config/index.js b/examples/next-14/lib/rtk-query/config/index.js new file mode 100644 index 00000000..53fdd71a --- /dev/null +++ b/examples/next-14/lib/rtk-query/config/index.js @@ -0,0 +1,7 @@ +import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; + +export const api = createApi({ + reducerPath: 'mesheryApi', + baseQuery: fetchBaseQuery({ baseUrl: '/api/' }), + endpoints: () => ({}), +}); diff --git a/examples/next-14/lib/rtk-query/queries/ability.js b/examples/next-14/lib/rtk-query/queries/ability.js new file mode 100644 index 00000000..135731e9 --- /dev/null +++ b/examples/next-14/lib/rtk-query/queries/ability.js @@ -0,0 +1,42 @@ +import { useState, useEffect } from 'react'; +import { ability } from '@/utils/can'; +import { useLazyGetUserKeysQuery } from './userKeys'; + +export const useGetUserAbilities = (org, skip) => { + const [data, setData] = useState(null); + + /** + * RTk Lazy Query + */ + const [getUserQuery] = useLazyGetUserKeysQuery(); + + useEffect(() => { + getUserQuery({ orgId: org.id }, { skip }) + .unwrap() + .then((res) => { + const abilities = res.keys?.map((key) => ({ + action: key.id, + subject: key.function, + })); + + setData({ + ...res, + abilities: abilities, + }); + }) + .catch((error) => { + console.error('Error when fetching keys in useGetUserAbilities custom hook', error); + }); + }, [org.id, getUserQuery, skip]); + + return data; +}; + +export const useGetCurrentAbilities = (org, setKeys, skip) => { + const res = useGetUserAbilities(org, skip); + if (res?.abilities) { + ability.update(res.abilities); + setKeys({ keys: res.keys }); + } + return res; +}; diff --git a/examples/next-14/lib/rtk-query/queries/connection.js b/examples/next-14/lib/rtk-query/queries/connection.js new file mode 100644 index 00000000..3d1004fc --- /dev/null +++ b/examples/next-14/lib/rtk-query/queries/connection.js @@ -0,0 +1,93 @@ +const TAGS = { + CONNECTIONS: 'connections', +}; +import { api } from '../config'; + +const connectionsApi = api.injectEndpoints({ + endpoints: (builder) => ({ + getConnections: builder.query({ + query: (queryArg) => ({ + url: `integrations/connections`, + params: { + page: queryArg.page, + pagesize: queryArg.pagesize, + search: queryArg.search, + order: queryArg.order, + }, + method: 'GET', + }), + providesTags: () => [{ type: TAGS.CONNECTIONS }], + }), + getConnectionStatus: builder.query({ + query: (queryArg) => ({ + url: `integrations/connections/${queryArg.connectionKind}/status`, + params: { id: queryArg.repoURL }, + }), + }), + getConnectionDetails: builder.query({ + query: (queryArg) => ({ + url: `integrations/connections/${queryArg.connectionKind}/details`, + params: { id: queryArg.repoURL }, + }), + }), + verifyConnectionURL: builder.mutation({ + query: (queryArg) => ({ + url: `integrations/connections/${queryArg.connectionKind}/verify`, + method: 'POST', + params: { id: queryArg.repoURL }, + }), + }), + connectionMetaData: builder.mutation({ + query: (queryArg) => ({ + url: `integrations/connections/${queryArg.connectionKind}/metadata`, + method: 'POST', + body: queryArg.body, + }), + }), + configureConnection: builder.mutation({ + query: (queryArg) => ({ + url: `integrations/connections/${queryArg.connectionKind}/configure`, + method: 'POST', + body: queryArg.body, + }), + }), + updateConnection: builder.mutation({ + query: (queryArg) => ({ + url: `integrations/connections/${queryArg.connectionKind}/status`, + method: 'PUT', + body: queryArg.connectionPayload, + }), + invalidatesTags: () => [{ type: TAGS.CONNECTIONS }], + }), + getAllConnectionStatus: builder.query({ + query: () => ({ + url: `integrations/connections/status`, + method: 'GET', + }), + }), + getConnectionByKind: builder.query({ + query: (queryArg) => ({ + url: `integrations/connections/${queryArg.connectionKind}`, + params: { + page: queryArg.page, + pagesize: queryArg.pagesize, + search: queryArg.search, + order: queryArg.order, + }, + method: 'GET', + }), + }), + }), +}); + +export const { + useGetConnectionsQuery, + useGetConnectionStatusQuery, + useLazyGetConnectionDetailsQuery, + useVerifyConnectionURLMutation, + useConnectionMetaDataMutation, + useConfigureConnectionMutation, + useUpdateConnectionMutation, + useGetAllConnectionStatusQuery, + useGetConnectionByKindQuery, +} = connectionsApi; diff --git a/examples/next-14/lib/rtk-query/queries/design.js b/examples/next-14/lib/rtk-query/queries/design.js new file mode 100644 index 00000000..8d83f007 --- /dev/null +++ b/examples/next-14/lib/rtk-query/queries/design.js @@ -0,0 +1,29 @@ +import { api } from '../config'; + +const TAGS = { + DESIGNS: 'designs', +}; +const designs = api + .enhanceEndpoints({ + addTagTypes: [TAGS.DESIGNS], + }) + .injectEndpoints({ + endpoints: (builder) => ({ + getPatterns: builder.query({ + query: (queryArg) => ({ + url: `pattern`, + params: { + page: queryArg.page, + pagesize: queryArg.pagesize, + search: queryArg.search, + order: queryArg.order, + visibility: queryArg.visibility, + }, + method: 'GET', + }), + providesTags: () => [{ type: TAGS.DESIGNS }], + }), + }), + }); + +export const { useGetPatternsQuery } = designs; diff --git a/examples/next-14/lib/rtk-query/queries/environments.js b/examples/next-14/lib/rtk-query/queries/environments.js new file mode 100644 index 00000000..1ef437c4 --- /dev/null +++ b/examples/next-14/lib/rtk-query/queries/environments.js @@ -0,0 +1,116 @@ +import { api } from '../config'; + +const TAGS = { + ENVIRONMENT_CONNECTIONS: 'enivroment_connections', +}; +const connectionsApi = api + .enhanceEndpoints({ + addTagTypes: [TAGS.ENVIRONMENT_CONNECTIONS], + }) + .injectEndpoints({ + endpoints: (builder) => ({ + getEnvironments: builder.query({ + query: (queryArg) => ({ + url: `environments`, + params: { + search: queryArg.search, + order: queryArg.order, + page: queryArg.page || 0, + pagesize: queryArg.pagesize || 'all', + orgID: queryArg.orgId, + }, + method: 'GET', + }), + providesTags: () => [{ type: TAGS.ENVIRONMENT_CONNECTIONS }], + }), + + createEnvironment: builder.mutation({ + query: (queryArg) => ({ + url: `environments`, + method: 'POST', + body: queryArg.environmentPayload, + }), + + invalidatesTags: () => [{ type: TAGS.ENVIRONMENT_CONNECTIONS }], + }), + + updateEnvironment: builder.mutation({ + query: (queryArg) => ({ + url: `environments/${queryArg.environmentId}`, + method: 'PUT', + body: queryArg.environmentPayload, + }), + + invalidatesTags: () => [{ type: TAGS.ENVIRONMENT_CONNECTIONS }], + }), + + deleteEnvironment: builder.mutation({ + query: (queryArg) => ({ + url: `environments/${queryArg.environmentId}`, + method: 'DELETE', + }), + + invalidatesTags: () => [{ type: TAGS.ENVIRONMENT_CONNECTIONS }], + }), + + getEnvironmentConnections: builder.query({ + query: (queryArg) => ({ + url: `environments/${queryArg.environmentId}/connections`, + params: { + page: queryArg.page || 0, + per_page: queryArg.per_page, + pagesize: queryArg.pagesize || 'all', + filter: queryArg.filter, + }, + method: 'GET', + }), + providesTags: (_result, _error, arg) => [ + { type: TAGS.ENVIRONMENT_CONNECTIONS, id: arg.environmentId }, + ], + }), + + addConnectionToEnvironment: builder.mutation({ + query: (queryArg) => ({ + url: `environments/${queryArg.environmentId}/connections/${queryArg.connectionId}`, + method: 'POST', + body: {}, + }), + + invalidatesTags: (_result, _error, arg) => [ + { type: TAGS.ENVIRONMENT_CONNECTIONS, id: arg.environmentId }, + ], + }), + + removeConnectionFromEnvironment: builder.mutation({ + query: (queryArg) => ({ + url: `environments/${queryArg.environmentId}/connections/${queryArg.connectionId}`, + method: 'DELETE', + body: {}, + }), + + invalidatesTags: (_result, _error, arg) => [ + { type: TAGS.ENVIRONMENT_CONNECTIONS, id: arg.environmentId }, + ], + }), + + saveEnvironment: builder.mutation({ + query: (queryArg) => ({ + url: `environments`, + method: 'POST', + body: queryArg.body, + }), + invalidatesTags: [{ type: TAGS.ENVIRONMENT_CONNECTIONS }], + }), + }), + }); + +export const { + useGetEnvironmentsQuery, + useCreateEnvironmentMutation, + useUpdateEnvironmentMutation, + useDeleteEnvironmentMutation, + useGetEnvironmentConnectionsQuery, + useAddConnectionToEnvironmentMutation, + useRemoveConnectionFromEnvironmentMutation, + useSaveEnvironmentMutation, +} = connectionsApi; diff --git a/examples/next-14/lib/rtk-query/queries/filter.js b/examples/next-14/lib/rtk-query/queries/filter.js new file mode 100644 index 00000000..9a8cb70f --- /dev/null +++ b/examples/next-14/lib/rtk-query/queries/filter.js @@ -0,0 +1,29 @@ +import { api } from '../config'; + +const TAGS = { + FILTERS: 'filters', +}; +const filters = api + .enhanceEndpoints({ + addTagTypes: [TAGS.FILTERS], + }) + .injectEndpoints({ + endpoints: (builder) => ({ + getFilters: builder.query({ + query: (queryArg) => ({ + url: `filter`, + params: { + page: queryArg.page, + pagesize: queryArg.pagesize, + search: queryArg.search, + order: queryArg.order, + visibility: queryArg.visibility, + }, + method: 'GET', + }), + providesTags: () => [{ type: TAGS.FILTERS }], + }), + }), + }); + +export const { useGetFiltersQuery } = filters; diff --git a/examples/next-14/lib/rtk-query/queries/meshModel.js b/examples/next-14/lib/rtk-query/queries/meshModel.js new file mode 100644 index 00000000..ce294e7a --- /dev/null +++ b/examples/next-14/lib/rtk-query/queries/meshModel.js @@ -0,0 +1,91 @@ +import { api } from '../config'; + +import _ from 'lodash'; + +const TAGS = { + MESH_MODELS: 'mesh-models', +}; + +const defaultOptions = { + trim: false, + // annotations: false, + search: '', + page: 1, + pagesize: 'all', +}; + +const meshModelApi = api + .enhanceEndpoints({ + addTagTypes: [TAGS.MESH_MODELS], + }) + .injectEndpoints({ + endpoints: (builder) => ({ + getMeshModels: builder.query({ + query: (queryArgs) => ({ + url: `meshmodels/models`, + params: _.merge({}, defaultOptions, queryArgs.params), + }), + providesTags: () => [{ type: TAGS.MESH_MODELS }], + }), + getComponents: builder.query({ + query: (queryArgs) => ({ + url: `meshmodels/components`, + params: _.merge({}, defaultOptions, queryArgs.params), + }), + providesTags: () => [{ type: TAGS.MESH_MODELS }], + }), + getRelationships: builder.query({ + query: (queryArgs) => ({ + url: `meshmodels/relationships`, + params: _.merge({}, defaultOptions, queryArgs.params), + }), + providesTags: () => [{ type: TAGS.MESH_MODELS }], + }), + getRegistrants: builder.query({ + query: (queryArgs) => ({ + url: `meshmodels/registrants`, + params: _.merge({}, defaultOptions, queryArgs.params), + }), + providesTags: () => [{ type: TAGS.MESH_MODELS }], + }), + getComponentsFromModal: builder.query({ + query: (queryArgs) => ({ + url: `meshmodels/models/${queryArgs.model}/components`, + params: _.merge({}, defaultOptions, queryArgs.params), + }), + providesTags: () => [{ type: TAGS.MESH_MODELS }], + }), + getRelationshipsFromModal: builder.query({ + query: (queryArgs) => ({ + url: `meshmodels/models/${queryArgs.model}/relationships`, + params: _.merge({}, defaultOptions, queryArgs.params), + }), + providesTags: () => [{ type: TAGS.MESH_MODELS }], + }), + getModelCategories: builder.query({ + query: () => ({ + url: `meshmodels/categories`, + method: 'GET', + }), + providesTags: () => [{ type: TAGS.MESH_MODELS }], + }), + getModelFromCategory: builder.query({ + query: (queryArgs) => ({ + url: `meshmodels/categories/${queryArgs.category}/models`, + params: _.merge({}, defaultOptions, queryArgs.params), + }), + providesTags: () => [{ type: TAGS.MESH_MODELS }], + }), + }), + }); + +export const { + useLazyGetMeshModelsQuery, + useLazyGetComponentsQuery, + useLazyGetRelationshipsQuery, + useLazyGetRegistrantsQuery, + useLazyGetComponentsFromModalQuery, + useLazyGetRelationshipsFromModalQuery, + useGetModelCategoriesQuery, + useLazyGetModelFromCategoryQuery, +} = meshModelApi; diff --git a/examples/next-14/lib/rtk-query/queries/meshsync.js b/examples/next-14/lib/rtk-query/queries/meshsync.js new file mode 100644 index 00000000..90c2682a --- /dev/null +++ b/examples/next-14/lib/rtk-query/queries/meshsync.js @@ -0,0 +1,46 @@ +import { api } from '../config'; + +const TAGS = { + MESH_SYNC: 'meshsync', +}; + +const meshSyncApi = api.injectEndpoints({ + endpoints: (builder) => ({ + getMeshSyncResources: builder.query({ + query: (queryArg) => ({ + url: `system/meshsync/resources`, + params: { + page: queryArg.page, + pagesize: queryArg.pagesize, + search: queryArg.search, + order: queryArg.order, + kind: queryArg.kind, + clusterId: queryArg.clusterId, + label: queryArg.label, + status: queryArg.status, + annotation: queryArg.annotation, + spec: queryArg.spec, + apiVersion: queryArg.apiVersion, + }, + method: 'GET', + }), + providesTags: () => [{ type: TAGS.MESH_SYNC }], + }), + getMeshSyncResourceKinds: builder.query({ + query: (queryArg) => ({ + url: `system/meshsync/resources/kinds`, + params: { + page: queryArg.page, + pagesize: queryArg.pagesize, + search: queryArg.search, + order: queryArg.order, + clusterId: queryArg.clusterId, + }, + method: 'GET', + }), + providesTags: () => [{ type: TAGS.MESH_SYNC }], + }), + }), +}); + +export const { useGetMeshSyncResourcesQuery, useGetMeshSyncResourceKindsQuery } = meshSyncApi; diff --git a/examples/next-14/lib/rtk-query/queries/provider.js b/examples/next-14/lib/rtk-query/queries/provider.js new file mode 100644 index 00000000..f985a5b0 --- /dev/null +++ b/examples/next-14/lib/rtk-query/queries/provider.js @@ -0,0 +1,13 @@ +import { api } from '../config'; + +const providerApi = api.injectEndpoints({ + endpoints: (builder) => ({ + fetchProviders: builder.query({ + query: () => 'providers', + }), + }), +}); + +export const { useFetchProvidersQuery, useLazyFetchProvidersQuery } = providerApi; + +export default providerApi; diff --git a/examples/next-14/lib/rtk-query/queries/userKeys.js b/examples/next-14/lib/rtk-query/queries/userKeys.js new file mode 100644 index 00000000..05e5c95e --- /dev/null +++ b/examples/next-14/lib/rtk-query/queries/userKeys.js @@ -0,0 +1,26 @@ +import { api } from '../config'; + +const TAGS = { + USER_KEYS: 'user-keys', +}; + +const userKeysApi = api + .enhanceEndpoints({ + addTagTypes: [TAGS.USER_KEYS], + }) + .injectEndpoints({ + endpoints: (builder) => ({ + getUserKeys: builder.query({ + query: (queryArgs) => ({ + url: `identity/orgs/${queryArgs.orgId}/users/keys`, + params: { + page: queryArgs.page || 0, + pagesize: queryArgs.pagesize || 10, + }, + }), + providesTags: () => [{ type: TAGS.USER_KEYS }], + }), + }), + }); + +export const { useLazyGetUserKeysQuery } = userKeysApi; diff --git a/examples/next-14/middleware.jsx b/examples/next-14/middleware.jsx new file mode 100644 index 00000000..08db60e8 --- /dev/null +++ b/examples/next-14/middleware.jsx @@ -0,0 +1,24 @@ +import { NextResponse } from 'next/server'; + +export function middleware() { + // retrieve the current response + const res = NextResponse.next(); + + const allowCredentials = process.env.ACCESS_CONTROL_ALLOW_CREDENTIALS || 'false'; + const allowOrigin = process.env.ACCESS_CONTROL_ALLOW_ORIGIN || '*'; + const allowMethods = process.env.ACCESS_CONTROL_ALLOW_METHODS || 'GET, POST, PUT, DELETE'; + const allowHeaders = process.env.ACCESS_CONTROL_ALLOW_HEADERS || '*'; + + // add the CORS headers to the response + res.headers.append('Access-Control-Allow-Credentials', allowCredentials); + res.headers.append('Access-Control-Allow-Origin', allowOrigin); + res.headers.append('Access-Control-Allow-Methods', allowMethods); + res.headers.append('Access-Control-Allow-Headers', allowHeaders); + + return res; +} + +// specify the path regex to apply the middleware to +export const config = { + matcher: '/api/:path*', +}; diff --git a/examples/next-14/next.config.mjs b/examples/next-14/next.config.mjs new file mode 100644 index 00000000..cf2a699c --- /dev/null +++ b/examples/next-14/next.config.mjs @@ -0,0 +1,46 @@ +const API_URL = process.env.API_URL; + +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + compiler: { + relay: { + // ... + // Configuration options accepted by the `relay-compiler` command-line tool and `babel-plugin-relay`. + src: './components', + schema: './schema.graphql', + language: 'javascript', + excludes: ['**/node_modules/**', '**/__mocks__/**', '**/__generated__/**'], + }, + }, + async rewrites() { + return [ + { source: '/api/:path*', destination: `${API_URL}/:path*` }, + { source: '/user/:path*', destination: `${API_URL}/:path*` }, + { source: '/provider/:path*', destination: '/:path*' }, + ]; + }, + async headers() { + return [ + { + // matching all API routes + source: '/api/:path*', + headers: [ + { key: 'Access-Control-Allow-Credentials', value: 'true' }, + { key: 'Access-Control-Allow-Origin', value: '*' }, + { + key: 'Access-Control-Allow-Methods', + value: 'GET,DELETE,PATCH,POST,PUT', + }, + { + key: 'Access-Control-Allow-Headers', + value: + 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version', + }, + ], + }, + ]; + }, +}; + +export default nextConfig; diff --git a/examples/next-14/package-lock.json b/examples/next-14/package-lock.json new file mode 100644 index 00000000..74ab1dc3 --- /dev/null +++ b/examples/next-14/package-lock.json @@ -0,0 +1,6896 @@ +{ + "name": "next-14", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "next-14", + "version": "0.1.0", + "dependencies": { + "@casl/ability": "^6.5.0", + "@emotion/server": "^11.11.0", + "@layer5/sistent": "^0.14.29", + "@mui/icons-material": "^5.15.8", + "@mui/lab": "^5.0.0-alpha.164", + "@mui/material-nextjs": "^5.15.9", + "@mui/x-tree-view": "^6.17.0", + "@reduxjs/toolkit": "^2.1.0", + "axios": "^1.6.7", + "billboard.js": "^3.10.3", + "lodash": "^4.17.21", + "moment": "^2.30.1", + "next": "14.1.0", + "notistack": "^3.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-redux": "^9.1.0", + "redux": "^5.0.1" + }, + "devDependencies": { + "@babel/eslint-parser": "^7.23.10", + "ajv": "^8.12.0", + "eslint": "^8.56.0", + "eslint-config-next": "14.1.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-cypress": "^2.15.1", + "eslint-plugin-prettier": "^5.1.3", + "graphql-ws": "^5.14.3", + "http-proxy": "^1.18.1", + "prettier": "^3.2.5", + "react-relay": "^16.2.0", + "relay-compiler": "^16.2.0", + "relay-runtime": "^16.2.0", + "uuid": "^9.0.1" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "peer": true, + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", + "dev": true, + "peer": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.1.tgz", + "integrity": "sha512-d5guuzMlPeDfZIbpQ8+g1NaCNuAGBBGNECh0HVqz1sjOeVLh2CEaifuOysCH18URW6R7pqXINvf5PaR/dC6jLQ==", + "dev": true, + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "peer": true, + "dependencies": { + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", + "dev": true, + "peer": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", + "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "peer": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@casl/ability": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@casl/ability/-/ability-6.7.1.tgz", + "integrity": "sha512-e+Vgrehd1/lzOSwSqKHtmJ6kmIuZbGBlM2LBS5IuYGGKmVHuhUuyh3XgTn1VIw9+TO4gqU+uptvxfIRBUEdJuw==", + "dependencies": { + "@ucast/mongo2js": "^1.3.0" + }, + "funding": { + "url": "https://github.com/stalniy/casl/blob/master/BACKERS.md" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "peer": true, + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "peer": true + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==", + "peer": true + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", + "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "peer": true, + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/react": { + "version": "11.11.4", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", + "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz", + "integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==", + "peer": true, + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/server": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/server/-/server-11.11.0.tgz", + "integrity": "sha512-6q89fj2z8VBTx9w93kJ5n51hsmtYuFPtZgnc1L8VzRx9ti4EU6EyvF6Nn1H1x3vcCQCF7u2dB2lY4AYJwUW4PA==", + "dependencies": { + "@emotion/utils": "^1.2.1", + "html-tokenize": "^2.0.0", + "multipipe": "^1.0.2", + "through": "^2.3.8" + }, + "peerDependencies": { + "@emotion/css": "^11.0.0-rc.0" + }, + "peerDependenciesMeta": { + "@emotion/css": { + "optional": true + } + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/styled": { + "version": "11.11.5", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.5.tgz", + "integrity": "sha512-/ZjjnaNKvuMPxcIiUkf/9SHoG4Q196DRl1w82hQ3WCsjo1IUR8uaGWrC6a87CrYAW0Kb/pK7hk8BnLgLRi9KoQ==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/is-prop-valid": "^1.2.2", + "@emotion/serialize": "^1.1.4", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", + "peer": true + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "peer": true, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "dependencies": { + "@floating-ui/utils": "^0.2.1" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", + "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "dependencies": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", + "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", + "dependencies": { + "@floating-ui/dom": "^1.6.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true, + "peer": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@layer5/sistent": { + "version": "0.14.29", + "resolved": "https://registry.npmjs.org/@layer5/sistent/-/sistent-0.14.29.tgz", + "integrity": "sha512-YJ91RvfuxLwg2si6kPrzoSOGQwZtD1eNQwe+D0Y2pc0vqbsx31s4plAZX44Prgzdj6dBzN1Cp2Tq1Kb366zjtQ==", + "peerDependencies": { + "@emotion/react": "^11.11.3", + "@emotion/styled": "^11.11.0", + "@mui/material": "^5.15.11", + "@types/mui-datatables": "*", + "mui-datatables": "*", + "react": ">=17", + "react-dom": ">=17" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material": { + "optional": true + }, + "mui-datatables": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@mui/base": { + "version": "5.0.0-beta.40", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", + "integrity": "sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@floating-ui/react-dom": "^2.0.8", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", + "@popperjs/core": "^2.11.8", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.15.15", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.15.tgz", + "integrity": "sha512-aXnw29OWQ6I5A47iuWEI6qSSUfH6G/aCsW9KmW3LiFqr7uXZBK4Ks+z8G+qeIub8k0T5CMqlT2q0L+ZJTMrqpg==", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "5.15.15", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.15.tgz", + "integrity": "sha512-kkeU/pe+hABcYDH6Uqy8RmIsr2S/y5bP2rp+Gat4CcRjCcVne6KudS1NrZQhUCRysrTDCAhcbcf9gt+/+pGO2g==", + "dependencies": { + "@babel/runtime": "^7.23.9" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^5.0.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/lab": { + "version": "5.0.0-alpha.170", + "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-5.0.0-alpha.170.tgz", + "integrity": "sha512-0bDVECGmrNjd3+bLdcLiwYZ0O4HP5j5WSQm5DV6iA/Z9kr8O6AnvZ1bv9ImQbbX7Gj3pX4o43EKwCutj3EQxQg==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.40", + "@mui/system": "^5.15.15", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material": ">=5.15.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "5.15.15", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.15.tgz", + "integrity": "sha512-3zvWayJ+E1kzoIsvwyEvkTUKVKt1AjchFFns+JtluHCuvxgKcLSRJTADw37k0doaRtVAsyh8bz9Afqzv+KYrIA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.40", + "@mui/core-downloads-tracker": "^5.15.15", + "@mui/system": "^5.15.15", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", + "@types/react-transition-group": "^4.4.10", + "clsx": "^2.1.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material-nextjs": { + "version": "5.15.11", + "resolved": "https://registry.npmjs.org/@mui/material-nextjs/-/material-nextjs-5.15.11.tgz", + "integrity": "sha512-cp5RWYbBngyi7NKP91R9QITllfxumCVPFjqe4AKzNROVuCot0VpgkafxXqfbv0uFsyUU0ROs0O2M3r17q604Aw==", + "dependencies": { + "@babel/runtime": "^7.23.9" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/cache": "^11.11.0", + "@emotion/server": "^11.11.0", + "@mui/material": "^5.0.0", + "@types/react": "^17.0.0 || ^18.0.0", + "next": "^13.0.0 || ^14.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/cache": { + "optional": true + }, + "@emotion/server": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.14.tgz", + "integrity": "sha512-UH0EiZckOWcxiXLX3Jbb0K7rC8mxTr9L9l6QhOZxYc4r8FHUkefltV9VDGLrzCaWh30SQiJvAEd7djX3XXY6Xw==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.15.14", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.14.tgz", + "integrity": "sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.15.15", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.15.tgz", + "integrity": "sha512-aulox6N1dnu5PABsfxVGOZffDVmlxPOVgj56HrUnJE8MCSh8lOvvkd47cebIVQQYAjpwieXQXiDPj5pwM40jTQ==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/private-theming": "^5.15.14", + "@mui/styled-engine": "^5.15.14", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", + "clsx": "^2.1.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.14", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.14.tgz", + "integrity": "sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.14.tgz", + "integrity": "sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@types/prop-types": "^15.7.11", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/x-tree-view": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@mui/x-tree-view/-/x-tree-view-6.17.0.tgz", + "integrity": "sha512-09dc2D+Rjg2z8KOaxbUXyPi0aw7fm2jurEtV8Xw48xJ00joLWd5QJm1/v4CarEvaiyhTQzHImNqdgeJW8ZQB6g==", + "dependencies": { + "@babel/runtime": "^7.23.2", + "@mui/base": "^5.0.0-beta.20", + "@mui/utils": "^5.14.14", + "@types/react-transition-group": "^4.4.8", + "clsx": "^2.0.0", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.8.6", + "@mui/system": "^5.8.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + } + }, + "node_modules/@next/env": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.0.tgz", + "integrity": "sha512-Py8zIo+02ht82brwwhTg36iogzFqGLPXlRGKQw5s+qP/kMNc4MAyDeEwBKDijk6zTIbegEgu8Qy7C1LboslQAw==" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.1.0.tgz", + "integrity": "sha512-x4FavbNEeXx/baD/zC/SdrvkjSby8nBn8KcCREqk6UuwvwoAPZmaV8TFCAuo/cpovBRTIY67mHhe86MQQm/68Q==", + "dev": true, + "dependencies": { + "glob": "10.3.10" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.0.tgz", + "integrity": "sha512-nUDn7TOGcIeyQni6lZHfzNoo9S0euXnu0jhsbMOmMJUBfgsnESdjN97kM7cBqQxZa8L/bM9om/S5/1dzCrW6wQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.0.tgz", + "integrity": "sha512-1jgudN5haWxiAl3O1ljUS2GfupPmcftu2RYJqZiMJmmbBT5M1XDffjUtRUzP4W3cBHsrvkfOFdQ71hAreNQP6g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.0.tgz", + "integrity": "sha512-RHo7Tcj+jllXUbK7xk2NyIDod3YcCPDZxj1WLIYxd709BQ7WuRYl3OWUNG+WUfqeQBds6kvZYlc42NJJTNi4tQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.0.tgz", + "integrity": "sha512-v6kP8sHYxjO8RwHmWMJSq7VZP2nYCkRVQ0qolh2l6xroe9QjbgV8siTbduED4u0hlk0+tjS6/Tuy4n5XCp+l6g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.0.tgz", + "integrity": "sha512-zJ2pnoFYB1F4vmEVlb/eSe+VH679zT1VdXlZKX+pE66grOgjmKJHKacf82g/sWE4MQ4Rk2FMBCRnX+l6/TVYzQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.0.tgz", + "integrity": "sha512-rbaIYFt2X9YZBSbH/CwGAjbBG2/MrACCVu2X0+kSykHzHnYH5FjHxwXLkcoJ10cX0aWCEynpu+rP76x0914atg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.0.tgz", + "integrity": "sha512-o1N5TsYc8f/HpGt39OUQpQ9AKIGApd3QLueu7hXk//2xq5Z9OxmV6sQfNp8C7qYmiOlHYODOGqNNa0e9jvchGQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.0.tgz", + "integrity": "sha512-XXIuB1DBRCFwNO6EEzCTMHT5pauwaSj4SWs7CYnME57eaReAKBXCnkUE80p/pAZcewm7hs+vGvNqDPacEXHVkw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.0.tgz", + "integrity": "sha512-9WEbVRRAqJ3YFVqEZIxUqkiO8l1nool1LmNxygr5HWF8AcSYsEpneUDhmjUVJEzO2A04+oPtZdombzzPPkTtgg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.3.tgz", + "integrity": "sha512-76dll9EnJXg4EVcI5YNxZA/9hSAmZsFqzMmNRHvIlzw2WS/twfcVX3ysYrWGJMClwEmChQFC4yRq74tn6fdzRA==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.0.1" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz", + "integrity": "sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==", + "dev": true + }, + "node_modules/@swc/helpers": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", + "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/d3-selection": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.10.tgz", + "integrity": "sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg==" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.8.tgz", + "integrity": "sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/mui-datatables": { + "version": "4.3.12", + "resolved": "https://registry.npmjs.org/@types/mui-datatables/-/mui-datatables-4.3.12.tgz", + "integrity": "sha512-Xz7My6kOi7Q3LK0lNEKVF/XU0jMawIRMpROaXQxn2E8Ccmiguh19MHi/v7I8Qae8AAj/fuDx9EAHGBmvluRf3A==", + "peer": true, + "dependencies": { + "@emotion/react": "^11.10.5", + "@emotion/styled": "^11.10.5", + "@mui/material": "^5.11.4", + "@types/react": "*", + "csstype": "3.1.1 || 3.1.2" + } + }, + "node_modules/@types/mui-datatables/node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", + "peer": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "peer": true + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + }, + "node_modules/@types/react": { + "version": "18.2.79", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz", + "integrity": "sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ucast/core": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@ucast/core/-/core-1.10.2.tgz", + "integrity": "sha512-ons5CwXZ/51wrUPfoduC+cO7AS1/wRb0ybpQJ9RrssossDxVy4t49QxWoWgfBDvVKsz9VXzBk9z0wqTdZ+Cq8g==" + }, + "node_modules/@ucast/js": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@ucast/js/-/js-3.0.4.tgz", + "integrity": "sha512-TgG1aIaCMdcaEyckOZKQozn1hazE0w90SVdlpIJ/er8xVumE11gYAtSbw/LBeUnA4fFnFWTcw3t6reqseeH/4Q==", + "dependencies": { + "@ucast/core": "^1.0.0" + } + }, + "node_modules/@ucast/mongo": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@ucast/mongo/-/mongo-2.4.3.tgz", + "integrity": "sha512-XcI8LclrHWP83H+7H2anGCEeDq0n+12FU2mXCTz6/Tva9/9ddK/iacvvhCyW6cijAAOILmt0tWplRyRhVyZLsA==", + "dependencies": { + "@ucast/core": "^1.4.1" + } + }, + "node_modules/@ucast/mongo2js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@ucast/mongo2js/-/mongo2js-1.3.4.tgz", + "integrity": "sha512-ahazOr1HtelA5AC1KZ9x0UwPMqqimvfmtSm/PRRSeKKeE5G2SCqTgwiNzO7i9jS8zA3dzXpKVPpXMkcYLnyItA==", + "dependencies": { + "@ucast/core": "^1.6.1", + "@ucast/js": "^3.0.0", + "@ucast/mongo": "^2.4.0" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", + "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.1.0", + "es-shim-unscopables": "^1.0.2" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", + "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axobject-query": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/billboard.js": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/billboard.js/-/billboard.js-3.11.3.tgz", + "integrity": "sha512-r5o1ZHlJ9Ju2xPdme4I/v3DL5qAIYNqDR0C9O1xpzC9cos5rJqaJhiVLLDCFKCJkJq+mwOvoYJx+YOOm+fZLhg==", + "dependencies": { + "@types/d3-selection": "^3.0.0", + "@types/d3-transition": "^3.0.0", + "d3-axis": "^3.0.0", + "d3-brush": "^3.0.0", + "d3-drag": "^3.0.0", + "d3-dsv": "^3.0.1", + "d3-ease": "^3.0.1", + "d3-hierarchy": "^3.1.2", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-selection": "^3.0.0", + "d3-shape": "^3.2.0", + "d3-time-format": "^4.1.0", + "d3-transition": "^3.0.1", + "d3-zoom": "^3.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz", + "integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001612", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", + "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "peer": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "peer": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "peer": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.747", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.747.tgz", + "integrity": "sha512-+FnSWZIAvFHbsNVmUxhEqWiaOiPMcfum1GQzlWCg/wLigVtshOsjXHyEFfmt6cFK6+HkS3QOJBv6/3OPumbBfw==", + "dev": true, + "peer": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/enhanced-resolve": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "peer": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz", + "integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-next": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.1.0.tgz", + "integrity": "sha512-SBX2ed7DoRFXC6CQSLc/SbLY9Ut6HxNB2wPTcoIWjUMd7aF7O/SIE7111L8FdZ9TXsNV4pulUDnfthpyPtbFUg==", + "dev": true, + "dependencies": { + "@next/eslint-plugin-next": "14.1.0", + "@rushstack/eslint-patch": "^1.3.3", + "@typescript-eslint/parser": "^5.4.2 || ^6.0.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" + }, + "peerDependencies": { + "eslint": "^7.23.0 || ^8.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-cypress": { + "version": "2.15.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.2.tgz", + "integrity": "sha512-CtcFEQTDKyftpI22FVGpx8bkpKyYXBlNge6zSo0pl5/qJvBAnzaD76Vu2AsP16d6mTj478Ldn2mhgrWV+Xr0vQ==", + "dev": true, + "dependencies": { + "globals": "^13.20.0" + }, + "peerDependencies": { + "eslint": ">= 3.2.1" + } + }, + "node_modules/eslint-plugin-cypress/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", + "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.23.2", + "aria-query": "^5.3.0", + "array-includes": "^3.1.7", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "=4.7.0", + "axobject-query": "^3.2.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.15", + "hasown": "^2.0.0", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.34.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", + "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlast": "^1.2.4", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.17", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7", + "object.hasown": "^1.1.3", + "object.values": "^1.1.7", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.10" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fbjs": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz", + "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==", + "dev": true, + "dependencies": { + "cross-fetch": "^3.1.5", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^1.0.35" + } + }, + "node_modules/fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==", + "dev": true + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "peer": true + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/goober": { + "version": "2.1.14", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.14.tgz", + "integrity": "sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/graphql": { + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", + "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/graphql-ws": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.16.0.tgz", + "integrity": "sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==", + "dev": true, + "workspaces": [ + "website" + ], + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "graphql": ">=0.11 <=16" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "peer": true, + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "peer": true + }, + "node_modules/html-tokenize": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-2.0.1.tgz", + "integrity": "sha512-QY6S+hZ0f5m1WT8WffYN+Hg+xm/w5I8XeUcAq/ZYP5wVC8xbKi4Whhru3FtrAebD5EhBW8rmFzkDI6eCAuFe2w==", + "dependencies": { + "buffer-from": "~0.1.1", + "inherits": "~2.0.1", + "minimist": "~1.2.5", + "readable-stream": "~1.0.27-1", + "through2": "~0.4.1" + }, + "bin": { + "html-tokenize": "bin/cmd.js" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.4.tgz", + "integrity": "sha512-cuBuGK40P/sk5IzWa9QPUaAdvPHjkk1c+xYsd9oZw+YQQEV+10G0P5uMpGctZZKnyQ+ibRO08bD25nWLmYi2pw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "peer": true + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "peer": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "peer": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "peer": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "peer": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multipipe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-1.0.2.tgz", + "integrity": "sha512-6uiC9OvY71vzSGX8lZvSqscE7ft9nPupJ8fMjrCNRAUy2LREUW42UL+V/NTrogr6rFgRydUrCX4ZitfpSNkSCQ==", + "dependencies": { + "duplexer2": "^0.1.2", + "object-assign": "^4.1.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/next": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/next/-/next-14.1.0.tgz", + "integrity": "sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q==", + "dependencies": { + "@next/env": "14.1.0", + "@swc/helpers": "0.5.2", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=18.17.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "14.1.0", + "@next/swc-darwin-x64": "14.1.0", + "@next/swc-linux-arm64-gnu": "14.1.0", + "@next/swc-linux-arm64-musl": "14.1.0", + "@next/swc-linux-x64-gnu": "14.1.0", + "@next/swc-linux-x64-musl": "14.1.0", + "@next/swc-win32-arm64-msvc": "14.1.0", + "@next/swc-win32-ia32-msvc": "14.1.0", + "@next/swc-win32-x64-msvc": "14.1.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true, + "peer": true + }, + "node_modules/notistack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/notistack/-/notistack-3.0.1.tgz", + "integrity": "sha512-ntVZXXgSQH5WYfyU+3HfcXuKaapzAJ8fBLQ/G618rn3yvSzEbnOB8ZSOwhX+dAORy/lw+GC2N061JA0+gYWTVA==", + "dependencies": { + "clsx": "^1.1.0", + "goober": "^2.0.33" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/notistack" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/notistack/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", + "dev": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.hasown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-scurry": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/react-redux": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.1.tgz", + "integrity": "sha512-5ynfGDzxxsoV73+4czQM56qF43vsmgJsO22rmAvU5tZT2z5Xow/A2uhhxwXuGTxgdReF3zcp7A80gma2onRs1A==", + "dependencies": { + "@types/use-sync-external-store": "^0.0.3", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25", + "react": "^18.0", + "react-native": ">=0.69", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react-native": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-relay": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/react-relay/-/react-relay-16.2.0.tgz", + "integrity": "sha512-f/HtC4whyYmK6/WUeOVakXRoBkV+JEgoSeBHXfIC2U6AuH14NrKXnFicX65LksfzgD1OUfYF6IqGQ4MvO52lTQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.0.0", + "fbjs": "^3.0.2", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "relay-runtime": "16.2.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17 || ^18" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.0.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/relay-compiler": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/relay-compiler/-/relay-compiler-16.2.0.tgz", + "integrity": "sha512-KuyzUBKL9PZRNtIZWNlWEOl7OliUxaGJ2d+3mkiWEiGCEuGnNTxqEg4kJyL341aIGZC4gSqEpfvRTcMqnSM4qQ==", + "dev": true, + "bin": { + "relay-compiler": "cli.js" + } + }, + "node_modules/relay-runtime": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/relay-runtime/-/relay-runtime-16.2.0.tgz", + "integrity": "sha512-SrIyYItH1EZUj37NI8nZALasuq7mNyFrrSNgMefhgxNZxTVnr1KCp43LaxUfZqhsWbw4Y00JSGDRQXlcv4STHQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.0.0", + "fbjs": "^3.0.2", + "invariant": "^2.2.4" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/reselect": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz", + "integrity": "sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg==" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "node_modules/through2": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", + "integrity": "sha512-45Llu+EwHKtAZYTPPVn3XZHBgakWMN3rokhEv5hu596XP+cNgplMg+Gj+1nmAvj+L0K7+N49zBKx5rah5u0QIQ==", + "dependencies": { + "readable-stream": "~1.0.17", + "xtend": "~2.1.1" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ua-parser-js": { + "version": "1.0.37", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz", + "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==", + "dependencies": { + "object-keys": "~0.4.0" + }, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/xtend/node_modules/object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "peer": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "peer": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/examples/next-14/package.json b/examples/next-14/package.json new file mode 100644 index 00000000..e6e27cf7 --- /dev/null +++ b/examples/next-14/package.json @@ -0,0 +1,48 @@ +{ + "name": "next-14", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "next build", + "dev": "next dev", + "lint": "next lint", + "relay": "relay-compiler --validate", + "start": "next start" + }, + "dependencies": { + "@casl/ability": "^6.5.0", + "@emotion/server": "^11.11.0", + "@layer5/sistent": "^0.14.29", + "@mui/icons-material": "^5.15.8", + "@mui/lab": "^5.0.0-alpha.164", + "@mui/material-nextjs": "^5.15.9", + "@mui/x-tree-view": "^6.17.0", + "@reduxjs/toolkit": "^2.1.0", + "axios": "^1.6.7", + "billboard.js": "^3.10.3", + "lodash": "^4.17.21", + "moment": "^2.30.1", + "next": "14.1.0", + "notistack": "^3.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-redux": "^9.1.0", + "redux": "^5.0.1" + }, + "devDependencies": { + "@babel/eslint-parser": "^7.23.10", + "ajv": "^8.12.0", + "eslint": "^8.56.0", + "eslint-config-next": "14.1.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-cypress": "^2.15.1", + "eslint-plugin-prettier": "^5.1.3", + "graphql-ws": "^5.14.3", + "http-proxy": "^1.18.1", + "prettier": "^3.2.5", + "react-relay": "^16.2.0", + "relay-compiler": "^16.2.0", + "relay-runtime": "^16.2.0", + "uuid": "^9.0.1" + } +} diff --git a/examples/next-14/pages/_app.jsx b/examples/next-14/pages/_app.jsx new file mode 100644 index 00000000..edfc46bd --- /dev/null +++ b/examples/next-14/pages/_app.jsx @@ -0,0 +1,18 @@ +import { store } from '@/lib/redux'; +import { AppCacheProvider } from '@mui/material-nextjs/v14-pagesRouter'; +import { SistentThemeProvider } from '@layer5/sistent'; +import { Provider } from 'react-redux'; + +export default function App({ ...props }) { + const { Component, pageProps } = props; + + return ( + <Provider store={store()}> + <AppCacheProvider {...props}> + <SistentThemeProvider> + <Component {...pageProps} /> + </SistentThemeProvider> + </AppCacheProvider> + </Provider> + ); +} diff --git a/examples/next-14/pages/_document.jsx b/examples/next-14/pages/_document.jsx new file mode 100644 index 00000000..e1e9cbbb --- /dev/null +++ b/examples/next-14/pages/_document.jsx @@ -0,0 +1,13 @@ +import { Html, Head, Main, NextScript } from 'next/document'; + +export default function Document() { + return ( + <Html lang="en"> + <Head /> + <body> + <Main /> + <NextScript /> + </body> + </Html> + ); +} diff --git a/examples/next-14/pages/api/[...path].jsx b/examples/next-14/pages/api/[...path].jsx new file mode 100644 index 00000000..7ac0cff8 --- /dev/null +++ b/examples/next-14/pages/api/[...path].jsx @@ -0,0 +1,22 @@ +import httpProxy from 'http-proxy'; + +const API_URL = process.env.API_URL; + +const proxy = httpProxy.createProxyServer(); + +export const config = { + api: { + bodyParser: false, + }, +}; + +export default (req, res) => { + return new Promise((resolve, reject) => { + proxy.web(req, res, { target: API_URL, changeOrigin: true }, (err) => { + if (err) { + return reject(err); + } + resolve(); + }); + }); +}; diff --git a/examples/next-14/pages/auth/login.jsx b/examples/next-14/pages/auth/login.jsx new file mode 100644 index 00000000..b9fb856a --- /dev/null +++ b/examples/next-14/pages/auth/login.jsx @@ -0,0 +1,75 @@ +import { useRouter } from 'next/router'; +import { useSelector, useDispatch } from 'react-redux'; +import { DialogContentText, Dialog, DialogContent, DialogTitle, Typography } from '@layer5/sistent'; +import React from 'react'; +import { selectCountdown } from '@/lib/redux/selectors'; +import { fetchSessionData } from '@/lib/redux/features/session/session.slice'; +import { styled } from '@mui/material'; + +const SessionExpired = styled(DialogContentText)(() => ({ + minWidth: 400, + overflowWrap: 'anywhere', + textAlign: 'center', + padding: 5, + margin: 2, + display: 'flex', + flexDirection: 'column', + height: '7rem', + justifyContent: 'space-evenly', +})); + +export default function UnauthenticatedSession() { + const router = useRouter(); + + const [open, setOpen] = React.useState(false); + const countdown = useSelector(selectCountdown); + const dispatch = useDispatch(); + + React.useEffect(() => { + void dispatch(fetchSessionData()); + }, [dispatch]); + + React.useEffect(() => { + if (countdown === 0) { + handleClose(); + router.push('/user/login'); + } + }, [countdown]); + + React.useEffect(() => { + setOpen(true); + }, []); + + const handleClose = () => { + setOpen(false); + }; + + return ( + <Dialog + open={open} + onClose={handleClose} + aria-labelledby="alert-dialog-title" + aria-describedby="alert-dialog-description" + > + <DialogTitle + id="alert-dialog-title" + sx={{ + textAlign: 'center', + minWidth: 400, + padding: '10px', + color: '#ebf1f5', + backgroundColor: '#F0A303', + }} + > + <span></span> + Session Expired + </DialogTitle> + <DialogContent> + <SessionExpired id="alert-dialog-description"> + <Typography variant="body1">Your session has expired</Typography> + <Typography>You will be redirected to login in {countdown}</Typography> + </SessionExpired> + </DialogContent> + </Dialog> + ); +} diff --git a/examples/next-14/pages/index.jsx b/examples/next-14/pages/index.jsx new file mode 100644 index 00000000..1ea5444b --- /dev/null +++ b/examples/next-14/pages/index.jsx @@ -0,0 +1,20 @@ +import Dashboard from '@/components/Dashboard'; +import { useDispatch } from 'react-redux'; +import { updatePathTitle } from '@/lib/redux/features/page/page.slice'; +import { useEffect } from 'react'; + +function IndexPage() { + const dispatch = useDispatch(); + + useEffect(() => { + const newTitle = 'Dashboard'; + + dispatch(updatePathTitle(newTitle)); + + document.title = `${newTitle} | Meshery`; + }, []); + + return <Dashboard />; +} + +export default IndexPage; diff --git a/examples/next-14/pages/provider/index.jsx b/examples/next-14/pages/provider/index.jsx new file mode 100644 index 00000000..13f0635d --- /dev/null +++ b/examples/next-14/pages/provider/index.jsx @@ -0,0 +1,22 @@ +import { useDispatch } from 'react-redux'; +import { updatePathTitle } from '@/lib/redux/features/page/page.slice'; +import { useEffect, Fragment } from 'react'; +import Provider from '@/components/ProviderLogin'; + +export default function ProviderPage() { + const dispatch = useDispatch(); + + useEffect(() => { + const newTitle = 'Provider'; + + dispatch(updatePathTitle(newTitle)); + + document.title = `${newTitle} | Meshery`; + }); + + return ( + <Fragment> + <Provider /> + </Fragment> + ); +} diff --git a/examples/next-14/pages/settings.jsx b/examples/next-14/pages/settings.jsx new file mode 100644 index 00000000..ccfe8a93 --- /dev/null +++ b/examples/next-14/pages/settings.jsx @@ -0,0 +1,19 @@ +import { useDispatch } from 'react-redux'; +import { useEffect } from 'react'; +import { updatePathTitle } from '@/lib/redux/features/page/page.slice'; + +function SettingsPage() { + const dispatch = useDispatch(); + + useEffect(() => { + const newTitle = 'Settings'; + + dispatch(updatePathTitle(newTitle)); + + document.title = `${newTitle} | Meshery`; + }, []); + + return <div>Settings</div>; +} + +export default SettingsPage; diff --git a/examples/next-14/public/assets/fonts/QanelasSoftBlack.otf b/examples/next-14/public/assets/fonts/QanelasSoftBlack.otf new file mode 100644 index 00000000..27ed8f78 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftBlack.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftBlack.woff b/examples/next-14/public/assets/fonts/QanelasSoftBlack.woff new file mode 100644 index 00000000..36bcc774 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftBlack.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftBlack.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftBlack.woff2 new file mode 100644 index 00000000..22a9296b Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftBlack.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftBlackItalic.otf b/examples/next-14/public/assets/fonts/QanelasSoftBlackItalic.otf new file mode 100644 index 00000000..18c212bf Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftBlackItalic.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftBlackItalic.woff b/examples/next-14/public/assets/fonts/QanelasSoftBlackItalic.woff new file mode 100644 index 00000000..70a5f296 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftBlackItalic.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftBlackItalic.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftBlackItalic.woff2 new file mode 100644 index 00000000..35ac0a1d Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftBlackItalic.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftBold.otf b/examples/next-14/public/assets/fonts/QanelasSoftBold.otf new file mode 100644 index 00000000..d6b53365 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftBold.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftBold.woff b/examples/next-14/public/assets/fonts/QanelasSoftBold.woff new file mode 100644 index 00000000..2f47986a Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftBold.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftBold.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftBold.woff2 new file mode 100644 index 00000000..e3b02e23 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftBold.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftBoldItalic.otf b/examples/next-14/public/assets/fonts/QanelasSoftBoldItalic.otf new file mode 100644 index 00000000..90053635 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftBoldItalic.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftBoldItalic.woff b/examples/next-14/public/assets/fonts/QanelasSoftBoldItalic.woff new file mode 100644 index 00000000..3e30ef6a Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftBoldItalic.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftBoldItalic.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftBoldItalic.woff2 new file mode 100644 index 00000000..bc258b00 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftBoldItalic.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftExtraBold.otf b/examples/next-14/public/assets/fonts/QanelasSoftExtraBold.otf new file mode 100644 index 00000000..c0e3bc93 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftExtraBold.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftExtraBold.woff b/examples/next-14/public/assets/fonts/QanelasSoftExtraBold.woff new file mode 100644 index 00000000..6a48c476 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftExtraBold.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftExtraBold.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftExtraBold.woff2 new file mode 100644 index 00000000..50efd05b Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftExtraBold.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftExtraBoldItalic.otf b/examples/next-14/public/assets/fonts/QanelasSoftExtraBoldItalic.otf new file mode 100644 index 00000000..cd805cad Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftExtraBoldItalic.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftExtraBoldItalic.woff b/examples/next-14/public/assets/fonts/QanelasSoftExtraBoldItalic.woff new file mode 100644 index 00000000..bf39b3a1 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftExtraBoldItalic.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftExtraBoldItalic.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftExtraBoldItalic.woff2 new file mode 100644 index 00000000..d23f2028 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftExtraBoldItalic.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftHeavy.otf b/examples/next-14/public/assets/fonts/QanelasSoftHeavy.otf new file mode 100644 index 00000000..28c2d4d5 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftHeavy.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftHeavy.woff b/examples/next-14/public/assets/fonts/QanelasSoftHeavy.woff new file mode 100644 index 00000000..ddf971a0 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftHeavy.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftHeavyItalic.otf b/examples/next-14/public/assets/fonts/QanelasSoftHeavyItalic.otf new file mode 100644 index 00000000..58e83f9c Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftHeavyItalic.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftHeavyItalic.woff b/examples/next-14/public/assets/fonts/QanelasSoftHeavyItalic.woff new file mode 100644 index 00000000..49b349b6 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftHeavyItalic.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftHeavyItalic.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftHeavyItalic.woff2 new file mode 100644 index 00000000..eede765c Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftHeavyItalic.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftLight.otf b/examples/next-14/public/assets/fonts/QanelasSoftLight.otf new file mode 100644 index 00000000..1c34d7dc Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftLight.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftLight.woff b/examples/next-14/public/assets/fonts/QanelasSoftLight.woff new file mode 100644 index 00000000..87f6f11e Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftLight.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftLight.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftLight.woff2 new file mode 100644 index 00000000..c58b8e0c Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftLight.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftLightItalic.otf b/examples/next-14/public/assets/fonts/QanelasSoftLightItalic.otf new file mode 100644 index 00000000..382bef17 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftLightItalic.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftLightItalic.woff b/examples/next-14/public/assets/fonts/QanelasSoftLightItalic.woff new file mode 100644 index 00000000..b28ce2a8 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftLightItalic.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftLightItalic.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftLightItalic.woff2 new file mode 100644 index 00000000..aff0681e Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftLightItalic.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftMedium.otf b/examples/next-14/public/assets/fonts/QanelasSoftMedium.otf new file mode 100644 index 00000000..a0dd7190 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftMedium.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftMedium.woff b/examples/next-14/public/assets/fonts/QanelasSoftMedium.woff new file mode 100644 index 00000000..56eaf488 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftMedium.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftMediumItalic.otf b/examples/next-14/public/assets/fonts/QanelasSoftMediumItalic.otf new file mode 100644 index 00000000..91676a97 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftMediumItalic.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftMediumItalic.woff b/examples/next-14/public/assets/fonts/QanelasSoftMediumItalic.woff new file mode 100644 index 00000000..d7bc54bf Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftMediumItalic.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftRegular.otf b/examples/next-14/public/assets/fonts/QanelasSoftRegular.otf new file mode 100644 index 00000000..249b8a27 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftRegular.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftRegular.woff b/examples/next-14/public/assets/fonts/QanelasSoftRegular.woff new file mode 100644 index 00000000..66f70268 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftRegular.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftRegular.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftRegular.woff2 new file mode 100644 index 00000000..7c3a5ef7 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftRegular.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftRegularItalic.otf b/examples/next-14/public/assets/fonts/QanelasSoftRegularItalic.otf new file mode 100644 index 00000000..e3898f21 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftRegularItalic.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftRegularItalic.woff b/examples/next-14/public/assets/fonts/QanelasSoftRegularItalic.woff new file mode 100644 index 00000000..c3a250d6 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftRegularItalic.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftRegularItalic.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftRegularItalic.woff2 new file mode 100644 index 00000000..f6defa95 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftRegularItalic.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftSemiBold.otf b/examples/next-14/public/assets/fonts/QanelasSoftSemiBold.otf new file mode 100644 index 00000000..7463179c Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftSemiBold.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftSemiBold.woff b/examples/next-14/public/assets/fonts/QanelasSoftSemiBold.woff new file mode 100644 index 00000000..9923de0a Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftSemiBold.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftSemiBold.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftSemiBold.woff2 new file mode 100644 index 00000000..d331d941 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftSemiBold.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftSemiBoldItalic.otf b/examples/next-14/public/assets/fonts/QanelasSoftSemiBoldItalic.otf new file mode 100644 index 00000000..7a2a99d4 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftSemiBoldItalic.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftSemiBoldItalic.woff b/examples/next-14/public/assets/fonts/QanelasSoftSemiBoldItalic.woff new file mode 100644 index 00000000..156d7d72 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftSemiBoldItalic.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftSemiBoldItalic.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftSemiBoldItalic.woff2 new file mode 100644 index 00000000..781aa735 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftSemiBoldItalic.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftThin.otf b/examples/next-14/public/assets/fonts/QanelasSoftThin.otf new file mode 100644 index 00000000..cd81b0c6 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftThin.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftThin.woff b/examples/next-14/public/assets/fonts/QanelasSoftThin.woff new file mode 100644 index 00000000..1a2b56b4 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftThin.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftThin.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftThin.woff2 new file mode 100644 index 00000000..6101f580 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftThin.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftThinItalic.otf b/examples/next-14/public/assets/fonts/QanelasSoftThinItalic.otf new file mode 100644 index 00000000..cb2e650b Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftThinItalic.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftThinItalic.woff b/examples/next-14/public/assets/fonts/QanelasSoftThinItalic.woff new file mode 100644 index 00000000..96e7d3c8 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftThinItalic.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftThinItalic.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftThinItalic.woff2 new file mode 100644 index 00000000..7d5aa08d Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftThinItalic.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftUltraLight.otf b/examples/next-14/public/assets/fonts/QanelasSoftUltraLight.otf new file mode 100644 index 00000000..86a0b545 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftUltraLight.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftUltraLight.woff b/examples/next-14/public/assets/fonts/QanelasSoftUltraLight.woff new file mode 100644 index 00000000..182c2b69 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftUltraLight.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftUltraLight.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftUltraLight.woff2 new file mode 100644 index 00000000..6f41f53e Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftUltraLight.woff2 differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftUltraLightItalic.otf b/examples/next-14/public/assets/fonts/QanelasSoftUltraLightItalic.otf new file mode 100644 index 00000000..bd9637b2 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftUltraLightItalic.otf differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftUltraLightItalic.woff b/examples/next-14/public/assets/fonts/QanelasSoftUltraLightItalic.woff new file mode 100644 index 00000000..ee723475 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftUltraLightItalic.woff differ diff --git a/examples/next-14/public/assets/fonts/QanelasSoftUltraLightItalic.woff2 b/examples/next-14/public/assets/fonts/QanelasSoftUltraLightItalic.woff2 new file mode 100644 index 00000000..3c5ed7f3 Binary files /dev/null and b/examples/next-14/public/assets/fonts/QanelasSoftUltraLightItalic.woff2 differ diff --git a/examples/next-14/public/favicon.ico b/examples/next-14/public/favicon.ico new file mode 100644 index 00000000..718d6fea Binary files /dev/null and b/examples/next-14/public/favicon.ico differ diff --git a/examples/next-14/public/next.svg b/examples/next-14/public/next.svg new file mode 100644 index 00000000..5174b28c --- /dev/null +++ b/examples/next-14/public/next.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg> \ No newline at end of file diff --git a/examples/next-14/public/vercel.svg b/examples/next-14/public/vercel.svg new file mode 100644 index 00000000..d2f84222 --- /dev/null +++ b/examples/next-14/public/vercel.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg> \ No newline at end of file diff --git a/examples/next-14/relay.config.js b/examples/next-14/relay.config.js new file mode 100644 index 00000000..152a0b08 --- /dev/null +++ b/examples/next-14/relay.config.js @@ -0,0 +1,9 @@ +// relay.config.js +module.exports = { + // ... + // Configuration options accepted by the `relay-compiler` command-line tool and `babel-plugin-relay`. + src: './components', + schema: './schema.graphql', + language: 'javascript', + excludes: ['**/node_modules/**', '**/__mocks__/**', '**/__generated__/**'], +}; diff --git a/examples/next-14/schema.graphql b/examples/next-14/schema.graphql new file mode 100644 index 00000000..166e48c0 --- /dev/null +++ b/examples/next-14/schema.graphql @@ -0,0 +1,715 @@ +# We assume a few things about the schema. We use the graphql-ruby gem to generate docs, which enforces: +# - All mutations have a single input field named 'input' +# If these things change, then doc generation for GraphQL will break. + +# ================= COMMONS ========================= + +scalar Map +scalar Time +scalar Any +directive @KubernetesMiddleware on FIELD_DEFINITION + +# Service Mesh Types +enum MeshType { + # All meshes that Meshery supports + ALL_MESH + + # Invalid Mesh + INVALID_MESH + + # AWS App Mesh + APP_MESH + + # Citrix Service Mesh + CITRIX_SERVICE_MESH + + # Consul by HashiCorp + CONSUL + + # Istio Service Mesh + ISTIO + + # Kuma + KUMA + + # LinkerD Service Mesh + LINKERD + + # Traefik Mesh + TRAEFIK_MESH + + # Octarine Mesh + OCTARINE + + # Network Service Mesh + NETWORK_SERVICE_MESH + + # VMware Tanzu Service Mesh + TANZU + + # Open Service Mesh + OPEN_SERVICE_MESH + + # NGINX Service Mesh + NGINX_SERVICE_MESH + + # Cilium Service Mesh + CILIUM_SERVICE_MESH +} + +enum MesheryController { + BROKER + OPERATOR + MESHSYNC +} + +enum MesheryControllerStatus { + DEPLOYED + NOTDEPLOYED + DEPLOYING + UNKOWN + UNDEPLOYED + ENABLED + RUNNING + CONNECTED +} + +type MesheryControllersStatusListItem { + contextId: String! + controller: MesheryController! + status: MesheryControllerStatus! + version: String +} + +type MeshSyncEvent { + type: String! + object: Any! + contextId: String! +} + +enum Status { + # Enabled + ENABLED + + # Connected (Applicable only for NATS status for now) + CONNECTED + + # Disabled + DISABLED + + # Processing + PROCESSING + + # Unknown + UNKNOWN +} + +type Error { + # Error Code + code: String! + + # Error Details + description: String! +} + +# ================= EVENTS ================= + +type Event { + id: ID! + userID: ID! + actedUpon: ID! + operationID: ID! + systemID: ID! + severity: Severity! + action: String! + status: String! + category: String! + description: String! + metadata: Map + createdAt: Time! + updatedAt: Time! + deletedAt: Time +} + +enum Severity { + alert + critical + debug + emergency + error + warning + informational +} + +# ================ DASHBOARD ================ + +type Resource { + # Name of resource + kind: String! + # Number of resouce + count: Int! +} + +# Details about discovered workloads +type ClusterResources { + resources: [Resource!]! +} + +# =================== ADDONS ===================== + +# Input for changing Addon Status +input AddonStatusInput { + # Filter by Serice Mesh + selector: MeshType + #kubernetes context ID + k8scontextID: String! + # Desired Status + targetStatus: Status! +} + +# Deatils about the Addon Component +type AddonList { + # Name + name: String! + + # Owner + owner: String! +} + +# ============== DATA PLANE ======================= + +# Data Plane for a particular Mesh +type DataPlane { + # Service Mesh Name + name: String! + + # Members of the Mesh + proxies: [Container!]! +} + +type Container { + controlPlaneMemberName: String! + containerName: String! + image: String! + status: Container_Status + # args: NOT IMPLEMENTED + ports: [Container_Port] + # env: NOT IMPLEMENTED, + resources: Any +} + +type Container_Status { + containerStatusName: String! + image: String! + state: Any + lastState: Any + ready: Boolean! + restartCount: Any + # image: String! + # imageID: String! + # containerID: String! + started: Boolean! + imageID: Any + containerID: Any +} + +type Container_Port { + name: String + containerPort: Int! + protocol: String! +} + +# ============== CONTROL PLANE ======================= + +# Filter Control Plane Query +input ServiceMeshFilter { + # Filter by Service Mesh + type: MeshType + k8sClusterIDs: [String!] +} + +# Control Plane data for a particular Mesh +type ControlPlane { + # Service Mesh Name + name: String! + + # Members of the Mesh + members: [ControlPlaneMember!]! +} + +# Member Details +type ControlPlaneMember { + # Name + name: String! + + # Component + component: String! + + # Version + version: String! + + # Namespace + namespace: String! + + # DataPlanes + data_planes: [Container!] +} + +# ============== MESHSYNC ============================= + +enum MeshSyncEventType { + ADDED + MODIFIED + DELETED +} + +# ============== OPERATOR ============================= + +# Input for status change of Meshery Operator +input OperatorStatusInput { + # Desired status for Meshery Operator + targetStatus: Status! + + contextID: String! +} + +type OperatorStatusPerK8sContext { + contextID: String! + operatorStatus: OperatorStatus! +} +type OperatorControllerStatusPerK8sContext { + contextID: String! + OperatorControllerStatus: OperatorControllerStatus! +} +# Status of Meshery Operator and its controllers +type OperatorStatus { + # Status of Meshery Operator + status: Status! + + # Verion of Meshery Operator + version: String! + + # Details about various Controllers of Meshery Operator + controllers: [OperatorControllerStatus!]! + + # Error Logs encountered by Meshery Operator + error: Error + + contextID: String! +} + +# Controllers of Meshery Operator +type OperatorControllerStatus { + # Controller Name + name: String! + + # Controller Verison + version: String! + + # Controller Status + status: Status! + + # Controller Error Log + error: Error + + contextID: String! +} + +# ============== NAMESPACE ============================= + +# Type to define a k8s Namespace +type NameSpace { + # Namespace Name + namespace: String! +} + +# ================ K8s Context ====================== + +type K8sContext { + id: String! + name: String! + server: String! + owner: ID! + created_by: ID! + meshery_instance_id: ID! + kubernetes_server_id: ID! + deployment_type: String! + version: String! + updated_at: String! + created_at: String! + connection_id: String! +} + +type K8sContextsPage { + total_count: Int! + contexts: [K8sContext]! +} + +# ================= Configuration =================== + +type ConfigurationPage { + applications: ApplicationPage + patterns: PatternPageResult + filters: FilterPage +} + +# ================= Applications ==================== + +type ApplicationPage { + page: Int! + page_size: Int! + total_count: Int! + applications: [ApplicationResult] +} + +type ApplicationResult { + id: ID! + name: String! + application_file: String! + type: NullString! + user_id: String! + location: Location! + visibility: String! + created_at: String + updated_at: String +} + +type NullString { + String: String! + Valid: Boolean! +} + +# ================= Filters ======================= + +type FilterPage { + page: Int! + page_size: Int! + total_count: Int! + filters: [FilterResult] +} + +type FilterResult { + id: ID! + name: String! + filter_file: String! + filter_resource: String! + user_id: String! + location: Location! + visibility: String! + catalog_data: Map + created_at: String + updated_at: String +} + +type CatalogFilter { + id: ID! + name: String! + filter_file: String! + user_id: String! + location: Location! + filter_resource: String! + visibility: String! + catalog_data: Map + created_at: String + updated_at: String +} + +# ============== Patterns ================================= + +type PatternPageResult { + page: Int! + page_size: Int! + total_count: Int! + patterns: [PatternResult] +} + +type PatternResult { + id: ID! + name: String! + user_id: String! + location: Location! + pattern_file: String! + visibility: String! + catalog_data: Map + canSupport: Boolean! + errmsg: String + created_at: String + updated_at: String + type: NullString +} + +type Location { + branch: String + host: String + path: String + type: String +} + +type CatalogPattern { + id: ID! + name: String! + user_id: String! + pattern_file: String! + location: Location! + visibility: String! + catalog_data: Map + created_at: String + updated_at: String +} + +# ============== Perf ================================= + +type PerfPageResult { + page: Int! + page_size: Int! + total_count: Int! + + results: [MesheryResult] +} + +type PerfPageProfiles { + page: Int! + page_size: Int! + total_count: Int! + + profiles: [PerfProfile] +} + +type PerfProfile { + concurrent_request: Int! + created_at: String + duration: String! + endpoints: [String] + id: String! + last_run: String + load_generators: [String] + name: String + qps: Int + total_results: Int + updated_at: String + user_id: String! + request_headers: String + request_cookies: String + request_body: String + content_type: String + service_mesh: String + metadata: Map +} + +type MesheryResult { + meshery_id: String + name: String + mesh: String + performance_profile: String + test_id: String + runner_results: Map + server_metrics: String + server_board_config: String + test_start_time: String + user_id: String + updated_at: String + created_at: String +} + +input PageFilter { + page: String! + pageSize: String! + order: String + search: String + from: String + to: String + updated_after: String + visibility: [String!] +} + +# ============== CATALOG ============================= + +input CatalogSelector { + page: String! + pagesize: String! + search: String! + order: String! +} + +# ================ TELEMETRY ==================== + +type TelemetryComp { + name: String! + spec: String! + status: String! +} +# ============== RESYNC ============================= + +# Type ReSyncActions define the actions involved during resync +input ReSyncActions { + clearDB: String! + ReSync: String! + hardReset: String! +} + +# ============== MeshModel ============================= + +input MeshModelSummarySelector { + type: String! +} + +# Type MeshModelComponentsSummary define the summary of a Mesh Model +type MeshModelSummary { + components: [MeshModelComponent!] + relationships: [MeshModelRelationship!] +} + +type MeshModelComponent { + name: String! + count: Int! +} + +type MeshModelRelationship { + name: String! + count: Int! +} + +# ============== ROOT ================================= + +type Query { + # Query details about Addons available (Eg. Prometheus and Grafana) + getAvailableAddons( + # Select Mesh Type + filter: ServiceMeshFilter + ): [AddonList!]! + + # Query Control Plane data for a Service Mesh (or all) in your cluster + getControlPlanes( + # Filter Control Plane Query + filter: ServiceMeshFilter + ): [ControlPlane!]! + + # Query Data Plane information for a Service Mesh (or all) in your cluster + getDataPlanes( + # Filter Control Plane Query + filter: ServiceMeshFilter + ): [DataPlane!]! + + # Query status of Meshery Operator in your cluster + getOperatorStatus(k8scontextID: String!): MesheryControllersStatusListItem @KubernetesMiddleware + + # Query to resync the cluster discovery + resyncCluster( + # Selector to control several resync actions + selector: ReSyncActions + k8scontextID: String! + ): Status! @KubernetesMiddleware + + # Check the Meshsync Status + getMeshsyncStatus(connectionID: String!): OperatorControllerStatus! + + # Check is Meshey Server is connected to NATS + getNatsStatus(connectionID: String!): OperatorControllerStatus! + + # Query available Namesapces in your cluster + getAvailableNamespaces(k8sClusterIDs: [String!]): [NameSpace!]! + + # Query for performance result + getPerfResult(id: ID!): MesheryResult + + # Query for fetching all results for profile ID + fetchResults(selector: PageFilter!, profileID: String!): PerfPageResult! + + # Query for fetching all results for profile ID + getPerformanceProfiles(selector: PageFilter!): PerfPageProfiles! + + # Query for fetching all results for profile ID + fetchAllResults(selector: PageFilter!): PerfPageResult! + + # Query for fetching all patterns with selector + fetchPatterns(selector: PageFilter!): PatternPageResult! + + # Query for getting kubectl describe details with meshkit + getKubectlDescribe(name: String!, kind: String!, namespace: String!): KctlDescribeDetails! + + # Query for getting Pattern Catalog from remote provider + fetchPatternCatalogContent(selector: CatalogSelector): [CatalogPattern!]! + # Query for getting Filter Catalog from remote provider + fetchFilterCatalogContent(selector: CatalogSelector): [CatalogFilter!]! + + # Query for getting cluster info + # getClusterResources(k8scontextIDs: [String!], namespace: String!): ClusterResources! + + # Query for meshmodel summary + getMeshModelSummary(selector: MeshModelSummarySelector!): MeshModelSummary! + + # Query for telemetry components + fetchTelemetryComponents(contexts: [String!]): [TelemetryComp]! +} + +# + +# Input for status change of Meshery Operator +input AdapterStatusInput { + # Desired status for Meshery Operator + targetStatus: Status! + + # The port on which adapter will be deployed + targetPort: String! + + # Name of the adapter to be deployed + adapter: String! +} + +type Mutation { + # Change the Operator Status + changeOperatorStatus(input: OperatorStatusInput): Status! @KubernetesMiddleware + + # Change the Adapter Status + changeAdapterStatus(input: AdapterStatusInput): Status! @KubernetesMiddleware +} + +type Subscription { + # Listen to changes in status of Meshery Operator in your cluster + listenToOperatorState(k8scontextIDs: [String!]): OperatorStatusPerK8sContext @KubernetesMiddleware + + # Listen to changes in Performance Profiles + subscribePerfProfiles(selector: PageFilter!): PerfPageProfiles! + + # Listen to all results for profile ID + subscribePerfResults(selector: PageFilter!, profileID: String!): PerfPageResult! + + # Listen to changes in the status of meshery controllers + subscribeMesheryControllersStatus(k8scontextIDs: [String!]): [MesheryControllersStatusListItem!]! + @KubernetesMiddleware + + # Listen to the events that MeshSync is sending through Meshery Broker. + # Note: It does not listen to the changes in meshery database, but to meshsync events + subscribeMeshSyncEvents( + k8scontextIDs: [String!] + eventTypes: [MeshSyncEventType!] + ): MeshSyncEvent! @KubernetesMiddleware + + subscribeConfiguration( + patternSelector: PageFilter! + filterSelector: PageFilter! + ): ConfigurationPage! + + subscribeClusterResources(k8scontextIDs: [String!], namespace: String!): ClusterResources! + + subscribeK8sContext(selector: PageFilter!): K8sContextsPage! + + subscribeMeshModelSummary(selector: MeshModelSummarySelector!): MeshModelSummary! + + # Publish events to user + subscribeEvents: Event! +} + +type OAMCapability { + oam_definition: Any + id: String + oam_ref_schema: String + host: String + restricted: Boolean + metadata: Any +} + +type KctlDescribeDetails { + describe: String + ctxid: String +} diff --git a/examples/next-14/styles/ConnectClustersButton.jsx b/examples/next-14/styles/ConnectClustersButton.jsx new file mode 100644 index 00000000..591c1154 --- /dev/null +++ b/examples/next-14/styles/ConnectClustersButton.jsx @@ -0,0 +1,13 @@ +import { styled } from '@mui/material'; +import { Button } from '@layer5/sistent'; + +const ConnectClustersButton = styled(Button)(({ theme }) => ({ + paddingRight: theme.spacing(0.5), + margin: '0.5rem 0.5rem', + whiteSpace: 'nowrap', + '& .MuiSvgIcon-root': { + width: theme.spacing(2.5), + }, +})); + +export default ConnectClustersButton; diff --git a/examples/next-14/styles/CreateButton.jsx b/examples/next-14/styles/CreateButton.jsx new file mode 100644 index 00000000..1268f4e6 --- /dev/null +++ b/examples/next-14/styles/CreateButton.jsx @@ -0,0 +1,10 @@ +import { styled } from '@mui/material'; + +const CreateButton = styled('div')({ + display: 'flex', + justifyContent: 'flex-start', + alignItems: 'center', + whiteSpace: 'nowrap', +}); + +export default CreateButton; diff --git a/examples/next-14/styles/CreateDesignButton.jsx b/examples/next-14/styles/CreateDesignButton.jsx new file mode 100644 index 00000000..598d8df2 --- /dev/null +++ b/examples/next-14/styles/CreateDesignButton.jsx @@ -0,0 +1,13 @@ +import { styled } from '@mui/material'; +import { Button } from '@layer5/sistent'; + +const CreateDesignButton = styled(Button)(({ theme }) => ({ + paddingRight: theme.spacing(0.5), + margin: '0.5rem 0.5rem', + whiteSpace: 'nowrap', + '& .MuiSvgIcon-root': { + width: theme.spacing(2.5), + }, +})); + +export default CreateDesignButton; diff --git a/examples/next-14/styles/DashboardInfoOutlined.jsx b/examples/next-14/styles/DashboardInfoOutlined.jsx new file mode 100644 index 00000000..f5123ee8 --- /dev/null +++ b/examples/next-14/styles/DashboardInfoOutlined.jsx @@ -0,0 +1,13 @@ +import { styled } from '@mui/material/styles'; +import { InfoOutlined } from '@mui/icons-material'; +import { cultured } from '@layer5/sistent'; + +const DashboardInfoOutlined = styled(InfoOutlined)(({ theme }) => ({ + color: cultured.main, + // color: '#F6F8F8', // #3C494F + // ...iconSmall, + marginLeft: '0.5rem', + cursor: 'pointer', +})); + +export default DashboardInfoOutlined; diff --git a/examples/next-14/styles/DashboardLayout.jsx b/examples/next-14/styles/DashboardLayout.jsx new file mode 100644 index 00000000..236faa31 --- /dev/null +++ b/examples/next-14/styles/DashboardLayout.jsx @@ -0,0 +1,7 @@ +import { styled } from '@mui/material/styles'; + +export const DashboardLayout = styled('div')(() => ({ + flexGrow: 1, + maxWidth: '100%', + height: 'auto', +})); diff --git a/examples/next-14/styles/DashboardSection.jsx b/examples/next-14/styles/DashboardSection.jsx new file mode 100644 index 00000000..58c03494 --- /dev/null +++ b/examples/next-14/styles/DashboardSection.jsx @@ -0,0 +1,10 @@ +import { styled } from '@mui/material/styles'; + +const DashboardSection = styled('div')(({ theme }) => ({ + backgroundColor: theme.palette.mode === 'dark' ? '#202020' : '#FFFFFF', + padding: theme.spacing(2), + borderRadius: 4, + height: '100%', +})); + +export default DashboardSection; diff --git a/examples/next-14/styles/DashboardSubMenuTab.jsx b/examples/next-14/styles/DashboardSubMenuTab.jsx new file mode 100644 index 00000000..ada1059d --- /dev/null +++ b/examples/next-14/styles/DashboardSubMenuTab.jsx @@ -0,0 +1,5 @@ +import { styled } from '@mui/material/styles'; + +export const DashboardSubMenuTab = styled('div')(({ theme }) => ({ + backgroundColor: theme.palette.mode === 'dark' ? '#212121' : '#f5f5f5', +})); diff --git a/examples/next-14/styles/DashboardTab.jsx b/examples/next-14/styles/DashboardTab.jsx new file mode 100644 index 00000000..148b0821 --- /dev/null +++ b/examples/next-14/styles/DashboardTab.jsx @@ -0,0 +1,11 @@ +import { KEPPEL, Tab } from '@layer5/sistent'; +import { styled } from '@mui/material/styles'; + +export const DashboardTab = styled(Tab)(({ theme }) => ({ + minWidth: 40, + paddingLeft: 0, + paddingRight: 0, + '&.Mui-selected': { + color: theme.palette.mode === 'dark' ? KEPPEL : theme.palette.primary.main, + }, +})); diff --git a/examples/next-14/styles/DashboardTabs.jsx b/examples/next-14/styles/DashboardTabs.jsx new file mode 100644 index 00000000..682303a7 --- /dev/null +++ b/examples/next-14/styles/DashboardTabs.jsx @@ -0,0 +1,12 @@ +import { KEPPEL, Tabs } from '@layer5/sistent'; +import { styled } from '@mui/material/styles'; + +export const DashboardTabs = styled(Tabs)(({ theme }) => ({ + flexGrow: 1, + '& .MuiTabs-indicator': { + backgroundColor: theme.palette.mode === 'dark' ? KEPPEL : theme.palette.primary.main, + }, + '& .MuiTab-fullWidth': { + flexBasis: 'unset', + }, +})); diff --git a/examples/next-14/styles/Errors404.jsx b/examples/next-14/styles/Errors404.jsx new file mode 100644 index 00000000..048fa683 --- /dev/null +++ b/examples/next-14/styles/Errors404.jsx @@ -0,0 +1,46 @@ +import { ALICE_BLUE, darkTeal } from '@layer5/sistent'; +import { styled } from '@mui/material/styles'; + +export const ErrorMain = styled('main')(({ theme }) => ({ + background: ALICE_BLUE, + padding: '4rem 8rem', + minHeight: '100vh', + ['@media (max-width:680px)']: { + padding: '4rem 2rem', + }, +})); + +export const ErrorContainer = styled('div')(({ theme }) => ({ + background: theme.palette.white, + boxShadow: + '0px 2px 1px -1px rgb(0 0 0 / 20%), 0px 1px 1px 0px rgb(0 0 0 / 14%), 0px 1px 3px 0px rgb(0 0 0 / 12%)', + borderRadius: '8px', + padding: '3rem', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', +})); + +export const ErrorComponent = styled('div')(() => ({ + paddingTop: '2rem', + width: '100%', +})); + +export const ErrorContentContainer = styled('div')(() => ({ + textAlign: 'center', + backgroundColor: '#fafafa', + margin: '2rem', + padding: '20px', + borderRadius: '10px', + boxShadow: + ' 0 2px 2px 0 rgb(0 0 0 / 14%), 0 1px 5px 0 rgb(0 0 0 / 12%), 0 3px 1px -2px rgb(0 0 0 / 20%)', +})); + +export const ErrorLink = styled('a')(({ theme }) => ({ + color: darkTeal.dark, + textDecoration: 'none', +})); + +export const ErrorMsg = styled('errormsg')(() => ({ + fontWeight: '600', +})); diff --git a/examples/next-14/styles/InnerContainer.jsx b/examples/next-14/styles/InnerContainer.jsx new file mode 100644 index 00000000..0da57e06 --- /dev/null +++ b/examples/next-14/styles/InnerContainer.jsx @@ -0,0 +1,15 @@ +import { styled } from '@mui/material/styles'; + +const InnerContainer = styled('div')(({ theme }) => ({ + display: 'flex', + flexDirection: 'row', + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + [theme.breakpoints.down('sm')]: { + flexDirection: 'column', + }, +})); + +export default InnerContainer; diff --git a/examples/next-14/styles/InnerContainerAnimate.jsx b/examples/next-14/styles/InnerContainerAnimate.jsx new file mode 100644 index 00000000..72befb28 --- /dev/null +++ b/examples/next-14/styles/InnerContainerAnimate.jsx @@ -0,0 +1,21 @@ +import { primaryColor } from '@layer5/sistent'; +import { styled } from '@mui/material/styles'; + +const InnerContainerAnimate = styled(InnerContainer)(({ theme }) => ({ + width: '100%', + top: '0%', + paddingX: '2rem', + transform: 'translate(0%, 0%)', + display: 'flex', + justifyContent: 'center', + left: '0%', + backgroundColor: primaryColor.dark, + [theme.breakpoints.down('sm')]: { + flexDirection: 'row', + paddingLeft: '1rem', + overflowX: 'auto', + padding: '0.4rem', + }, +})); + +export default InnerContainerAnimate; diff --git a/examples/next-14/styles/MainContainer.jsx b/examples/next-14/styles/MainContainer.jsx new file mode 100644 index 00000000..52ae1cec --- /dev/null +++ b/examples/next-14/styles/MainContainer.jsx @@ -0,0 +1,16 @@ +import { styled } from '@mui/material/styles'; + +export const darkCharcoal = '#464646'; + +const MainContainer = styled('div')(({ theme }) => ({ + backgroundColor: theme.palette.type === 'dark' ? darkCharcoal : theme.palette.common.white, + height: '25rem', + display: 'flex', + position: 'relative', + marginTop: '1rem', + [theme.breakpoints.down('sm')]: { + height: '47rem', + }, +})); + +export default MainContainer; diff --git a/examples/next-14/styles/MainContainerAnimate.jsx b/examples/next-14/styles/MainContainerAnimate.jsx new file mode 100644 index 00000000..95c7189d --- /dev/null +++ b/examples/next-14/styles/MainContainerAnimate.jsx @@ -0,0 +1,10 @@ +import { styled } from '@mui/material/styles'; + +const MainContainerAnimate = styled(MainContainer)(({ theme }) => ({ + height: '36rem', + [theme.breakpoints.down('sm')]: { + height: '73rem', + }, +})); + +export default MainContainerAnimate; diff --git a/examples/next-14/styles/MeshModelToolbar.jsx b/examples/next-14/styles/MeshModelToolbar.jsx new file mode 100644 index 00000000..b9b3a085 --- /dev/null +++ b/examples/next-14/styles/MeshModelToolbar.jsx @@ -0,0 +1,20 @@ +import { styled } from '@mui/material/styles'; + +const MeshModelToolbar = styled('div')(({ theme }) => ({ + display: 'flex', + justifyContent: 'space-between', + backgroundColor: + theme.palette.type === 'dark' + ? theme.palette.secondary.toolbarBg2 + : theme.palette.secondary.toolbarBg1, + boxShadow: '0px 2px 4px -1px rgba(0,0,0,0.2)', + height: '0rem', + padding: '0rem', + borderRadius: '0.5rem', + position: 'relative', + zIndex: 0, + marginBottom: '0.5rem', + marginTop: '1rem', +})); + +export default MeshModelToolbar; diff --git a/examples/next-14/styles/PaperSquare.jsx b/examples/next-14/styles/PaperSquare.jsx new file mode 100644 index 00000000..56ed2f16 --- /dev/null +++ b/examples/next-14/styles/PaperSquare.jsx @@ -0,0 +1,8 @@ +import { Paper } from '@layer5/sistent'; +import { styled } from '@mui/material/styles'; + +export const PaperSquare = styled(Paper)(() => ({ + flexGrow: 1, + maxWidth: '100%', + height: 'auto', +})); diff --git a/examples/next-14/styles/SearchAndView.jsx b/examples/next-14/styles/SearchAndView.jsx new file mode 100644 index 00000000..992dae9d --- /dev/null +++ b/examples/next-14/styles/SearchAndView.jsx @@ -0,0 +1,14 @@ +import { styled } from '@mui/material/styles'; + +const SearchAndView = styled('div')(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + margin: 'auto', + [theme.breakpoints.down('lg')]: { + paddingLeft: 0, + margin: 0, + }, +})); + +export default SearchAndView; diff --git a/examples/next-14/styles/ToolWrapper.jsx b/examples/next-14/styles/ToolWrapper.jsx new file mode 100644 index 00000000..589f9858 --- /dev/null +++ b/examples/next-14/styles/ToolWrapper.jsx @@ -0,0 +1,19 @@ +import { styled } from '@mui/material/styles'; + +const ToolWrapper = styled('div')(({ theme }) => ({ + marginBottom: '3rem', + display: 'flex', + justifyContent: 'space-between', + backgroundColor: + theme.palette.type === 'dark' + ? theme.palette.secondary.toolbarBg2 + : theme.palette.secondary.toolbarBg1, + boxShadow: '0px 2px 4px -1px rgba(0,0,0,0.2)', + height: '4rem', + padding: '0.68rem', + borderRadius: '0.5rem', + position: 'relative', + zIndex: 101, +})); + +export default ToolWrapper; diff --git a/examples/next-14/styles/ToolWrapperAnimate.jsx b/examples/next-14/styles/ToolWrapperAnimate.jsx new file mode 100644 index 00000000..d9268c80 --- /dev/null +++ b/examples/next-14/styles/ToolWrapperAnimate.jsx @@ -0,0 +1,9 @@ +import { styled } from '@mui/material/styles'; + +const ToolWrapperAnimate = styled('div')(({ theme }) => ({ + height: '4rem', + zIndex: 125, + padding: '0.68rem', +})); + +export default ToolWrapperAnimate; diff --git a/examples/next-14/utils/Elements.js b/examples/next-14/utils/Elements.js new file mode 100644 index 00000000..8611996b --- /dev/null +++ b/examples/next-14/utils/Elements.js @@ -0,0 +1,35 @@ +// Description: Contains functions related to DOM elements and react components. + +import React from 'react'; + +// recursively check if element or any of its parent has the class +export const hasClass = (element, className) => { + try { + if (typeof element?.className == 'string' && element?.className?.includes(className)) { + return true; + } + if (element?.parentElement) { + return hasClass(element.parentElement, className); + } + } catch (e) { + console.error(`Error in hasClass while checking for ${className} in `, element, e); + } + return false; +}; + +// recursively got throught component and its children and add the class to each of them +// This is required to prevent the clickaway listner from blocking the click event +// on the notification center IconButton create it as a HOC and use react.cloneElement to add the class +export const AddClassRecursively = ({ children, className }) => { + return React.Children.map(children, (child) => { + if (React.isValidElement(child)) { + return React.cloneElement(child, { + className: `${child.props.className} ${className}`, + children: AddClassRecursively({ children: child.props.children, className }), + }); + } + + // if child is a svg or animated svg string + return child; + }); +}; diff --git a/examples/next-14/utils/Enum.js b/examples/next-14/utils/Enum.js new file mode 100644 index 00000000..dd6ffb6d --- /dev/null +++ b/examples/next-14/utils/Enum.js @@ -0,0 +1,79 @@ +export const FILE_OPS = { + FILE_UPLOAD: 'upload', + URL_UPLOAD: 'url_upload', + UPDATE: 'update', + DELETE: 'delete', + DOWNLOAD: 'download', + CLONE: 'clone', +}; + +export const CON_OPS = { + DELETE: 'delete', + UPDATE: 'update', + CREATE: 'create', +}; +export const ACTIONS = { + DEPLOY: 2, + UNDEPLOY: 1, + VERIFY: 0, +}; + +export const DEPLOYMENT_TYPE = { + IN_CLUSTER: 'in_cluster', + OUT_CLUSTER: 'out_of_cluster', +}; + +export const VISIBILITY = { + PRIVATE: 'private', + PUBLIC: 'public', + PUBLISHED: 'published', +}; + +export const EVENT_TYPES = { + ADDED: 'ADDED', + DELETED: 'DELETED', + MODIFIED: 'MODIFIED', +}; + +export const EXTENSIONS = { + MESHMAP: 'meshmap', +}; + +export const CONNECTION_STATES = { + DISCOVERED: 'discovered', + REGISTERED: 'registered', + CONNECTED: 'connected', + IGNORED: 'ignored', + MAINTENANCE: 'maintenance', + DISCONNECTED: 'disconnected', + DELETED: 'deleted', + NOTFOUND: 'not found', +}; + +export const CONTROLLERS = { + BROKER: 'BROKER', + OPERATOR: 'OPERATOR', + MESHSYNC: 'MESHSYNC', +}; + +// Fetch from GraphQL/REST API remove this +export const CONTROLLER_STATES = { + DEPLOYED: 'DEPLOYED', + NOTDEPLOYED: 'NOTDEPLOYED', + UNDEPLOYED: 'UNDEPLOYED', + DEPLOYING: 'DEPLOYING', + ENABLED: 'ENABLED', + UNKOWN: 'UNKOWN', + RUNNING: 'RUNNING', + CONNECTED: 'CONNECTED', + DISABLED: 'DISABLED', +}; + +export const MesheryPatternsCatalog = 'meshery-patterns-catalog'; + +export const MesheryFiltersCatalog = 'meshery-filters-catalog'; + +export const CONNECTION_KINDS = { + MESHERY: 'meshery', + KUBERNETES: 'kubernetes', +}; diff --git a/examples/next-14/utils/axios.js b/examples/next-14/utils/axios.js new file mode 100644 index 00000000..b94c25f5 --- /dev/null +++ b/examples/next-14/utils/axios.js @@ -0,0 +1,15 @@ +import axios from 'axios'; + +const instance = axios.create({ + withCredentials: true, // for pushing client-cookies in all requests to server +}); + +instance.interceptors.response.use((response) => { + if (response.request.responseURL.includes('/auth/login')) { + window.location = '/auth/login'; + window.onbeforeunload = null; + } + return response; +}); + +export default instance; diff --git a/examples/next-14/utils/can.js b/examples/next-14/utils/can.js new file mode 100644 index 00000000..b41f4d4d --- /dev/null +++ b/examples/next-14/utils/can.js @@ -0,0 +1,7 @@ +import { PureAbility } from '@casl/ability'; + +export const ability = new PureAbility([]); + +export default function CAN(action, subject) { + return ability.can(action, subject); +} diff --git a/examples/next-14/utils/capabilitiesRegistry.js b/examples/next-14/utils/capabilitiesRegistry.js new file mode 100644 index 00000000..e69de29b diff --git a/examples/next-14/utils/charts.js b/examples/next-14/utils/charts.js new file mode 100644 index 00000000..a29dd297 --- /dev/null +++ b/examples/next-14/utils/charts.js @@ -0,0 +1,38 @@ +export const isValidColumnName = (name) => { + return name !== '' && name !== ' ' && name != undefined && name != null; +}; + +export const CHART_COLORS = [ + '#14232A', // Gunmetal + // '#213A45', + '#2E5261', + // '#294957', + '#3B697D', // Paynes' Gray + // '#396679', + '#4A839C', + // '#477E96', Teal Blue + '#5996B1', + // '#639CB5', + '#74A8BE', + // '#8Bb2C6', + '#90B9CB', + // '#AACCBD8', // Columbia Blue + '#CBDEE6', + // '#EEF4F7' +]; + +export const dataToColors = (data) => { + const columns = data.map((item) => item[0]); + const colors = {}; + let colorIdx = 0; + + columns.forEach((col) => { + if (colorIdx >= CHART_COLORS.length) { + colorIdx = 0; + } + colors[col] = CHART_COLORS[colorIdx]; + colorIdx += 1; + }); + + return colors; +}; diff --git a/examples/next-14/utils/connections.js b/examples/next-14/utils/connections.js new file mode 100644 index 00000000..435ac8eb --- /dev/null +++ b/examples/next-14/utils/connections.js @@ -0,0 +1,5 @@ +import { promisifiedDataFetch } from './dataFetch'; + +export const getConnectionStatusSummary = async () => { + return await promisifiedDataFetch('/api/integrations/connections/status'); +}; diff --git a/examples/next-14/utils/constants/colors.js b/examples/next-14/utils/constants/colors.js new file mode 100644 index 00000000..56383fc0 --- /dev/null +++ b/examples/next-14/utils/constants/colors.js @@ -0,0 +1,6 @@ +// derived from Figma +export const PRIMARY_COLOR = '#647881'; +export const SUCCESS_COLOR = '#83B71E'; +export const INFO_COLOR = '#2AC3D1'; +export const WARNING_COLOR = '#EBC017'; +export const ERROR_COLOR = '#B32700'; diff --git a/examples/next-14/utils/constants/common.js b/examples/next-14/utils/constants/common.js new file mode 100644 index 00000000..062d18ce --- /dev/null +++ b/examples/next-14/utils/constants/common.js @@ -0,0 +1,5 @@ +export const ErrorTypes = { + MESHERY_DEPLOYMENT_INCOMPATIBLE: 'MESHERY_DEPLOYMENT_INCOMPATIBLE', + PAGE_NOT_FOUND: 'PAGE_NOT_FOUND', + UNKNOWN: 'UNKNOWN', +}; diff --git a/examples/next-14/utils/constants/endpoints.js b/examples/next-14/utils/constants/endpoints.js new file mode 100644 index 00000000..dc7c40af --- /dev/null +++ b/examples/next-14/utils/constants/endpoints.js @@ -0,0 +1,12 @@ +// The constants for API endpoints +export const MESHMODEL_ENDPOINT = '/api/meshmodels/models'; +export const MESHMODEL_COMPONENT_ENDPOINT = '/api/meshmodels'; +export const MESHMODEL_RELATIONSHIPS_ENDPOINT = '/api/meshmodels/models/core/relationships'; +export const MESHERY_CLOUD_PROD = 'https://meshery.layer5.io'; +export const PATTERN_ENDPOINT = '/api/pattern'; +export const FILTER_ENDPOINT = '/api/filter'; +export const RJSF_SCHEMAS = '/api/schema/resource'; +export const SORT = { + ASCENDING: 'asc', + DESCENDING: 'desc', +}; diff --git a/examples/next-14/utils/constants/navigator.js b/examples/next-14/utils/constants/navigator.js new file mode 100644 index 00000000..ee440819 --- /dev/null +++ b/examples/next-14/utils/constants/navigator.js @@ -0,0 +1,60 @@ +export const DASHBOARD = 'dashboard'; +export const LIFECYCLE = 'lifecycle'; +export const CONFIGURATION = 'configuration'; +export const CONFORMANCE = 'conformance'; +export const PERFORMANCE = 'performance'; + +export const WORKLOADS = 'workloads'; +export const STORAGE = 'storage'; +export const NETWORK = 'network'; +export const SECURITY = 'security'; +export const CONFIG = 'config'; + +export const CONNECTION = 'connection'; +export const ENVIRONMENT = 'environment'; +export const WORKSPACE = 'Workspace'; +export const SERVICE_MESH = 'service_mesh'; +export const ISTIO = 'istio'; +export const KUMA = 'kuma'; +export const CILIUM_SM = 'cilium_service_mesh'; +export const TRAEFIK_SM = 'traefik_mesh'; +export const LINKERD = 'linkerd'; +export const OSM = 'open_service_mesh'; +export const CONSUL = 'consul'; +export const NGINX = 'nginx_service_mesh'; +export const APP_MESH = 'app_mesh'; +export const CITRIX_SM = 'citrix_Service_mesh'; +export const NETWORK_SM = 'network_service_mesh'; +export const OCTARINE = 'ocatarine'; + +export const FILTER = 'filter'; +export const APPLICATION = 'application'; +export const PATTERN = 'pattern'; +export const DESIGN = 'design'; +export const WORKLOAD = 'workload'; +export const FILTER_PLURAL = 'filters'; +export const APPLICATION_PLURAL = 'applications'; +export const PATTERN_PLURAL = 'patterns'; + +export const PROFILES = 'profiles'; +export const SMI = 'service_mesh_interface'; +export const TOGGLER = 'toggler'; + +export const SETTINGS = 'settings'; +export const CONTEXT_SWITCHER = 'contextSwitcher'; + +export const OVERVIEW = 'Overview'; +export const MODELS = 'Models'; +export const COMPONENTS = 'Components'; +export const RELATIONSHIPS = 'Relationships'; +export const POLICIES = 'Policies'; +export const REGISTRANTS = 'Registrants'; +export const REGISTRY = 'Registry'; +export const ADAPTERS = 'Adapters'; +export const RESET = 'Reset'; +export const METRICS = 'Metrics'; +export const GRAFANA = 'Grafana'; +export const PROMETHEUS = 'Prometheus'; +export const INCLUSTER_CONFIG = 'Inclusterconfig'; +export const OUTCLUSTER_CONFIG = 'Outclusterconfig'; +export const ENDPOINTURL = 'https://playground.meshery.io/'; diff --git a/examples/next-14/utils/constants/notification.js b/examples/next-14/utils/constants/notification.js new file mode 100644 index 00000000..1a384694 --- /dev/null +++ b/examples/next-14/utils/constants/notification.js @@ -0,0 +1,28 @@ +export const NOTIFICATION_STATUS = { + VIEWED: 'viewed', + NEW: 'new', +}; + +export const NOTIFICATION_EVENT_TYPES = { + SUCCESS: { + type: 'success', + }, + DEFAULT: { + type: 'default', + }, + INFO: { + type: 'info', + }, + WARNING: { + type: 'warning', + }, + ERROR: { + type: 'error', + }, +}; + +export const SERVER_EVENT_TYPES = { + 0: NOTIFICATION_EVENT_TYPES.SUCCESS, + 1: NOTIFICATION_EVENT_TYPES.WARNING, + 2: NOTIFICATION_EVENT_TYPES.ERROR, +}; diff --git a/examples/next-14/utils/dataFetch.js b/examples/next-14/utils/dataFetch.js new file mode 100644 index 00000000..14e93422 --- /dev/null +++ b/examples/next-14/utils/dataFetch.js @@ -0,0 +1,64 @@ +const dataFetch = (url, options = {}, successFn, errorFn) => { + // const controller = new AbortController(); + // const signal = controller.signal; + // options.signal = signal; + // setTimeout(() => controller.abort(), 10000); // nice to have but will mess with the load test + if (errorFn === undefined) { + errorFn = (err) => { + console.error(`Error fetching ${url} --DataFetch`, err); + }; + } + fetch(url, options) + .then((res) => { + if (res.status === 401 || res.redirected) { + if (window.location.host.endsWith('3000')) { + window.location = '/user/login'; // for local dev thru node server + } else { + window.location.reload(); // for use with Go server + } + } + + let result; + if (res.ok) { + result = res.text().then((text) => { + try { + return JSON.parse(text); + } catch (e) { + return text; + } + }); + + return result; + } else { + throw res.text(); + } + }) + .then(successFn) + .catch((e) => { + if (e.then) { + e.then((text) => errorFn(text)); + return; + } + errorFn(e); + }); +}; + +/** + * promisifiedDataFetch adds a promise wrapper to the dataFetch function + * and ideal for use inside async functions - which is most of the functions + * @param {string} url url is the endpoint + * @param {Record<string, any>} options HTTP request options + * @returns + */ +export function promisifiedDataFetch(url, options = {}) { + return new Promise((resolve, reject) => { + dataFetch( + url, + options, + (result) => resolve(result), + (err) => reject(err), + ); + }); +} + +export default dataFetch; diff --git a/examples/next-14/utils/eventTypes.js b/examples/next-14/utils/eventTypes.js new file mode 100644 index 00000000..aaa2eb9a --- /dev/null +++ b/examples/next-14/utils/eventTypes.js @@ -0,0 +1,28 @@ +export const NOTIFICATION_STATUS = { + VIEWED: 'viewed', + NEW: 'new', +}; + +export const EVENT_TYPES = { + SUCCESS: { + type: 'success', + }, + DEFAULT: { + type: 'default', + }, + INFO: { + type: 'info', + }, + WARNING: { + type: 'warning', + }, + ERROR: { + type: 'error', + }, +}; + +export const SERVER_EVENT_TYPES = { + 0: EVENT_TYPES.SUCCESS, + 1: EVENT_TYPES.WARNING, + 2: EVENT_TYPES.ERROR, +}; diff --git a/examples/next-14/utils/extensionPointSchemaValidator.js b/examples/next-14/utils/extensionPointSchemaValidator.js new file mode 100644 index 00000000..26e84989 --- /dev/null +++ b/examples/next-14/utils/extensionPointSchemaValidator.js @@ -0,0 +1,142 @@ +/** + * @typedef {{ + * title: string; + * onClickCallback: number; + * href: string; + * component: string; + * icon: string; + * children: NavigatorSchema[]; + * type: string; + * isBeta?: boolean; + * }} NavigatorSchema + */ + +/** + * @typedef {{ + * component: string; + * type: string; + * }} UserPreferenceSchema + */ + +/** + * @typedef {{ + * title: string; + * onClickCallback: number; + * href: string; + * component: string; + * children: AccountSchema[]; + * type: string; + * }} AccountSchema + */ + +/** + * @typedef {{ + * title: string; + * onClickCallback: number; + * href: string; + * component: string; + * children: AccountSchema[]; + * type: string; + * }} FullPageExtensionSchema + */ + +/** + * @typedef {NavigatorSchema | UserPreferenceSchema | AccountSchema | FullPageExtensionSchema} ExtensionSchema + */ + +/** + * Validates extension point schema based on provided type. + * @param {"navigator" | "user_prefs" | "account"} type - Type of the schema. + * @returns {(content: any) => ExtensionSchema[]} A function that validates the content and returns an array of ExtensionSchema. + */ +export default function extensionPointSchemaValidator(type) { + switch (type) { + case 'navigator': + return navigatorExtensionSchemaDecoder; + case 'user_prefs': + return userPreferenceExtensionSchemaDecoder; + case 'account': + return accountExtensionSchemaDecoder; + default: + return () => []; + } +} + +/** + * Decodes navigator extension schema. + * @param {any[]} content - Content to decode. + * @returns {NavigatorSchema[]} Decoded navigator schema. + */ +function navigatorExtensionSchemaDecoder(content) { + if (Array.isArray(content)) { + return content.map((item) => { + return { + title: item.title || '', + href: prepareHref(item.href), + component: item.component || '', + onClickCallback: item?.on_click_callback || 0, + icon: (item.icon && '/api/provider/extension/' + item.icon) || '', + show: !!item.show, + children: navigatorExtensionSchemaDecoder(item.children), + full_page: item.full_page, + isBeta: item.isBeta ?? false, + type: 'navigator', // Add the 'type' property with the value 'navigator' + }; + }); + } + + return []; +} + +/** + * Decodes user preference extension schema. + * @param {any} content - Content to decode. + * @returns {UserPreferenceSchema[]} Decoded user preference schema. + */ +function userPreferenceExtensionSchemaDecoder(content) { + if (Array.isArray(content)) { + return content.map((item) => { + return { + component: item.component || '', + type: 'user_prefs', // Add the 'type' property with the value 'user_prefs' + }; + }); + } + + return []; +} + +/** + * Decodes account extension schema. + * @param {any} content - Content to decode. + * @returns {AccountSchema[]} Decoded account schema. + */ +function accountExtensionSchemaDecoder(content) { + if (Array.isArray(content)) { + return content.map((item) => { + return { + title: item.title || '', + href: prepareHref(item.href), + component: item.component || '', + onClickCallback: item?.on_click_callback || 0, + show: !!item.show, + children: accountExtensionSchemaDecoder(item.children), + full_page: item.full_page, + type: 'account', // Add the 'type' property with the value 'account' + }; + }); + } + + return []; +} + +/** + * Prepares href based on provided data. + * @param {any} href - Href data. + * @returns {string} Prepared href. + */ +function prepareHref(href) { + if (href.external) return href.uri || ''; + + return '/extension' + (href.uri || ''); +} diff --git a/examples/next-14/utils/getPath.js b/examples/next-14/utils/getPath.js new file mode 100644 index 00000000..023bad69 --- /dev/null +++ b/examples/next-14/utils/getPath.js @@ -0,0 +1,8 @@ +export function getPath() { + let path = typeof window !== 'undefined' ? window.location.pathname : ''; + if (path.lastIndexOf('/') > 0) { + path = path.substring(0, path.lastIndexOf('/')); + } + path += typeof window !== 'undefined' ? window.location.search : ''; + return path; +} diff --git a/examples/next-14/utils/meshmodel/index.jsx b/examples/next-14/utils/meshmodel/index.jsx new file mode 100644 index 00000000..a879e80d --- /dev/null +++ b/examples/next-14/utils/meshmodel/index.jsx @@ -0,0 +1,223 @@ +import { promisifiedDataFetch } from '../dataFetch'; +import { + MESHMODEL_COMPONENT_ENDPOINT, + MESHMODEL_ENDPOINT, + MESHMODEL_RELATIONSHIPS_ENDPOINT, +} from '../constants/endpoints'; + +const COMPONENTS_ENDPOINT = '/api/meshmodels/components'; +const CATEGORIES_ENDPOINT = '/api/meshmodels/categories'; + +/** + * @typedef {{ + * paginated: Boolean; + * pageSize: (Number|"all"); + * page: Number; + * trim: Boolean + * }} pageOptions + */ + +/** @type {pageOptions} */ +const defaultOptions = { + paginated: false, + pageSize: 'all', + page: 0, + trim: true, +}; + +/** + * Fetches the Relationships from the server + * + * @returns + */ +export async function fetchRelationships() { + return await promisifiedDataFetch(`${MESHMODEL_RELATIONSHIPS_ENDPOINT}`); +} + +export async function getAllComponents(page = 1, pageSize = 'all') { + return await promisifiedDataFetch(`${COMPONENTS_ENDPOINT}?page=${page}&pagesize=${pageSize}`); +} + +export async function getMeshModels(page = 1, pageSize = 'all', options = defaultOptions) { + return await promisifiedDataFetch( + `${MESHMODEL_ENDPOINT}?page=${page}&pagesize=${pageSize}&${optionToQueryConvertor({ + ...defaultOptions, + ...options, + })}`, + ); +} + +export async function getComponentFromModelApi(model, pageSize = 'all', trim = true) { + return await promisifiedDataFetch( + `${MESHMODEL_ENDPOINT}/${model}/components?pagesize=${pageSize}&trim=${trim}`, + ); +} + +export async function getMeshModelsByRegistrants(page = 1, pageSize = 'all', registrant) { + return await promisifiedDataFetch( + `${MESHMODEL_ENDPOINT}?page=${page}&pagesize=${pageSize}®istrant=${registrant}`, + ); +} + +export async function getRelationshipFromModelApi(model, pageSize = 'all', trim = true) { + return await promisifiedDataFetch( + `${MESHMODEL_ENDPOINT}/${model}/relationships?pagesize=${pageSize}&trim=${trim}`, + ); +} + +export async function getDuplicateModels(model, version) { + return await promisifiedDataFetch(`${MESHMODEL_ENDPOINT}/${model}?version=${version} `); +} + +export async function getDuplicateComponents(componentKind, apiVersion, modelName) { + return await promisifiedDataFetch( + `${COMPONENTS_ENDPOINT}/${componentKind}?apiVersion=${apiVersion}&?model=${modelName}`, + ); +} + +export async function getMeshModelRegistrants(page = 1, pageSize = 'all') { + return await promisifiedDataFetch( + `/api/meshmodels/registrants?page=${page}&pageSize=${pageSize}`, + ); +} + +export async function getVersionedComponentFromModel( + model, + version, + pageSize = 'all', + trim = true, +) { + return await promisifiedDataFetch( + `${MESHMODEL_ENDPOINT}/${model}/components?version=${version}&pagesize=${pageSize}&trim=${trim}`, + ); +} + +export async function getComponentsDetailWithPageSize( + page = 1, + pageSize = 'all', + sort = SORT.ASCENDING, + order = '', +) { + return await promisifiedDataFetch( + `api/meshmodels/components?page=${page}&pagesize=${pageSize}&order=${encodeURIComponent( + order, + )}&sort=${sort}`, + ); +} + +export async function getComponentsDetail(page) { + return await promisifiedDataFetch(`api/meshmodels/components?page=${page}`); +} + +export async function getModelsDetail(page) { + return await promisifiedDataFetch(`${MESHMODEL_ENDPOINT}?page=${page}`); +} + +export async function getRelationshipsDetailWithPageSize( + page = 1, + pageSize = 'all', + sort = SORT.ASCENDING, + order = '', +) { + return await promisifiedDataFetch( + `api/meshmodels/relationships?page=${page}&pagesize=${pageSize}&sort=${sort}&order=${encodeURIComponent( + order, + )}`, + ); +} + +export async function getRelationshipsDetail(page) { + return await promisifiedDataFetch(`api/meshmodels/relationships?page=${page}`); +} + +export async function getMeshModelComponent(model, component, version, apiVersion) { + const versionQueryString = !version ? '' : `?version=${version}`; + const apiVersionQueryString = !apiVersion + ? '' + : !version + ? `?apiVersion=${apiVersion}` + : `&apiVersion=${apiVersion}`; + + return promisifiedDataFetch( + `${MESHMODEL_ENDPOINT}/${model}/components/${component}${versionQueryString}${apiVersionQueryString}`, + ); +} + +export async function getMeshModelComponentByName(component) { + return promisifiedDataFetch(`${MESHMODEL_COMPONENT_ENDPOINT}/components/${component}`); +} +// export async function queryMeshModel(modelQueryString, paginated = true) { +// // Note: returns paginated response +// if (paginated) { +// return promisifiedDataFetch(`${MESHMODEL_ENDPOINT}/${modelQueryString}?search=true&trim=true`); +// } + +// // to get full response +// return promisifiedDataFetch( +// `${MESHMODEL_ENDPOINT}/${modelQueryString}?search=true&page=1&pagesize=all&trim=true` +// ); +// } + +export async function fetchCategories() { + return promisifiedDataFetch(`${CATEGORIES_ENDPOINT}`); +} + +export async function getModelFromCategoryApi(category) { + return promisifiedDataFetch(`${CATEGORIES_ENDPOINT}/${category}/models?pagesize=all`); +} + +/** + * + * @param {string} queryString + * @param {pageOptions} options + */ +export async function searchModels(queryString, options = defaultOptions) { + return promisifiedDataFetch( + `${MESHMODEL_ENDPOINT}?search=${encodeURI(queryString)}&${optionToQueryConvertor({ + ...defaultOptions, + ...options, + })}`, + ); +} + +export async function searchComponents(queryString, options = defaultOptions) { + return promisifiedDataFetch( + `/api/meshmodels/components?search=${encodeURI(queryString)}&${optionToQueryConvertor( + options, + )}`, + ); +} + +export async function getModelByName(modelName, options = defaultOptions) { + return promisifiedDataFetch( + `${MESHMODEL_ENDPOINT}/${modelName}?${optionToQueryConvertor(options)}`, + ); +} +/** + * + * @param {pageOptions} options + */ +function optionToQueryConvertor(options) { + const uri = new URLSearchParams(); + const { pageSize, page, trim, components, relationships } = options; + + if (trim) { + uri.append('trim', `${trim}`); + } + + if (pageSize) { + uri.append('pagesize', `${pageSize}`); + } + + if (page) { + uri.append('page', `${page}`); + } + + if (components) { + uri.append('components', `${components}`); + } + if (relationships) { + uri.append('relationships', `${relationships}`); + } + return uri.toString(); +} diff --git a/examples/next-14/utils/multi-ctx.js b/examples/next-14/utils/multi-ctx.js new file mode 100644 index 00000000..0cfbe08a --- /dev/null +++ b/examples/next-14/utils/multi-ctx.js @@ -0,0 +1,163 @@ +/** + * A function to be used by the requests sent for the + * operations based on multi-context support + * + * @param {string} url The request URL + * @param {Array.<string>} ctx The context Array + * @returns {string} The final query-parametrised URL + */ +export function ctxUrl(url, ctx) { + if (ctx?.length) { + const contextQuery = ctx.map((context) => `contexts=${context}`).join('&'); + return `${url}?${contextQuery}`; + } + return url; +} + +/** + * The function takes in all the context and returns + * their respective cluster IDs associated to them + * + * @param {Array.<string>} selectedContexts + * @param {Array.<string>} k8sconfig + * @returns {Array.<string>} An array of cluster IDs + */ +export const getK8sClusterIdsFromCtxId = (selectedContexts, k8sconfig) => { + if (selectedContexts.length === 0) { + return []; + } + + if (selectedContexts.includes('all')) { + return k8sconfig.map((cfg) => cfg?.kubernetes_server_id); + } + const clusterIds = []; + selectedContexts.forEach((context) => { + const clusterId = k8sconfig.find((cfg) => cfg.id === context)?.kubernetes_server_id; + if (clusterId) { + clusterIds.push(clusterId); + } + }); + + return clusterIds; +}; + +/** + * Get the context ID of the first selected context IDs + * + * @param {Array.<string>} selectedK8sContexts + * @param {Array.<string>} k8sConfig + * @returns {string} The context ID + */ +export function getFirstCtxIdFromSelectedCtxIds(selectedK8sContexts, k8sConfig) { + if (!selectedK8sContexts?.length) { + return ''; + } + + if (selectedK8sContexts?.includes('all')) { + return k8sConfig[0]?.id; + } + + return selectedK8sContexts[0]; +} + +/** + * Get the Kubernetes config IDs + * + * @param {Array.<Object>} k8sConfig + * @returns {Array.<string>} An array of config IDs + */ +export function getK8sConfigIdsFromK8sConfig(k8sConfig) { + if (!k8sConfig || !k8sConfig.length) { + return []; + } + + return k8sConfig.map((cfg) => cfg.id); +} + +/** + * Get the cluster names from context IDs + * + * @param {Array.<string>} selectedContexts + * @param {Array.<string>} k8sconfig + * @returns {Array.<string>} An array of cluster names + */ +export const getK8sClusterNamesFromCtxId = (selectedContexts, k8sconfig) => { + if (selectedContexts.length === 0) { + return []; + } + + if (selectedContexts.includes('all')) { + return ['all']; + } + + const clusterNames = []; + + selectedContexts.forEach((context) => { + const name = k8sconfig.find((cfg) => cfg.id === context)?.name; + if (name) { + clusterNames.push(name); + } + }); + + return clusterNames; +}; + +/** + * Get the cluster name from the cluster ID + * + * @param {string} clusterId Kubernetes Cluster ID + * @param {Array<Object>} k8sConfig Kubernetes config + * @returns {string} Kubernetes cluster name + */ +export function getClusterNameFromClusterId(clusterId, k8sConfig) { + const cluster = k8sConfig.find((cfg) => cfg.kubernetes_server_id === clusterId); + if (!cluster) { + return ''; + } + return cluster.name; +} + +/** + * Get the cluster name from the connection ID + * + * @param {string} connectionId Kubernetes Connection ID + * @param {Array<Object>} k8sConfig Kubernetes config + * @returns {string} Kubernetes cluster name + */ +export function getClusterNameFromConnectionId(connectionId, k8sConfig) { + const cluster = k8sConfig.find((cfg) => cfg.connection_id === connectionId); + if (!cluster) { + return ''; + } + return cluster.name; +} + +/** + * Get the connection ID from the cluster ID + * + * @param {string} clusterId Kubernetes Cluster ID + * @param {Array<Object>} k8sConfig Kubernetes config + * @returns {string} Kubernetes connection ID + */ +export function getConnectionIdFromClusterId(clusterId, k8sConfig) { + const cluster = k8sConfig.find((cfg) => cfg.kubernetes_server_id === clusterId); + if (!cluster) { + return ''; + } + return cluster.connection_id; +} + +/** + * Get the cluster name from the context ID + * + * @param {string} ctxId Kubernetes context ID + * @param {Array<Object>} k8sConfig Kubernetes config + * @returns {string} Kubernetes cluster name + */ +export function getClusterNameFromCtxId(ctxId, k8sConfig) { + const cluster = k8sConfig.find((cfg) => cfg.id === ctxId); + if (!cluster) { + return ''; + } + return cluster.name; +} diff --git a/examples/next-14/utils/nameMapper.js b/examples/next-14/utils/nameMapper.js new file mode 100644 index 00000000..1d95a2ad --- /dev/null +++ b/examples/next-14/utils/nameMapper.js @@ -0,0 +1,53 @@ +export const podNameMapper = (serviceMeshName, podName) => { + switch (serviceMeshName) { + case 'istio': + if (podName.includes('istio-galley')) return 'Istio Galley'; + if (podName.includes('istio-ingressgateway')) return 'Istio Ingress Gateway'; + if (podName.includes('istio-egressgateway')) return 'Istio Egress Gateway'; + if (podName.includes('istio-policy')) return 'Istio Policy'; + if (podName.includes('istio-citadel')) return 'Istio Citadel'; + if (podName.includes('istio-telemetry')) return 'Istio Telemetry'; + if (podName.includes('istio-pilot')) return 'Istio Pilot'; + if (podName.includes('istio-tracing')) return 'Istio Tracing'; + if (podName.includes('istio-sidecar-injector')) return 'Istio Sidecar Injector'; + break; + case 'kiali': + return 'Kiali'; + case 'grafana': + return 'Grafana'; + case 'prometheus': + return 'Prometheus'; + default: + break; + } + const podNameArr = podName.split('-'); + + if (Array.isArray(podNameArr)) { + const prettifiedPodName = podNameArr + .slice(0, -2) + .map((word) => word[0].toUpperCase() + word.substr(1)) + .join(' '); + + return prettifiedPodName; + } + return podName; +}; + +export const versionMapper = (versionName) => + versionName.charAt(0) === 'v' ? versionName : `v${versionName}`; + +export const TelemetryComps = { + GRAFANA: 'grafana', + PROMETHEUS: 'prometheus', +}; + +// maps objects to telemetry comp if name is one of "TelemetryComps" +export function isTelemetryComponent(name) { + const comps = Object.values(TelemetryComps); + for (const comp in comps) { + if (name?.toLowerCase().includes(comps[comp])) { + return comps[comp]; + } + } + return ''; +} diff --git a/examples/next-14/utils/patterns.js b/examples/next-14/utils/patterns.js new file mode 100644 index 00000000..ae0cbeee --- /dev/null +++ b/examples/next-14/utils/patterns.js @@ -0,0 +1,24 @@ +import { ctxUrl } from './multi-ctx'; + +export async function dryRunPattern(patternFileData, contexts) { + return deployPatternWithData(patternFileData, contexts, { + verify: false, + dryRun: true, + }); +} + +/** + * Deploys pattern with the content provided to it. + * It is {pattern_file} property of the patterns meta + * + * @param {String} patternFileData + * @param {String} contexts + * @param {{verify: Boolean, dryRun: Boolean}} options + */ +export async function deployPatternWithData(patternFileData, contexts, options) { + const { verify = false, dryRun = false } = options; + const endpoint = `${ctxUrl(PATTERN_ENDPOINT + '/deploy', contexts)}${ + verify ? '&verify=true' : '' + }${dryRun ? '&dryRun=true' : ''}`; + return await api.post(endpoint, patternFileData); +} diff --git a/examples/next-14/utils/prePopulatedOptions.js b/examples/next-14/utils/prePopulatedOptions.js new file mode 100644 index 00000000..77dee434 --- /dev/null +++ b/examples/next-14/utils/prePopulatedOptions.js @@ -0,0 +1,14 @@ +export const durationOptions = [ + '15s', + '30s', + '1m', + '3m', + '5m', + '10m', + '30m', + '1h', + '2h', + '5h', + '10h', + '1d', +]; diff --git a/examples/next-14/utils/trueRandom.js b/examples/next-14/utils/trueRandom.js new file mode 100644 index 00000000..5597d912 --- /dev/null +++ b/examples/next-14/utils/trueRandom.js @@ -0,0 +1,3 @@ +export function trueRandom() { + return crypto.getRandomValues(new Uint32Array(1))[0] / 2 ** 32; +} diff --git a/examples/next-14/utils/urlValidator.js b/examples/next-14/utils/urlValidator.js new file mode 100644 index 00000000..51b3c4c4 --- /dev/null +++ b/examples/next-14/utils/urlValidator.js @@ -0,0 +1,14 @@ +export const urlValidator = (url) => { + const compulsoryProtocolValidUrlPattern = new RegExp( + '(^(http|https|nats|tcp):\\/\\/)' + // compulsory protocol + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.{0,})+[a-z]{0,}|' + // domain name + 'localhost|' + + '((\\d{1,3}.){3}\\d{1,3}))' + // OR ip (v4) address + '(\\:\\d+)?(/[-a-z\\d%_.~+]*)*' + // port and path + '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string + '(\\#[-a-z\\d_]*)?$', + 'i', + ); // fragment locator + + return url?.match(compulsoryProtocolValidUrlPattern); +}; diff --git a/examples/next-14/utils/utils.js b/examples/next-14/utils/utils.js new file mode 100644 index 00000000..8b5fb229 --- /dev/null +++ b/examples/next-14/utils/utils.js @@ -0,0 +1,16 @@ +import { EVENT_TYPES } from './Enum'; + +export function updateURLs(urlsSet, newUrls, eventType) { + switch (eventType) { + case EVENT_TYPES.DELETED: + newUrls.forEach((url) => { + urlsSet.delete(url); + }); + break; + case EVENT_TYPES.ADDED: + case EVENT_TYPES.MODIFIED: + newUrls.forEach((url) => { + urlsSet.add(url); + }); + } +} diff --git a/examples/next-14/utils/zIndex.js b/examples/next-14/utils/zIndex.js new file mode 100644 index 00000000..e052aff5 --- /dev/null +++ b/examples/next-14/utils/zIndex.js @@ -0,0 +1,16 @@ +/** + * function used to calculate the zIndex + * @param {number} p - power of zIndex - directly proportional to `zIndex` (css property) value + * @returns {string} zIndex + */ +export const ziCalc = (p = 1) => { + if (p >= 1) { + // 1 is the least power for zIndex + let zIndex = ''; + for (let i = 0; i < p; i++) { + zIndex = zIndex + '9'; + } + return zIndex; + } + `0`; +};