Compare commits
18 Commits
@nhost/vue
...
@nhost/das
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4a0aad2dd | ||
|
|
1030813279 | ||
|
|
917a14aa40 | ||
|
|
6381d1b095 | ||
|
|
8dbdc0bf50 | ||
|
|
8c072a4c6e | ||
|
|
fe341519f7 | ||
|
|
757c888656 | ||
|
|
7c13eb5f9b | ||
|
|
a84608e086 | ||
|
|
e43c079b9c | ||
|
|
3f396a9ebb | ||
|
|
6ed605beb8 | ||
|
|
edd223d29c | ||
|
|
b17e8d6f3c | ||
|
|
12e2855f01 | ||
|
|
c1080d9e63 | ||
|
|
e4972b8307 |
@@ -1,5 +1,19 @@
|
||||
# @nhost/dashboard
|
||||
|
||||
## 0.16.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 12e2855f: chore(deps): bump `jsdom` to v22
|
||||
- e4972b83: feat(metrics): add Grafana page
|
||||
|
||||
## 0.16.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 3f396a9e: fix(projects): unpause after upgrading a paused project to pro
|
||||
- 3f396a9e: fix(projects): don't redirect to 404 page after project creation
|
||||
|
||||
## 0.16.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -30,7 +30,7 @@ test('should show a sidebar with menu items', async () => {
|
||||
const navLocator = page.getByRole('navigation', { name: /main navigation/i });
|
||||
await expect(navLocator).toBeVisible();
|
||||
await expect(navLocator.getByRole('list').getByRole('listitem')).toHaveCount(
|
||||
10,
|
||||
11,
|
||||
);
|
||||
await expect(
|
||||
navLocator.getByRole('link', { name: /overview/i }),
|
||||
@@ -53,6 +53,9 @@ test('should show a sidebar with menu items', async () => {
|
||||
navLocator.getByRole('link', { name: /backups/i }),
|
||||
).toBeVisible();
|
||||
await expect(navLocator.getByRole('link', { name: /logs/i })).toBeVisible();
|
||||
await expect(
|
||||
navLocator.getByRole('link', { name: /metrics/i }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
navLocator.getByRole('link', { name: /settings/i }),
|
||||
).toBeVisible();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/dashboard",
|
||||
"version": "0.16.3",
|
||||
"version": "0.16.5",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
@@ -129,7 +129,7 @@
|
||||
"eslint-plugin-jsx-a11y": "^6.6.1",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"jsdom": "^21.0.0",
|
||||
"jsdom": "^22.0.0",
|
||||
"lint-staged": ">=13",
|
||||
"msw": "^1.0.1",
|
||||
"msw-storybook-addon": "^1.6.3",
|
||||
|
||||
1
dashboard/public/assets/grafana.svg
Normal file
1
dashboard/public/assets/grafana.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.3 KiB |
@@ -33,7 +33,8 @@ export default function ApplicationPaused() {
|
||||
} = useCurrentWorkspaceAndProject();
|
||||
const user = useUserData();
|
||||
const isOwner = currentWorkspace.workspaceMembers.some(
|
||||
({ id, type }) => id === user?.id && type === 'owner',
|
||||
({ type, user: workspaceUser }) =>
|
||||
workspaceUser.id === user?.id && type === 'owner',
|
||||
);
|
||||
const [showDeletingModal, setShowDeletingModal] = useState(false);
|
||||
const [unpauseApplication, { loading: changingApplicationStateLoading }] =
|
||||
@@ -120,20 +121,22 @@ export default function ApplicationPaused() {
|
||||
</Box>
|
||||
|
||||
<Box className="grid grid-flow-row gap-2">
|
||||
<Button
|
||||
className="mx-auto w-full max-w-[280px]"
|
||||
onClick={() => {
|
||||
openDialog({
|
||||
component: <ChangePlanModal />,
|
||||
props: {
|
||||
PaperProps: { className: 'p-0' },
|
||||
maxWidth: 'lg',
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
Upgrade to Pro
|
||||
</Button>
|
||||
{isOwner && (
|
||||
<Button
|
||||
className="mx-auto w-full max-w-[280px]"
|
||||
onClick={() => {
|
||||
openDialog({
|
||||
component: <ChangePlanModal />,
|
||||
props: {
|
||||
PaperProps: { className: 'p-0' },
|
||||
maxWidth: 'lg',
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
Upgrade to Pro
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<div className="grid grid-flow-row gap-2">
|
||||
<Button
|
||||
|
||||
@@ -6,7 +6,9 @@ import {
|
||||
useGetPaymentMethodsQuery,
|
||||
useUpdateApplicationMutation,
|
||||
} from '@/generated/graphql';
|
||||
import useApplicationState from '@/hooks/useApplicationState';
|
||||
import { useCurrentWorkspaceAndProject } from '@/hooks/v2/useCurrentWorkspaceAndProject';
|
||||
import { ApplicationStatus } from '@/types/application';
|
||||
import ActivityIndicator from '@/ui/v2/ActivityIndicator';
|
||||
import Box from '@/ui/v2/Box';
|
||||
import Button from '@/ui/v2/Button';
|
||||
@@ -15,11 +17,11 @@ import { BaseDialog } from '@/ui/v2/Dialog';
|
||||
import Link from '@/ui/v2/Link';
|
||||
import Text from '@/ui/v2/Text';
|
||||
import { planDescriptions } from '@/utils/planDescriptions';
|
||||
import getServerError from '@/utils/settings/getServerError/getServerError';
|
||||
import getServerError from '@/utils/settings/getServerError';
|
||||
import { getToastStyleProps } from '@/utils/settings/settingsConstants';
|
||||
import Image from 'next/image';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
|
||||
function Plan({ planName, price, setPlan, planId, selectedPlanId }: any) {
|
||||
@@ -53,7 +55,7 @@ function Plan({ planName, price, setPlan, planId, selectedPlanId }: any) {
|
||||
</div>
|
||||
|
||||
<Text variant="h3" component="p">
|
||||
$ {price}/mo
|
||||
${price}/mo
|
||||
</Text>
|
||||
</button>
|
||||
);
|
||||
@@ -62,12 +64,14 @@ function Plan({ planName, price, setPlan, planId, selectedPlanId }: any) {
|
||||
export function ChangePlanModalWithData({ app, plans, close }: any) {
|
||||
const [selectedPlanId, setSelectedPlanId] = useState('');
|
||||
const { closeAlertDialog } = useDialog();
|
||||
const [pollingCurrentProject, setPollingCurrentProject] = useState(false);
|
||||
|
||||
const {
|
||||
currentWorkspace,
|
||||
currentProject,
|
||||
refetch: refetchWorkspaceAndProject,
|
||||
} = useCurrentWorkspaceAndProject();
|
||||
const { state } = useApplicationState();
|
||||
|
||||
const { data } = useGetPaymentMethodsQuery({
|
||||
variables: {
|
||||
@@ -82,6 +86,29 @@ export function ChangePlanModalWithData({ app, plans, close }: any) {
|
||||
const currentPlan = plans.find((plan) => plan.id === app.plan.id);
|
||||
const selectedPlan = plans.find((plan) => plan.id === selectedPlanId);
|
||||
|
||||
useEffect(() => {
|
||||
if (!pollingCurrentProject || state === ApplicationStatus.Paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
close?.();
|
||||
closeAlertDialog();
|
||||
setShowPaymentModal(false);
|
||||
setPollingCurrentProject(false);
|
||||
}, [state, pollingCurrentProject, close, closeAlertDialog]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!pollingCurrentProject) {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
const interval = setInterval(() => {
|
||||
refetchWorkspaceAndProject();
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [pollingCurrentProject, refetchWorkspaceAndProject, currentProject]);
|
||||
|
||||
const [updateApp] = useUpdateApplicationMutation({
|
||||
refetchQueries: [
|
||||
refetchGetApplicationPlanQuery({
|
||||
@@ -99,6 +126,7 @@ export function ChangePlanModalWithData({ app, plans, close }: any) {
|
||||
appId: app.id,
|
||||
app: {
|
||||
planId: selectedPlan.id,
|
||||
desiredState: 5,
|
||||
},
|
||||
},
|
||||
}),
|
||||
@@ -112,11 +140,7 @@ export function ChangePlanModalWithData({ app, plans, close }: any) {
|
||||
getToastStyleProps(),
|
||||
);
|
||||
|
||||
await refetchWorkspaceAndProject();
|
||||
|
||||
close?.();
|
||||
closeAlertDialog();
|
||||
setShowPaymentModal(false);
|
||||
setPollingCurrentProject(true);
|
||||
} catch (error) {
|
||||
// Note: Error is handled by the toast.
|
||||
}
|
||||
@@ -134,12 +158,49 @@ export function ChangePlanModalWithData({ app, plans, close }: any) {
|
||||
}
|
||||
|
||||
await handleUpdateAppPlan();
|
||||
|
||||
setShowPaymentModal(false);
|
||||
close?.();
|
||||
closeAlertDialog();
|
||||
};
|
||||
|
||||
if (pollingCurrentProject) {
|
||||
return (
|
||||
<Box className="mx-auto w-full max-w-xl rounded-lg p-6 text-left">
|
||||
<div className="flex flex-col">
|
||||
<div className="mx-auto">
|
||||
<Image
|
||||
src="/assets/upgrade.svg"
|
||||
alt="Nhost Logo"
|
||||
width={72}
|
||||
height={72}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Text variant="h3" component="h2" className="mt-2 text-center">
|
||||
Successfully upgraded to {currentPlan.name}
|
||||
</Text>
|
||||
|
||||
<ActivityIndicator
|
||||
label="We are unpausing your project. This may take some time..."
|
||||
className="mx-auto mt-2"
|
||||
/>
|
||||
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
className="mx-auto mt-4 w-full max-w-sm"
|
||||
onClick={() => {
|
||||
if (close) {
|
||||
close();
|
||||
}
|
||||
|
||||
closeAlertDialog();
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
if (app.plan.id !== plans.find((plan) => plan.isFree)?.id) {
|
||||
return (
|
||||
<Box className="mx-auto w-full max-w-xl rounded-lg p-6 text-left">
|
||||
@@ -215,7 +276,7 @@ export function ChangePlanModalWithData({ app, plans, close }: any) {
|
||||
You're currently on the <strong>{app.plan.name}</strong> plan.
|
||||
</Text>
|
||||
|
||||
<div className="mt-5">
|
||||
<div className="mt-2">
|
||||
{plans
|
||||
.filter((plan) => plan.id !== app.plan.id)
|
||||
.map((plan) => (
|
||||
@@ -233,8 +294,12 @@ export function ChangePlanModalWithData({ app, plans, close }: any) {
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-6 grid grid-flow-row gap-2">
|
||||
<Button onClick={handleChangePlanClick} disabled={!selectedPlan}>
|
||||
<div className="mt-2 grid grid-flow-row gap-2">
|
||||
<Button
|
||||
onClick={handleChangePlanClick}
|
||||
disabled={!selectedPlan}
|
||||
loading={pollingCurrentProject}
|
||||
>
|
||||
Upgrade
|
||||
</Button>
|
||||
|
||||
|
||||
@@ -56,7 +56,9 @@ export default function ResetDatabasePasswordSettings() {
|
||||
const handleGenerateRandomPassword = () => {
|
||||
const newRandomDatabasePassword = generateRandomDatabasePassword();
|
||||
triggerToast('New random database password generated.');
|
||||
setValue('databasePassword', newRandomDatabasePassword);
|
||||
setValue('databasePassword', newRandomDatabasePassword, {
|
||||
shouldDirty: true,
|
||||
});
|
||||
};
|
||||
|
||||
const handleChangeDatabasePassword = async (
|
||||
|
||||
26
dashboard/src/components/ui/v2/icons/GaugeIcon/GaugeIcon.tsx
Normal file
26
dashboard/src/components/ui/v2/icons/GaugeIcon/GaugeIcon.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import type { IconProps } from '@/ui/v2/icons';
|
||||
import SvgIcon from '@/ui/v2/icons/SvgIcon';
|
||||
|
||||
function GaugeIcon(props: IconProps) {
|
||||
return (
|
||||
<SvgIcon
|
||||
width="16"
|
||||
height="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
aria-label="A gauge"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M10.757 3.295A7.25 7.25 0 0 0 8 2.75h-.026c-3.286.011-6.032 2.231-6.92 5.227a.753.753 0 0 0-.081.293 7.359 7.359 0 0 0-.223 1.8v1.43A1.25 1.25 0 0 0 2 12.75h12a1.25 1.25 0 0 0 1.25-1.25V10a7.25 7.25 0 0 0-.246-1.872l-.001-.004V8.12a7.248 7.248 0 0 0-4.246-4.825Zm-2.77 7.955h5.763V10c0-.252-.017-.503-.05-.751l-1.16.31a.75.75 0 1 1-.387-1.448l1.16-.31-.003-.006a5.751 5.751 0 0 0-4.56-3.496V5.5a.75.75 0 0 1-1.5 0V4.3c-2.053.271-3.764 1.645-4.545 3.505l1.142.306A.75.75 0 1 1 3.46 9.56L2.307 9.25a5.895 5.895 0 0 0-.057.82v1.179h3.845l4.05-5.277a.75.75 0 0 1 1.19.913L7.985 11.25Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
|
||||
GaugeIcon.displayName = 'NhostGaugeIcon';
|
||||
|
||||
export default GaugeIcon;
|
||||
1
dashboard/src/components/ui/v2/icons/GaugeIcon/index.ts
Normal file
1
dashboard/src/components/ui/v2/icons/GaugeIcon/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as GaugeIcon } from './GaugeIcon';
|
||||
@@ -10,6 +10,11 @@ fragment Project on apps {
|
||||
nhostBaseFolder
|
||||
providersUpdated
|
||||
config(resolve: true) {
|
||||
observability {
|
||||
grafana {
|
||||
adminPassword
|
||||
}
|
||||
}
|
||||
hasura {
|
||||
adminSecret
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import CloudIcon from '@/ui/v2/icons/CloudIcon';
|
||||
import CogIcon from '@/ui/v2/icons/CogIcon';
|
||||
import DatabaseIcon from '@/ui/v2/icons/DatabaseIcon';
|
||||
import FileTextIcon from '@/ui/v2/icons/FileTextIcon';
|
||||
import { GaugeIcon } from '@/ui/v2/icons/GaugeIcon';
|
||||
import GraphQLIcon from '@/ui/v2/icons/GraphQLIcon';
|
||||
import HasuraIcon from '@/ui/v2/icons/HasuraIcon';
|
||||
import HomeIcon from '@/ui/v2/icons/HomeIcon';
|
||||
@@ -77,6 +78,13 @@ export default function useProjectRoutes() {
|
||||
icon: <FileTextIcon />,
|
||||
disabled: !isPlatform,
|
||||
},
|
||||
{
|
||||
relativePath: '/metrics',
|
||||
exact: false,
|
||||
label: 'Metrics',
|
||||
icon: <GaugeIcon />,
|
||||
disabled: !isPlatform,
|
||||
},
|
||||
{
|
||||
relativeMainPath: '/settings',
|
||||
relativePath: '/settings/general',
|
||||
@@ -124,7 +132,6 @@ export default function useProjectRoutes() {
|
||||
label: 'Storage',
|
||||
icon: <StorageIcon />,
|
||||
},
|
||||
|
||||
...nhostRoutes,
|
||||
];
|
||||
|
||||
|
||||
@@ -6,52 +6,36 @@ import { useEffect } from 'react';
|
||||
* Redirects to 404 page if either currentWorkspace/currentProject resolves to undefined.
|
||||
*/
|
||||
export default function useNotFoundRedirect() {
|
||||
const { currentProject, currentWorkspace, loading } =
|
||||
useCurrentWorkspaceAndProject();
|
||||
const router = useRouter();
|
||||
const {
|
||||
query: { workspaceSlug, appSlug, updating },
|
||||
isReady,
|
||||
} = router;
|
||||
|
||||
const notIn404Already = router.pathname !== '/404';
|
||||
const noResolvedWorkspace =
|
||||
isReady && !loading && workspaceSlug && currentWorkspace === undefined;
|
||||
const noResolvedApplication =
|
||||
isReady &&
|
||||
!loading &&
|
||||
workspaceSlug &&
|
||||
appSlug &&
|
||||
currentProject === undefined;
|
||||
|
||||
const inSettingsDatabasePage = router.pathname.includes('/settings/database');
|
||||
const { currentProject, currentWorkspace, loading } =
|
||||
useCurrentWorkspaceAndProject();
|
||||
|
||||
useEffect(() => {
|
||||
// This code is checking if the URL has a query of the form `?updating=true`
|
||||
// If it does (`updating` is true) this useEffect will immediately exit without executing
|
||||
// any further statements (e.g. the page will show a loader until `updating` is false).
|
||||
// This is to prevent the user from being redirected to the 404 page while we are updating
|
||||
// either the workspace slug or application slug.
|
||||
if (updating) {
|
||||
if (
|
||||
updating ||
|
||||
!isReady ||
|
||||
loading ||
|
||||
router.pathname === '/404' ||
|
||||
(workspaceSlug && currentWorkspace && appSlug && currentProject) ||
|
||||
(workspaceSlug && currentWorkspace)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (noResolvedWorkspace && notIn404Already) {
|
||||
router.replace('/404');
|
||||
}
|
||||
|
||||
if (noResolvedApplication && notIn404Already) {
|
||||
router.replace('/404');
|
||||
}
|
||||
router.replace('/404');
|
||||
}, [
|
||||
isReady,
|
||||
updating,
|
||||
currentProject,
|
||||
currentWorkspace,
|
||||
noResolvedApplication,
|
||||
noResolvedWorkspace,
|
||||
notIn404Already,
|
||||
isReady,
|
||||
loading,
|
||||
appSlug,
|
||||
router,
|
||||
inSettingsDatabasePage,
|
||||
updating,
|
||||
workspaceSlug,
|
||||
]);
|
||||
}
|
||||
|
||||
130
dashboard/src/pages/[workspaceSlug]/[appSlug]/metrics/index.tsx
Normal file
130
dashboard/src/pages/[workspaceSlug]/[appSlug]/metrics/index.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
import { UnlockFeatureByUpgrading } from '@/components/applications/UnlockFeatureByUpgrading';
|
||||
import Container from '@/components/layout/Container';
|
||||
import ProjectLayout from '@/components/layout/ProjectLayout';
|
||||
import { useCurrentWorkspaceAndProject } from '@/hooks/v2/useCurrentWorkspaceAndProject';
|
||||
import ActivityIndicator from '@/ui/v2/ActivityIndicator';
|
||||
import Box from '@/ui/v2/Box';
|
||||
import Button from '@/ui/v2/Button/Button';
|
||||
import Divider from '@/ui/v2/Divider';
|
||||
import IconButton from '@/ui/v2/IconButton';
|
||||
import Text from '@/ui/v2/Text';
|
||||
import ArrowSquareOutIcon from '@/ui/v2/icons/ArrowSquareOutIcon';
|
||||
import CopyIcon from '@/ui/v2/icons/CopyIcon';
|
||||
import generateAppServiceUrl from '@/utils/common/generateAppServiceUrl';
|
||||
import { copy } from '@/utils/copy';
|
||||
import Image from 'next/image';
|
||||
import type { ReactElement } from 'react';
|
||||
|
||||
export default function MetricsPage() {
|
||||
const { currentProject, loading } = useCurrentWorkspaceAndProject();
|
||||
const adminPassword =
|
||||
currentProject?.config?.observability?.grafana?.adminPassword;
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Container>
|
||||
<ActivityIndicator label="Loading project..." delay={1000} />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
if (currentProject.plan.isFree) {
|
||||
return (
|
||||
<Container>
|
||||
<UnlockFeatureByUpgrading message="Unlock metrics by upgrading your project to the Pro plan." />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<div className="mx-auto w-full max-w-md px-6 py-4 text-left">
|
||||
<div className="grid grid-flow-row gap-1">
|
||||
<div className="mx-auto">
|
||||
<Image
|
||||
src="/assets/grafana.svg"
|
||||
width={72}
|
||||
height={72}
|
||||
alt="Grafana"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Text variant="h3" component="h1" className="text-center">
|
||||
Open Grafana
|
||||
</Text>
|
||||
|
||||
<Text className="text-center">
|
||||
Grafana is the observability dashboard for your project. Here you
|
||||
will be able to see various metrics about its usage and performance.
|
||||
Copy the admin password to your clipboard and enter it in the next
|
||||
screen.
|
||||
</Text>
|
||||
|
||||
<Box className="mt-6 grid grid-flow-row gap-0 border-y-1">
|
||||
<div className="grid w-full grid-cols-1 place-content-between items-center py-2 sm:grid-cols-3">
|
||||
<Text className="col-span-1 text-center font-medium sm:justify-start sm:text-left">
|
||||
Username
|
||||
</Text>
|
||||
|
||||
<div className="col-span-1 grid grid-flow-col items-center justify-center gap-2 sm:col-span-2 sm:justify-end">
|
||||
<Text color="secondary" className="text-sm">
|
||||
admin
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
<div className="grid w-full grid-cols-1 place-content-between items-center py-2 sm:grid-cols-3">
|
||||
<Text className="col-span-1 text-center font-medium sm:justify-start sm:text-left">
|
||||
Password
|
||||
</Text>
|
||||
|
||||
<div className="col-span-1 grid grid-flow-col items-center justify-center gap-2 sm:col-span-2 sm:justify-end">
|
||||
<Text className="font-medium" variant="subtitle2">
|
||||
{adminPassword
|
||||
? Array(adminPassword.length).fill('•').join('')
|
||||
: 'N/A'}
|
||||
</Text>
|
||||
|
||||
{adminPassword && (
|
||||
<IconButton
|
||||
onClick={() => copy(adminPassword, 'Grafana password')}
|
||||
variant="borderless"
|
||||
color="secondary"
|
||||
className="min-w-0 p-1"
|
||||
aria-label="Copy password"
|
||||
>
|
||||
<CopyIcon className="h-4 w-4" />
|
||||
</IconButton>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
|
||||
<div className="mt-6 grid grid-flow-row gap-2">
|
||||
<Button
|
||||
href={generateAppServiceUrl(
|
||||
currentProject.subdomain,
|
||||
currentProject.region.awsName,
|
||||
'grafana',
|
||||
)}
|
||||
// Both `target` and `rel` are available when `href` is set. This is
|
||||
// a limitation of MUI.
|
||||
// @ts-ignore
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
endIcon={<ArrowSquareOutIcon className="h-4 w-4" />}
|
||||
>
|
||||
Open Grafana
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
MetricsPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return <ProjectLayout>{page}</ProjectLayout>;
|
||||
};
|
||||
20
dashboard/src/utils/__generated__/graphql.ts
generated
20
dashboard/src/utils/__generated__/graphql.ts
generated
@@ -13091,6 +13091,7 @@ export type Query_Root = {
|
||||
/** fetch aggregated fields from the table: "cli_tokens" */
|
||||
cliTokensAggregate: CliTokens_Aggregate;
|
||||
config?: Maybe<ConfigConfig>;
|
||||
configRawJSON: Scalars['String'];
|
||||
configs: Array<ConfigAppConfig>;
|
||||
/** fetch data from the table: "continents" */
|
||||
continents: Array<Continents>;
|
||||
@@ -13614,6 +13615,12 @@ export type Query_RootConfigArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type Query_RootConfigRawJsonArgs = {
|
||||
appID: Scalars['uuid'];
|
||||
resolve: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
|
||||
export type Query_RootConfigsArgs = {
|
||||
resolve: Scalars['Boolean'];
|
||||
where?: InputMaybe<ConfigConfigComparisonExp>;
|
||||
@@ -17775,7 +17782,7 @@ export type DeleteApplicationMutation = { __typename?: 'mutation_root', deleteAp
|
||||
export type GetAllWorkspacesAndProjectsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type GetAllWorkspacesAndProjectsQuery = { __typename?: 'query_root', workspaces: Array<{ __typename?: 'workspaces', id: any, name: string, slug: string, creatorUserId?: any | null, workspaceMembers: Array<{ __typename?: 'workspaceMembers', id: any, type: string, user: { __typename?: 'users', id: any, email?: any | null, displayName: string } }>, projects: Array<{ __typename?: 'apps', id: any, slug: string, name: string, repositoryProductionBranch: string, subdomain: string, isProvisioned: boolean, createdAt: any, desiredState: number, nhostBaseFolder: string, providersUpdated?: boolean | null, config?: { __typename?: 'ConfigConfig', hasura: { __typename?: 'ConfigHasura', adminSecret: string } } | null, featureFlags: Array<{ __typename?: 'featureFlags', description: string, id: any, name: string, value: string }>, appStates: Array<{ __typename?: 'appStateHistory', id: any, appId: any, message?: string | null, stateId: number, createdAt: any }>, region: { __typename?: 'regions', id: any, countryCode: string, awsName: string, city: string }, plan: { __typename?: 'plans', id: any, name: string, price: number, isFree: boolean }, githubRepository?: { __typename?: 'githubRepositories', fullName: string } | null, deployments: Array<{ __typename?: 'deployments', id: any, commitSHA: string, commitMessage?: string | null, commitUserName?: string | null, deploymentStartedAt?: any | null, deploymentEndedAt?: any | null, commitUserAvatarUrl?: string | null, deploymentStatus?: string | null }>, creator?: { __typename?: 'users', id: any, email?: any | null, displayName: string } | null }> }> };
|
||||
export type GetAllWorkspacesAndProjectsQuery = { __typename?: 'query_root', workspaces: Array<{ __typename?: 'workspaces', id: any, name: string, slug: string, creatorUserId?: any | null, workspaceMembers: Array<{ __typename?: 'workspaceMembers', id: any, type: string, user: { __typename?: 'users', id: any, email?: any | null, displayName: string } }>, projects: Array<{ __typename?: 'apps', id: any, slug: string, name: string, repositoryProductionBranch: string, subdomain: string, isProvisioned: boolean, createdAt: any, desiredState: number, nhostBaseFolder: string, providersUpdated?: boolean | null, config?: { __typename?: 'ConfigConfig', observability?: { __typename?: 'ConfigObservability', grafana?: { __typename?: 'ConfigGrafana', adminPassword: string } | null } | null, hasura: { __typename?: 'ConfigHasura', adminSecret: string } } | null, featureFlags: Array<{ __typename?: 'featureFlags', description: string, id: any, name: string, value: string }>, appStates: Array<{ __typename?: 'appStateHistory', id: any, appId: any, message?: string | null, stateId: number, createdAt: any }>, region: { __typename?: 'regions', id: any, countryCode: string, awsName: string, city: string }, plan: { __typename?: 'plans', id: any, name: string, price: number, isFree: boolean }, githubRepository?: { __typename?: 'githubRepositories', fullName: string } | null, deployments: Array<{ __typename?: 'deployments', id: any, commitSHA: string, commitMessage?: string | null, commitUserName?: string | null, deploymentStartedAt?: any | null, deploymentEndedAt?: any | null, commitUserAvatarUrl?: string | null, deploymentStatus?: string | null }>, creator?: { __typename?: 'users', id: any, email?: any | null, displayName: string } | null }> }> };
|
||||
|
||||
export type GetAppPlanAndGlobalPlansAppFragment = { __typename?: 'apps', id: any, subdomain: string, workspace: { __typename?: 'workspaces', id: any, paymentMethods: Array<{ __typename?: 'paymentMethods', id: any }> }, plan: { __typename?: 'plans', id: any, name: string } };
|
||||
|
||||
@@ -17832,7 +17839,7 @@ export type GetWorkspaceAndProjectQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type GetWorkspaceAndProjectQuery = { __typename?: 'query_root', workspaces: Array<{ __typename?: 'workspaces', id: any, name: string, slug: string, creatorUserId?: any | null, workspaceMembers: Array<{ __typename?: 'workspaceMembers', id: any, type: string, user: { __typename?: 'users', id: any, email?: any | null, displayName: string } }>, projects: Array<{ __typename?: 'apps', id: any, slug: string, name: string, repositoryProductionBranch: string, subdomain: string, isProvisioned: boolean, createdAt: any, desiredState: number, nhostBaseFolder: string, providersUpdated?: boolean | null, config?: { __typename?: 'ConfigConfig', hasura: { __typename?: 'ConfigHasura', adminSecret: string } } | null, featureFlags: Array<{ __typename?: 'featureFlags', description: string, id: any, name: string, value: string }>, appStates: Array<{ __typename?: 'appStateHistory', id: any, appId: any, message?: string | null, stateId: number, createdAt: any }>, region: { __typename?: 'regions', id: any, countryCode: string, awsName: string, city: string }, plan: { __typename?: 'plans', id: any, name: string, price: number, isFree: boolean }, githubRepository?: { __typename?: 'githubRepositories', fullName: string } | null, deployments: Array<{ __typename?: 'deployments', id: any, commitSHA: string, commitMessage?: string | null, commitUserName?: string | null, deploymentStartedAt?: any | null, deploymentEndedAt?: any | null, commitUserAvatarUrl?: string | null, deploymentStatus?: string | null }>, creator?: { __typename?: 'users', id: any, email?: any | null, displayName: string } | null }> }> };
|
||||
export type GetWorkspaceAndProjectQuery = { __typename?: 'query_root', workspaces: Array<{ __typename?: 'workspaces', id: any, name: string, slug: string, creatorUserId?: any | null, workspaceMembers: Array<{ __typename?: 'workspaceMembers', id: any, type: string, user: { __typename?: 'users', id: any, email?: any | null, displayName: string } }>, projects: Array<{ __typename?: 'apps', id: any, slug: string, name: string, repositoryProductionBranch: string, subdomain: string, isProvisioned: boolean, createdAt: any, desiredState: number, nhostBaseFolder: string, providersUpdated?: boolean | null, config?: { __typename?: 'ConfigConfig', observability?: { __typename?: 'ConfigObservability', grafana?: { __typename?: 'ConfigGrafana', adminPassword: string } | null } | null, hasura: { __typename?: 'ConfigHasura', adminSecret: string } } | null, featureFlags: Array<{ __typename?: 'featureFlags', description: string, id: any, name: string, value: string }>, appStates: Array<{ __typename?: 'appStateHistory', id: any, appId: any, message?: string | null, stateId: number, createdAt: any }>, region: { __typename?: 'regions', id: any, countryCode: string, awsName: string, city: string }, plan: { __typename?: 'plans', id: any, name: string, price: number, isFree: boolean }, githubRepository?: { __typename?: 'githubRepositories', fullName: string } | null, deployments: Array<{ __typename?: 'deployments', id: any, commitSHA: string, commitMessage?: string | null, commitUserName?: string | null, deploymentStartedAt?: any | null, deploymentEndedAt?: any | null, commitUserAvatarUrl?: string | null, deploymentStatus?: string | null }>, creator?: { __typename?: 'users', id: any, email?: any | null, displayName: string } | null }> }> };
|
||||
|
||||
export type InsertApplicationMutationVariables = Exact<{
|
||||
app: Apps_Insert_Input;
|
||||
@@ -18039,9 +18046,9 @@ export type GetFilesAggregateQueryVariables = Exact<{
|
||||
|
||||
export type GetFilesAggregateQuery = { __typename?: 'query_root', filesAggregate: { __typename?: 'files_aggregate', aggregate?: { __typename?: 'files_aggregate_fields', count: number } | null } };
|
||||
|
||||
export type ProjectFragment = { __typename?: 'apps', id: any, slug: string, name: string, repositoryProductionBranch: string, subdomain: string, isProvisioned: boolean, createdAt: any, desiredState: number, nhostBaseFolder: string, providersUpdated?: boolean | null, config?: { __typename?: 'ConfigConfig', hasura: { __typename?: 'ConfigHasura', adminSecret: string } } | null, featureFlags: Array<{ __typename?: 'featureFlags', description: string, id: any, name: string, value: string }>, appStates: Array<{ __typename?: 'appStateHistory', id: any, appId: any, message?: string | null, stateId: number, createdAt: any }>, region: { __typename?: 'regions', id: any, countryCode: string, awsName: string, city: string }, plan: { __typename?: 'plans', id: any, name: string, price: number, isFree: boolean }, githubRepository?: { __typename?: 'githubRepositories', fullName: string } | null, deployments: Array<{ __typename?: 'deployments', id: any, commitSHA: string, commitMessage?: string | null, commitUserName?: string | null, deploymentStartedAt?: any | null, deploymentEndedAt?: any | null, commitUserAvatarUrl?: string | null, deploymentStatus?: string | null }>, creator?: { __typename?: 'users', id: any, email?: any | null, displayName: string } | null };
|
||||
export type ProjectFragment = { __typename?: 'apps', id: any, slug: string, name: string, repositoryProductionBranch: string, subdomain: string, isProvisioned: boolean, createdAt: any, desiredState: number, nhostBaseFolder: string, providersUpdated?: boolean | null, config?: { __typename?: 'ConfigConfig', observability?: { __typename?: 'ConfigObservability', grafana?: { __typename?: 'ConfigGrafana', adminPassword: string } | null } | null, hasura: { __typename?: 'ConfigHasura', adminSecret: string } } | null, featureFlags: Array<{ __typename?: 'featureFlags', description: string, id: any, name: string, value: string }>, appStates: Array<{ __typename?: 'appStateHistory', id: any, appId: any, message?: string | null, stateId: number, createdAt: any }>, region: { __typename?: 'regions', id: any, countryCode: string, awsName: string, city: string }, plan: { __typename?: 'plans', id: any, name: string, price: number, isFree: boolean }, githubRepository?: { __typename?: 'githubRepositories', fullName: string } | null, deployments: Array<{ __typename?: 'deployments', id: any, commitSHA: string, commitMessage?: string | null, commitUserName?: string | null, deploymentStartedAt?: any | null, deploymentEndedAt?: any | null, commitUserAvatarUrl?: string | null, deploymentStatus?: string | null }>, creator?: { __typename?: 'users', id: any, email?: any | null, displayName: string } | null };
|
||||
|
||||
export type WorkspaceFragment = { __typename?: 'workspaces', id: any, name: string, slug: string, creatorUserId?: any | null, workspaceMembers: Array<{ __typename?: 'workspaceMembers', id: any, type: string, user: { __typename?: 'users', id: any, email?: any | null, displayName: string } }>, projects: Array<{ __typename?: 'apps', id: any, slug: string, name: string, repositoryProductionBranch: string, subdomain: string, isProvisioned: boolean, createdAt: any, desiredState: number, nhostBaseFolder: string, providersUpdated?: boolean | null, config?: { __typename?: 'ConfigConfig', hasura: { __typename?: 'ConfigHasura', adminSecret: string } } | null, featureFlags: Array<{ __typename?: 'featureFlags', description: string, id: any, name: string, value: string }>, appStates: Array<{ __typename?: 'appStateHistory', id: any, appId: any, message?: string | null, stateId: number, createdAt: any }>, region: { __typename?: 'regions', id: any, countryCode: string, awsName: string, city: string }, plan: { __typename?: 'plans', id: any, name: string, price: number, isFree: boolean }, githubRepository?: { __typename?: 'githubRepositories', fullName: string } | null, deployments: Array<{ __typename?: 'deployments', id: any, commitSHA: string, commitMessage?: string | null, commitUserName?: string | null, deploymentStartedAt?: any | null, deploymentEndedAt?: any | null, commitUserAvatarUrl?: string | null, deploymentStatus?: string | null }>, creator?: { __typename?: 'users', id: any, email?: any | null, displayName: string } | null }> };
|
||||
export type WorkspaceFragment = { __typename?: 'workspaces', id: any, name: string, slug: string, creatorUserId?: any | null, workspaceMembers: Array<{ __typename?: 'workspaceMembers', id: any, type: string, user: { __typename?: 'users', id: any, email?: any | null, displayName: string } }>, projects: Array<{ __typename?: 'apps', id: any, slug: string, name: string, repositoryProductionBranch: string, subdomain: string, isProvisioned: boolean, createdAt: any, desiredState: number, nhostBaseFolder: string, providersUpdated?: boolean | null, config?: { __typename?: 'ConfigConfig', observability?: { __typename?: 'ConfigObservability', grafana?: { __typename?: 'ConfigGrafana', adminPassword: string } | null } | null, hasura: { __typename?: 'ConfigHasura', adminSecret: string } } | null, featureFlags: Array<{ __typename?: 'featureFlags', description: string, id: any, name: string, value: string }>, appStates: Array<{ __typename?: 'appStateHistory', id: any, appId: any, message?: string | null, stateId: number, createdAt: any }>, region: { __typename?: 'regions', id: any, countryCode: string, awsName: string, city: string }, plan: { __typename?: 'plans', id: any, name: string, price: number, isFree: boolean }, githubRepository?: { __typename?: 'githubRepositories', fullName: string } | null, deployments: Array<{ __typename?: 'deployments', id: any, commitSHA: string, commitMessage?: string | null, commitUserName?: string | null, deploymentStartedAt?: any | null, deploymentEndedAt?: any | null, commitUserAvatarUrl?: string | null, deploymentStatus?: string | null }>, creator?: { __typename?: 'users', id: any, email?: any | null, displayName: string } | null }> };
|
||||
|
||||
export type GithubRepositoryFragment = { __typename?: 'githubRepositories', id: any, name: string, fullName: string, private: boolean, githubAppInstallation: { __typename?: 'githubAppInstallations', id: any, accountLogin?: string | null, accountType?: string | null, accountAvatarUrl?: string | null } };
|
||||
|
||||
@@ -18452,6 +18459,11 @@ export const ProjectFragmentDoc = gql`
|
||||
nhostBaseFolder
|
||||
providersUpdated
|
||||
config(resolve: true) {
|
||||
observability {
|
||||
grafana {
|
||||
adminPassword
|
||||
}
|
||||
}
|
||||
hasura {
|
||||
adminSecret
|
||||
}
|
||||
|
||||
@@ -52,6 +52,10 @@ test('should generate a per service subdomain in remote mode', () => {
|
||||
expect(generateAppServiceUrl('test', 'eu-west-1', 'hasura')).toBe(
|
||||
'https://test.hasura.eu-west-1.nhost.run',
|
||||
);
|
||||
|
||||
expect(generateAppServiceUrl('test', 'eu-west-1', 'grafana')).toBe(
|
||||
'https://test.grafana.eu-west-1.nhost.run',
|
||||
);
|
||||
});
|
||||
|
||||
test('should generate staging subdomains in staging environment', () => {
|
||||
@@ -77,9 +81,13 @@ test('should generate staging subdomains in staging environment', () => {
|
||||
expect(generateAppServiceUrl('test', 'eu-west-1', 'hasura')).toBe(
|
||||
'https://test.hasura.eu-west-1.staging.nhost.run',
|
||||
);
|
||||
|
||||
expect(generateAppServiceUrl('test', 'eu-west-1', 'grafana')).toBe(
|
||||
'https://test.grafana.eu-west-1.staging.nhost.run',
|
||||
);
|
||||
});
|
||||
|
||||
test('should generate no slug for Hasura neither in local mode nor in remote mode', () => {
|
||||
test('should generate no slug for Hasura and Grafana neither in local mode nor in remote mode', () => {
|
||||
process.env.NEXT_PUBLIC_NHOST_HASURA_API_URL = 'http://localhost:8082';
|
||||
|
||||
expect(generateAppServiceUrl('test', 'eu-west-1', 'hasura')).toBe(
|
||||
@@ -92,12 +100,18 @@ test('should generate no slug for Hasura neither in local mode nor in remote mod
|
||||
expect(generateAppServiceUrl('test', 'eu-west-1', 'hasura')).toBe(
|
||||
'https://test.hasura.eu-west-1.staging.nhost.run',
|
||||
);
|
||||
expect(generateAppServiceUrl('test', 'eu-west-1', 'grafana')).toBe(
|
||||
'https://test.grafana.eu-west-1.staging.nhost.run',
|
||||
);
|
||||
|
||||
process.env.NEXT_PUBLIC_ENV = 'production';
|
||||
|
||||
expect(generateAppServiceUrl('test', 'eu-west-1', 'hasura')).toBe(
|
||||
'https://test.hasura.eu-west-1.nhost.run',
|
||||
);
|
||||
expect(generateAppServiceUrl('test', 'eu-west-1', 'grafana')).toBe(
|
||||
'https://test.grafana.eu-west-1.nhost.run',
|
||||
);
|
||||
});
|
||||
|
||||
test('should be able to override the default remote backend slugs', () => {
|
||||
|
||||
@@ -12,7 +12,8 @@ export type NhostService =
|
||||
| 'graphql'
|
||||
| 'functions'
|
||||
| 'storage'
|
||||
| 'hasura';
|
||||
| 'hasura'
|
||||
| 'grafana';
|
||||
|
||||
/**
|
||||
* The default slugs that are used when running the dashboard locally. These
|
||||
@@ -25,6 +26,7 @@ export const defaultLocalBackendSlugs: Record<NhostService, string> = {
|
||||
functions: '/v1/functions',
|
||||
storage: '/v1/files',
|
||||
hasura: '',
|
||||
grafana: '',
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -37,6 +39,7 @@ export const defaultRemoteBackendSlugs: Record<NhostService, string> = {
|
||||
functions: '/v1',
|
||||
storage: '/v1',
|
||||
hasura: '',
|
||||
grafana: '',
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -53,7 +56,7 @@ export const defaultRemoteBackendSlugs: Record<NhostService, string> = {
|
||||
export default function generateAppServiceUrl(
|
||||
subdomain: string,
|
||||
region: string,
|
||||
service: 'auth' | 'graphql' | 'functions' | 'storage' | 'hasura',
|
||||
service: 'auth' | 'graphql' | 'functions' | 'storage' | 'hasura' | 'grafana',
|
||||
localBackendSlugs = defaultLocalBackendSlugs,
|
||||
remoteBackendSlugs = defaultRemoteBackendSlugs,
|
||||
) {
|
||||
@@ -66,6 +69,7 @@ export default function generateAppServiceUrl(
|
||||
storage: getStorageServiceUrl(),
|
||||
functions: getFunctionsServiceUrl(),
|
||||
hasura: getHasuraApiUrl(),
|
||||
grafana: '',
|
||||
};
|
||||
|
||||
if (!serviceUrls[service]) {
|
||||
|
||||
@@ -6,7 +6,7 @@ export default defineConfig({
|
||||
// @ts-ignore
|
||||
plugins: [tsconfigPaths({ projects: ['./tsconfig.test.json'] }), react()],
|
||||
test: {
|
||||
testTimeout: 20000,
|
||||
testTimeout: 30000,
|
||||
environment: 'jsdom',
|
||||
globals: true,
|
||||
setupFiles: 'src/setupTests.ts',
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/docs
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- fe341519: Add section on Metrics to the docs
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -7,7 +7,7 @@ image: /img/og/platform/compute-resources.png
|
||||
Compute resources are the fundamental units that represent the processing power and memory available to your Nhost projects. The primary compute resources are vCPU and RAM. This documentation outlines the key aspects of compute resources in the context of the Nhost Cloud Platform.
|
||||
|
||||
|
||||
## Shared vs Dedicated Compute
|
||||
### Shared vs Dedicated Compute
|
||||
|
||||
Free Projects are given a total of 2 shared vCPUs and 1 GiB of RAM:
|
||||
|
||||
|
||||
34
docs/docs/platform/metrics.mdx
Normal file
34
docs/docs/platform/metrics.mdx
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
title: 'Metrics (beta)'
|
||||
sidebar_position: 1
|
||||
image: /img/og/platform/metrics.png
|
||||
---
|
||||
|
||||
Metrics provide insights into your Nhost projects by integrating a managed Grafana instance tailored to them. This feature is available on the Pro plan and allows you to analyze your project's performance, identify potential bottlenecks, and optimize your application.
|
||||
|
||||
### Available Dashboards
|
||||
|
||||
Nhost Metrics includes pre-configured dashboards with the following metrics:
|
||||
|
||||
- vCPU/memory usage by Service replica for all services
|
||||
- Throttling time / percentage
|
||||
- Postgres volume usage
|
||||
- Networking
|
||||
|
||||

|
||||
|
||||
### Accessing Metrics
|
||||
|
||||
Metrics can be found in your project's dashboard.
|
||||
|
||||

|
||||
|
||||
### Limitations (Beta)
|
||||
|
||||
Please note that while Metrics is in beta, its functionality and pricing might change.
|
||||
|
||||
- Users cannot save or use custom dashboards in the current beta version.
|
||||
- Additional categories of metrics like application and database metrics will be added in future updates.
|
||||
- Future updates will centralize logs using Loki and integrate alerts directly into the Grafana dashboard.
|
||||
|
||||
Using Nhost Metrics allows you to identify bottlenecks in your applications, which you can then fix by leveraging [Compute Resources](https://docs.nhost.io/platform/compute) and [Service Replicas](https://docs.nhost.io/platform/service-replicas) to address these performance issues.
|
||||
@@ -10,7 +10,7 @@ Service Replicas is a feature that allows you to create multiple replicas of you
|
||||
|
||||
To read the announcement, check out our [blog post](https://nhost.io/blog/service-replicas).
|
||||
|
||||
## Supported Services
|
||||
### Supported Services
|
||||
|
||||
Replicas can be configured for the following services:
|
||||
|
||||
@@ -20,7 +20,7 @@ Replicas can be configured for the following services:
|
||||
|
||||
Currently, we don't support replicas for Postgres.
|
||||
|
||||
## Configuring Service Replicas
|
||||
### Configuring Service Replicas
|
||||
|
||||
To configure Service Replicas for your project, follow these steps:
|
||||
|
||||
@@ -32,13 +32,13 @@ To configure Service Replicas for your project, follow these steps:
|
||||
|
||||
Please note that when setting multiple replicas for a service, the 1:2 ratio between CPU and RAM for that service has to be respected. With only one replica, this ratio does not need to be respected at the service level.
|
||||
|
||||
## Benefits
|
||||
### Benefits
|
||||
|
||||
- Improved fault tolerance: Multiple replicas ensure that if one instance crashes duo to an unexpected issue, the other replicas can continue to serve user requests.
|
||||
- Improved availability: Distributing user requests among multiple replicas allows your apps to handle more traffic and maintain a high level of performance.
|
||||
- Load balancing: Distributing workloads evenly among replicas to prevent bottlenecks and ensure smooth performance during peak times.
|
||||
|
||||
## Pricing
|
||||
### Pricing
|
||||
|
||||
Pricing is based on the size of each replica and the total number of replicas you have configured for each service:
|
||||
|
||||
@@ -47,7 +47,7 @@ Pricing is based on the size of each replica and the total number of replicas yo
|
||||
|
||||
Please note that Service Replicas is available only for projects on the Pro plan or higher.
|
||||
|
||||
## Caveats
|
||||
### Caveats
|
||||
|
||||
- Postgres replication: As mentioned earlier, we do not have support for multiple replicas of Postgres. This feature may be added in the future.
|
||||
- Resource ratio: When configuring multiple replicas for a service, you must adhere to the 1:2 ratio between CPU and RAM for that service.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/docs",
|
||||
"version": "0.1.1",
|
||||
"version": "0.2.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
|
||||
BIN
docs/static/img/platform/metrics/grafana.png
vendored
Normal file
BIN
docs/static/img/platform/metrics/grafana.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 368 KiB |
BIN
docs/static/img/platform/metrics/nhost-dashboard-metrics.png
vendored
Normal file
BIN
docs/static/img/platform/metrics/nhost-dashboard-metrics.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 182 KiB |
170
pnpm-lock.yaml
generated
170
pnpm-lock.yaml
generated
@@ -160,7 +160,7 @@ importers:
|
||||
graphql-request: ^6.0.0
|
||||
graphql-tag: ^2.12.6
|
||||
graphql-ws: ^5.11.2
|
||||
jsdom: ^21.0.0
|
||||
jsdom: ^22.0.0
|
||||
just-kebab-case: ^4.1.1
|
||||
lint-staged: '>=13'
|
||||
lodash.debounce: ^4.0.8
|
||||
@@ -315,7 +315,7 @@ importers:
|
||||
eslint-plugin-jsx-a11y: 6.6.1_eslint@8.28.0
|
||||
eslint-plugin-react: 7.31.11_eslint@8.28.0
|
||||
eslint-plugin-react-hooks: 4.6.0_eslint@8.28.0
|
||||
jsdom: 21.0.0
|
||||
jsdom: 22.0.0
|
||||
lint-staged: 13.0.3
|
||||
msw: 1.0.1_encoding@0.1.13
|
||||
msw-storybook-addon: 1.6.3_wfed36xf2cj7dcilohayxz5mxm
|
||||
@@ -333,7 +333,7 @@ importers:
|
||||
tsconfig-paths-webpack-plugin: 4.0.0
|
||||
vite: 4.0.4_@types+node@16.18.11
|
||||
vite-tsconfig-paths: 4.0.3_vite@4.0.4
|
||||
vitest: 0.30.1_jsdom@21.0.0
|
||||
vitest: 0.30.1_jsdom@22.0.0
|
||||
webpack: 5.75.0
|
||||
|
||||
docs:
|
||||
@@ -5619,7 +5619,6 @@ packages:
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.9
|
||||
dev: true
|
||||
|
||||
/@date-io/core/2.16.0:
|
||||
resolution: {integrity: sha512-DYmSzkr+jToahwWrsiRA2/pzMEtz9Bq1euJwoOuYwuwIYXnZFtHajY2E6a1VNVDc9jP8YUXK1BvnZH9mmT19Zg==}
|
||||
@@ -8940,11 +8939,11 @@ packages:
|
||||
extract-files: 11.0.0
|
||||
graphql: 16.6.0
|
||||
graphql-ws: 5.11.3_graphql@16.6.0
|
||||
isomorphic-ws: 5.0.0_ws@8.12.1
|
||||
isomorphic-ws: 5.0.0_ws@8.13.0
|
||||
meros: 1.2.1_@types+node@16.18.11
|
||||
tslib: 2.5.0
|
||||
value-or-promise: 1.0.12
|
||||
ws: 8.12.1
|
||||
ws: 8.13.0
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- bufferutil
|
||||
@@ -9051,10 +9050,10 @@ packages:
|
||||
'@types/ws': 8.5.3
|
||||
'@whatwg-node/fetch': 0.8.1_@types+node@16.18.11
|
||||
graphql: 16.6.0
|
||||
isomorphic-ws: 5.0.0_ws@8.12.1
|
||||
isomorphic-ws: 5.0.0_ws@8.13.0
|
||||
tslib: 2.5.0
|
||||
value-or-promise: 1.0.12
|
||||
ws: 8.12.1
|
||||
ws: 8.13.0
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- bufferutil
|
||||
@@ -9544,7 +9543,6 @@ packages:
|
||||
dependencies:
|
||||
'@jridgewell/resolve-uri': 3.1.0
|
||||
'@jridgewell/sourcemap-codec': 1.4.14
|
||||
dev: true
|
||||
|
||||
/@leichtgewicht/ip-codec/2.0.3:
|
||||
resolution: {integrity: sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==}
|
||||
@@ -12049,7 +12047,7 @@ packages:
|
||||
util-deprecate: 1.0.2
|
||||
watchpack: 2.4.0
|
||||
webpack: 4.46.0
|
||||
ws: 8.12.1
|
||||
ws: 8.13.0
|
||||
x-default-browser: 0.4.0
|
||||
transitivePeerDependencies:
|
||||
- '@storybook/mdx2-csf'
|
||||
@@ -13045,7 +13043,7 @@ packages:
|
||||
tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1'
|
||||
dependencies:
|
||||
mini-svg-data-uri: 1.4.4
|
||||
tailwindcss: 3.2.1_postcss@8.4.20
|
||||
tailwindcss: 3.2.1_v776zzvn44o7tpgzieipaairwm
|
||||
|
||||
/@tailwindcss/forms/0.5.3_tailwindcss@3.2.4:
|
||||
resolution: {integrity: sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==}
|
||||
@@ -13254,19 +13252,15 @@ packages:
|
||||
|
||||
/@tsconfig/node10/1.0.8:
|
||||
resolution: {integrity: sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==}
|
||||
dev: true
|
||||
|
||||
/@tsconfig/node12/1.0.9:
|
||||
resolution: {integrity: sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==}
|
||||
dev: true
|
||||
|
||||
/@tsconfig/node14/1.0.1:
|
||||
resolution: {integrity: sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==}
|
||||
dev: true
|
||||
|
||||
/@tsconfig/node16/1.0.2:
|
||||
resolution: {integrity: sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==}
|
||||
dev: true
|
||||
|
||||
/@types/argparse/1.0.38:
|
||||
resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==}
|
||||
@@ -14560,7 +14554,7 @@ packages:
|
||||
c8: 7.13.0
|
||||
picocolors: 1.0.0
|
||||
std-env: 3.3.2
|
||||
vitest: 0.30.1_jsdom@21.0.0
|
||||
vitest: 0.30.1_jsdom@22.0.0
|
||||
dev: true
|
||||
|
||||
/@vitest/expect/0.30.0:
|
||||
@@ -15503,13 +15497,6 @@ packages:
|
||||
acorn-walk: 7.2.0
|
||||
dev: true
|
||||
|
||||
/acorn-globals/7.0.1:
|
||||
resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==}
|
||||
dependencies:
|
||||
acorn: 8.8.2
|
||||
acorn-walk: 8.2.0
|
||||
dev: true
|
||||
|
||||
/acorn-import-assertions/1.8.0_acorn@8.8.1:
|
||||
resolution: {integrity: sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==}
|
||||
peerDependencies:
|
||||
@@ -15562,7 +15549,6 @@ packages:
|
||||
resolution: {integrity: sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/acorn/8.8.1:
|
||||
resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==}
|
||||
@@ -15816,7 +15802,6 @@ packages:
|
||||
|
||||
/arg/4.1.3:
|
||||
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
|
||||
dev: true
|
||||
|
||||
/arg/5.0.2:
|
||||
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
|
||||
@@ -17962,7 +17947,6 @@ packages:
|
||||
|
||||
/create-require/1.1.1:
|
||||
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
|
||||
dev: true
|
||||
|
||||
/cross-fetch/3.1.5:
|
||||
resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==}
|
||||
@@ -18297,6 +18281,13 @@ packages:
|
||||
cssom: 0.3.8
|
||||
dev: true
|
||||
|
||||
/cssstyle/3.0.0:
|
||||
resolution: {integrity: sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
rrweb-cssom: 0.6.0
|
||||
dev: true
|
||||
|
||||
/csstype/2.6.21:
|
||||
resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==}
|
||||
|
||||
@@ -18667,13 +18658,13 @@ packages:
|
||||
whatwg-url: 10.0.0
|
||||
dev: true
|
||||
|
||||
/data-urls/3.0.2:
|
||||
resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==}
|
||||
engines: {node: '>=12'}
|
||||
/data-urls/4.0.0:
|
||||
resolution: {integrity: sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
abab: 2.0.6
|
||||
whatwg-mimetype: 3.0.0
|
||||
whatwg-url: 11.0.0
|
||||
whatwg-url: 12.0.1
|
||||
dev: true
|
||||
|
||||
/dataloader/2.1.0:
|
||||
@@ -18748,8 +18739,8 @@ packages:
|
||||
resolution: {integrity: sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==}
|
||||
dev: true
|
||||
|
||||
/decimal.js/10.4.2:
|
||||
resolution: {integrity: sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==}
|
||||
/decimal.js/10.4.3:
|
||||
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
|
||||
dev: true
|
||||
|
||||
/decode-uri-component/0.2.0:
|
||||
@@ -19011,7 +19002,6 @@ packages:
|
||||
/diff/4.0.2:
|
||||
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
|
||||
engines: {node: '>=0.3.1'}
|
||||
dev: true
|
||||
|
||||
/diffie-hellman/5.0.3:
|
||||
resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==}
|
||||
@@ -23630,6 +23620,14 @@ packages:
|
||||
ws: 8.12.1
|
||||
dev: true
|
||||
|
||||
/isomorphic-ws/5.0.0_ws@8.13.0:
|
||||
resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==}
|
||||
peerDependencies:
|
||||
ws: '*'
|
||||
dependencies:
|
||||
ws: 8.13.0
|
||||
dev: true
|
||||
|
||||
/istanbul-lib-coverage/3.2.0:
|
||||
resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -23941,9 +23939,9 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/jsdom/21.0.0:
|
||||
resolution: {integrity: sha512-AIw+3ZakSUtDYvhwPwWHiZsUi3zHugpMEKlNPaurviseYoBqo0zBd3zqoUi3LPCNtPFlEP8FiW9MqCZdjb2IYA==}
|
||||
engines: {node: '>=14'}
|
||||
/jsdom/22.0.0:
|
||||
resolution: {integrity: sha512-p5ZTEb5h+O+iU02t0GfEjAnkdYPrQSkfuTSMkMYyIoMvUNEHsbG0bHHbfXIcfTqD2UfvjQX7mmgiFsyRwGscVw==}
|
||||
engines: {node: '>=16'}
|
||||
peerDependencies:
|
||||
canvas: ^2.5.0
|
||||
peerDependenciesMeta:
|
||||
@@ -23951,21 +23949,18 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
abab: 2.0.6
|
||||
acorn: 8.8.1
|
||||
acorn-globals: 7.0.1
|
||||
cssom: 0.5.0
|
||||
cssstyle: 2.3.0
|
||||
data-urls: 3.0.2
|
||||
decimal.js: 10.4.2
|
||||
cssstyle: 3.0.0
|
||||
data-urls: 4.0.0
|
||||
decimal.js: 10.4.3
|
||||
domexception: 4.0.0
|
||||
escodegen: 2.0.0
|
||||
form-data: 4.0.0
|
||||
html-encoding-sniffer: 3.0.0
|
||||
http-proxy-agent: 5.0.0
|
||||
https-proxy-agent: 5.0.1
|
||||
is-potential-custom-element-name: 1.0.1
|
||||
nwsapi: 2.2.2
|
||||
parse5: 7.1.1
|
||||
nwsapi: 2.2.4
|
||||
parse5: 7.1.2
|
||||
rrweb-cssom: 0.6.0
|
||||
saxes: 6.0.0
|
||||
symbol-tree: 3.2.4
|
||||
tough-cookie: 4.1.2
|
||||
@@ -23973,8 +23968,8 @@ packages:
|
||||
webidl-conversions: 7.0.0
|
||||
whatwg-encoding: 2.0.0
|
||||
whatwg-mimetype: 3.0.0
|
||||
whatwg-url: 11.0.0
|
||||
ws: 8.11.0
|
||||
whatwg-url: 12.0.1
|
||||
ws: 8.13.0
|
||||
xml-name-validator: 4.0.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
@@ -24678,7 +24673,6 @@ packages:
|
||||
|
||||
/make-error/1.3.6:
|
||||
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
|
||||
dev: true
|
||||
|
||||
/makeerror/1.0.12:
|
||||
resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
|
||||
@@ -25830,8 +25824,8 @@ packages:
|
||||
resolution: {integrity: sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==}
|
||||
dev: true
|
||||
|
||||
/nwsapi/2.2.2:
|
||||
resolution: {integrity: sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==}
|
||||
/nwsapi/2.2.4:
|
||||
resolution: {integrity: sha512-NHj4rzRo0tQdijE9ZqAx6kYDcoRwYwSYzCA8MY3JzfxlrvEU0jhnhJT9BhqhJs7I/dKcrDm6TyulaRqZPIhN5g==}
|
||||
dev: true
|
||||
|
||||
/object-assign/4.1.1:
|
||||
@@ -26329,6 +26323,12 @@ packages:
|
||||
dependencies:
|
||||
entities: 4.4.0
|
||||
|
||||
/parse5/7.1.2:
|
||||
resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==}
|
||||
dependencies:
|
||||
entities: 4.4.0
|
||||
dev: true
|
||||
|
||||
/parseurl/1.3.3:
|
||||
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@@ -26747,7 +26747,6 @@ packages:
|
||||
postcss-value-parser: 4.2.0
|
||||
read-cache: 1.0.0
|
||||
resolve: 1.22.1
|
||||
dev: true
|
||||
|
||||
/postcss-import/14.1.0_postcss@8.4.20:
|
||||
resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==}
|
||||
@@ -26759,6 +26758,7 @@ packages:
|
||||
postcss-value-parser: 4.2.0
|
||||
read-cache: 1.0.0
|
||||
resolve: 1.22.1
|
||||
dev: true
|
||||
|
||||
/postcss-js/4.0.0_postcss@8.4.18:
|
||||
resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==}
|
||||
@@ -26778,7 +26778,6 @@ packages:
|
||||
dependencies:
|
||||
camelcase-css: 2.0.1
|
||||
postcss: 8.4.19
|
||||
dev: true
|
||||
|
||||
/postcss-js/4.0.0_postcss@8.4.20:
|
||||
resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==}
|
||||
@@ -26788,6 +26787,7 @@ packages:
|
||||
dependencies:
|
||||
camelcase-css: 2.0.1
|
||||
postcss: 8.4.20
|
||||
dev: true
|
||||
|
||||
/postcss-load-config/3.1.4_postcss@8.4.18:
|
||||
resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
|
||||
@@ -26821,6 +26821,7 @@ packages:
|
||||
lilconfig: 2.0.6
|
||||
postcss: 8.4.20
|
||||
yaml: 1.10.2
|
||||
dev: true
|
||||
|
||||
/postcss-load-config/3.1.4_v776zzvn44o7tpgzieipaairwm:
|
||||
resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
|
||||
@@ -26838,7 +26839,6 @@ packages:
|
||||
postcss: 8.4.19
|
||||
ts-node: 10.9.1_@types+node@16.18.11
|
||||
yaml: 1.10.2
|
||||
dev: true
|
||||
|
||||
/postcss-loader/4.3.0_gzaxsinx64nntyd3vmdqwl7coe:
|
||||
resolution: {integrity: sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==}
|
||||
@@ -27052,7 +27052,6 @@ packages:
|
||||
dependencies:
|
||||
postcss: 8.4.19
|
||||
postcss-selector-parser: 6.0.10
|
||||
dev: true
|
||||
|
||||
/postcss-nested/6.0.0_postcss@8.4.20:
|
||||
resolution: {integrity: sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==}
|
||||
@@ -27062,6 +27061,7 @@ packages:
|
||||
dependencies:
|
||||
postcss: 8.4.20
|
||||
postcss-selector-parser: 6.0.10
|
||||
dev: true
|
||||
|
||||
/postcss-normalize-charset/5.1.0_postcss@8.4.21:
|
||||
resolution: {integrity: sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==}
|
||||
@@ -27278,7 +27278,6 @@ packages:
|
||||
nanoid: 3.3.4
|
||||
picocolors: 1.0.0
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/postcss/8.4.20:
|
||||
resolution: {integrity: sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==}
|
||||
@@ -27638,6 +27637,11 @@ packages:
|
||||
/punycode/2.1.1:
|
||||
resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/punycode/2.3.0:
|
||||
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
/pupa/2.1.1:
|
||||
resolution: {integrity: sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==}
|
||||
@@ -28820,6 +28824,10 @@ packages:
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
|
||||
/rrweb-cssom/0.6.0:
|
||||
resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
|
||||
dev: true
|
||||
|
||||
/rsvp/4.8.5:
|
||||
resolution: {integrity: sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==}
|
||||
engines: {node: 6.* || >= 7.*}
|
||||
@@ -30202,6 +30210,7 @@ packages:
|
||||
resolve: 1.22.1
|
||||
transitivePeerDependencies:
|
||||
- ts-node
|
||||
dev: true
|
||||
|
||||
/tailwindcss/3.2.1_v776zzvn44o7tpgzieipaairwm:
|
||||
resolution: {integrity: sha512-Uw+GVSxp5CM48krnjHObqoOwlCt5Qo6nw1jlCRwfGy68dSYb/LwS9ZFidYGRiM+w6rMawkZiu1mEMAsHYAfoLg==}
|
||||
@@ -30235,7 +30244,6 @@ packages:
|
||||
resolve: 1.22.1
|
||||
transitivePeerDependencies:
|
||||
- ts-node
|
||||
dev: true
|
||||
|
||||
/tailwindcss/3.2.4_postcss@8.4.20:
|
||||
resolution: {integrity: sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==}
|
||||
@@ -30625,6 +30633,13 @@ packages:
|
||||
punycode: 2.1.1
|
||||
dev: true
|
||||
|
||||
/tr46/4.1.1:
|
||||
resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
punycode: 2.3.0
|
||||
dev: true
|
||||
|
||||
/tree-kill/1.2.2:
|
||||
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
||||
hasBin: true
|
||||
@@ -30776,7 +30791,6 @@ packages:
|
||||
make-error: 1.3.6
|
||||
v8-compile-cache-lib: 3.0.1
|
||||
yn: 3.1.1
|
||||
dev: true
|
||||
|
||||
/ts-node/10.9.1_moeqx3xmzxqxagf2sz6mqkbb7m:
|
||||
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
|
||||
@@ -31607,7 +31621,7 @@ packages:
|
||||
/uri-js/4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
dependencies:
|
||||
punycode: 2.1.1
|
||||
punycode: 2.3.0
|
||||
|
||||
/urix/0.1.0:
|
||||
resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==}
|
||||
@@ -31871,7 +31885,6 @@ packages:
|
||||
|
||||
/v8-compile-cache-lib/3.0.1:
|
||||
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
|
||||
dev: true
|
||||
|
||||
/v8-to-istanbul/9.0.1:
|
||||
resolution: {integrity: sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==}
|
||||
@@ -32388,7 +32401,7 @@ packages:
|
||||
- terser
|
||||
dev: true
|
||||
|
||||
/vitest/0.30.1_jsdom@21.0.0:
|
||||
/vitest/0.30.1_jsdom@22.0.0:
|
||||
resolution: {integrity: sha512-y35WTrSTlTxfMLttgQk4rHcaDkbHQwDP++SNwPb+7H8yb13Q3cu2EixrtHzF27iZ8v0XCciSsLg00RkPAzB/aA==}
|
||||
engines: {node: '>=v14.18.0'}
|
||||
hasBin: true
|
||||
@@ -32433,7 +32446,7 @@ packages:
|
||||
chai: 4.3.7
|
||||
concordance: 5.0.4
|
||||
debug: 4.3.4
|
||||
jsdom: 21.0.0
|
||||
jsdom: 22.0.0
|
||||
local-pkg: 0.4.3
|
||||
magic-string: 0.30.0
|
||||
pathe: 1.1.0
|
||||
@@ -33111,11 +33124,11 @@ packages:
|
||||
webidl-conversions: 7.0.0
|
||||
dev: true
|
||||
|
||||
/whatwg-url/11.0.0:
|
||||
resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==}
|
||||
engines: {node: '>=12'}
|
||||
/whatwg-url/12.0.1:
|
||||
resolution: {integrity: sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
tr46: 3.0.0
|
||||
tr46: 4.1.1
|
||||
webidl-conversions: 7.0.0
|
||||
dev: true
|
||||
|
||||
@@ -33301,19 +33314,6 @@ packages:
|
||||
optional: true
|
||||
dev: true
|
||||
|
||||
/ws/8.11.0:
|
||||
resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: ^5.0.2
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
dev: true
|
||||
|
||||
/ws/8.12.1:
|
||||
resolution: {integrity: sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
@@ -33326,6 +33326,19 @@ packages:
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
|
||||
/ws/8.13.0:
|
||||
resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: '>=5.0.2'
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
dev: true
|
||||
|
||||
/ws/8.9.0:
|
||||
resolution: {integrity: sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
@@ -33504,7 +33517,6 @@ packages:
|
||||
/yn/3.1.1:
|
||||
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/yocto-queue/0.1.0:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
|
||||
Reference in New Issue
Block a user