Compare commits
40 Commits
@nhost/rea
...
@nhost/rea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55267c680e | ||
|
|
4d856f557f | ||
|
|
64c579cf8c | ||
|
|
eae65c715b | ||
|
|
9e69f9f235 | ||
|
|
8b127fbb62 | ||
|
|
86ba2081ec | ||
|
|
7c2c31082a | ||
|
|
60f705b033 | ||
|
|
ea34635eb2 | ||
|
|
2004687044 | ||
|
|
bd025d43ca | ||
|
|
87a05f7374 | ||
|
|
798f147db7 | ||
|
|
62b7fd2376 | ||
|
|
1ee021b4a3 | ||
|
|
6e61dce297 | ||
|
|
bd744e52dc | ||
|
|
85723d740b | ||
|
|
36e79e7b32 | ||
|
|
f61264b319 | ||
|
|
e84d9d2576 | ||
|
|
ea69d4f0f1 | ||
|
|
212d58bee5 | ||
|
|
c3d6b7beec | ||
|
|
5d5d8ef4f3 | ||
|
|
deb61fe97c | ||
|
|
04d36154b0 | ||
|
|
203cfb10b9 | ||
|
|
9690f871fa | ||
|
|
74a6b93971 | ||
|
|
dd4c0d2430 | ||
|
|
83f2ca5cde | ||
|
|
0c49e757c8 | ||
|
|
e90a9d7696 | ||
|
|
00a06466f5 | ||
|
|
8ca9f76cb2 | ||
|
|
78113dd62a | ||
|
|
adb0ee82c6 | ||
|
|
a41bb6cae6 |
@@ -1,5 +1,13 @@
|
||||
# @nhost/dashboard
|
||||
|
||||
## 0.20.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 7c2c31082: feat: add support for users to delete their account
|
||||
- @nhost/react-apollo@6.0.1
|
||||
- @nhost/nextjs@1.13.40
|
||||
|
||||
## 0.20.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/dashboard",
|
||||
"version": "0.20.27",
|
||||
"version": "0.20.28",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
import { useDialog } from '@/components/common/DialogProvider';
|
||||
import { SettingsContainer } from '@/components/layout/SettingsContainer';
|
||||
import { Box } from '@/components/ui/v2/Box';
|
||||
import { Button } from '@/components/ui/v2/Button';
|
||||
import { Checkbox } from '@/components/ui/v2/Checkbox';
|
||||
import { Text } from '@/components/ui/v2/Text';
|
||||
import { getToastStyleProps } from '@/utils/constants/settings';
|
||||
import {
|
||||
useDeleteUserAccountMutation,
|
||||
useGetAllWorkspacesAndProjectsQuery,
|
||||
} from '@/utils/__generated__/graphql';
|
||||
import { type ApolloError } from '@apollo/client';
|
||||
import { useSignOut, useUserData } from '@nhost/nextjs';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useState } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
function ConfirmDeleteAccountModal({
|
||||
close,
|
||||
onDelete,
|
||||
}: {
|
||||
onDelete?: () => Promise<any>;
|
||||
close: () => void;
|
||||
}) {
|
||||
const [remove, setRemove] = useState(false);
|
||||
const [loadingRemove, setLoadingRemove] = useState(false);
|
||||
|
||||
const user = useUserData();
|
||||
|
||||
const { data, loading } = useGetAllWorkspacesAndProjectsQuery({
|
||||
skip: !user,
|
||||
});
|
||||
|
||||
const userHasProjects =
|
||||
!loading && data?.workspaces.some((workspace) => workspace.projects.length);
|
||||
|
||||
const userData = useUserData();
|
||||
|
||||
const [deleteUserAccount] = useDeleteUserAccountMutation({
|
||||
variables: { id: userData?.id },
|
||||
});
|
||||
|
||||
const onClickConfirm = async () => {
|
||||
setLoadingRemove(true);
|
||||
|
||||
await toast.promise(
|
||||
deleteUserAccount(),
|
||||
{
|
||||
loading: 'Deleting your account...',
|
||||
success: `The account has been deleted successfully.`,
|
||||
error: (arg: ApolloError) => {
|
||||
// we need to get the internal error message from the GraphQL error
|
||||
const { internal } = arg.graphQLErrors[0]?.extensions || {};
|
||||
const { message } = (internal as Record<string, any>)?.error || {};
|
||||
|
||||
// we use the default Apollo error message if we can't find the
|
||||
// internal error message
|
||||
return (
|
||||
message ||
|
||||
arg.message ||
|
||||
'An error occurred while deleting your account. Please try again.'
|
||||
);
|
||||
},
|
||||
},
|
||||
getToastStyleProps(),
|
||||
);
|
||||
|
||||
onDelete?.();
|
||||
close();
|
||||
};
|
||||
|
||||
return (
|
||||
<Box className={twMerge('w-full rounded-lg p-6 text-left')}>
|
||||
<div className="grid grid-flow-row gap-1">
|
||||
<Text variant="h3" component="h2">
|
||||
Delete Account?
|
||||
</Text>
|
||||
|
||||
{userHasProjects && (
|
||||
<Text
|
||||
variant="subtitle2"
|
||||
className="font-bold"
|
||||
sx={{ color: (theme) => `${theme.palette.error.main} !important` }}
|
||||
>
|
||||
You still have active projects. Please delete your projects before
|
||||
proceeding with the account deletion.
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<Box className="my-4">
|
||||
<Checkbox
|
||||
id="accept-1"
|
||||
label={`I'm sure I want to delete my account`}
|
||||
className="py-2"
|
||||
checked={remove}
|
||||
onChange={(_event, checked) => setRemove(checked)}
|
||||
aria-label="Confirm Delete Project #1"
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<div className="grid grid-flow-row gap-2">
|
||||
<Button
|
||||
color="error"
|
||||
onClick={onClickConfirm}
|
||||
disabled={userHasProjects}
|
||||
loading={loadingRemove}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
|
||||
<Button variant="outlined" color="secondary" onClick={close}>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default function DeleteAccount() {
|
||||
const router = useRouter();
|
||||
const { signOut } = useSignOut();
|
||||
|
||||
const { openDialog, closeDialog } = useDialog();
|
||||
|
||||
const onDelete = async () => {
|
||||
await signOut();
|
||||
await router.push('/signin');
|
||||
};
|
||||
|
||||
const confirmDeleteAccount = async () => {
|
||||
openDialog({
|
||||
component: (
|
||||
<ConfirmDeleteAccountModal close={closeDialog} onDelete={onDelete} />
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<SettingsContainer
|
||||
title="Delete Account"
|
||||
description="Please proceed with caution as the removal of your Personal Account and its contents from the Nhost platform is irreversible. This action will permanently delete your account and all associated data."
|
||||
className="px-0"
|
||||
slotProps={{
|
||||
submitButton: { className: 'hidden' },
|
||||
footer: { className: 'hidden' },
|
||||
}}
|
||||
>
|
||||
<Box className="grid grid-flow-row border-t-1">
|
||||
<Button
|
||||
color="error"
|
||||
className="mx-4 mt-4 justify-self-end"
|
||||
onClick={confirmDeleteAccount}
|
||||
>
|
||||
Delete Personal Account
|
||||
</Button>
|
||||
</Box>
|
||||
</SettingsContainer>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { default as DeleteAccount } from './DeleteAccount';
|
||||
@@ -0,0 +1,5 @@
|
||||
mutation deleteUserAccount($id: uuid!) {
|
||||
deleteUser(id: $id) {
|
||||
__typename
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Container } from '@/components/layout/Container';
|
||||
import { RetryableErrorBoundary } from '@/components/presentational/RetryableErrorBoundary';
|
||||
import { AccountSettingsLayout } from '@/features/account/settings/components/AccountSettingsLayout';
|
||||
import { DeleteAccount } from '@/features/account/settings/components/DeleteAccount';
|
||||
import { PasswordSettings } from '@/features/account/settings/components/PasswordSettings';
|
||||
import { PATSettings } from '@/features/account/settings/components/PATSettings';
|
||||
import type { ReactElement } from 'react';
|
||||
@@ -18,6 +19,8 @@ export default function AccountSettingsPage() {
|
||||
<RetryableErrorBoundary>
|
||||
<PATSettings />
|
||||
</RetryableErrorBoundary>
|
||||
|
||||
<DeleteAccount />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
40
dashboard/src/utils/__generated__/graphql.ts
generated
40
dashboard/src/utils/__generated__/graphql.ts
generated
@@ -22196,6 +22196,13 @@ export type Workspaces_Updates = {
|
||||
where: Workspaces_Bool_Exp;
|
||||
};
|
||||
|
||||
export type DeleteUserAccountMutationVariables = Exact<{
|
||||
id: Scalars['uuid'];
|
||||
}>;
|
||||
|
||||
|
||||
export type DeleteUserAccountMutation = { __typename?: 'mutation_root', deleteUser?: { __typename: 'users' } | null };
|
||||
|
||||
export type GetPersonalAccessTokensQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
@@ -23190,6 +23197,39 @@ export const GetWorkspaceMembersWorkspaceMemberInviteFragmentDoc = gql`
|
||||
memberType
|
||||
}
|
||||
`;
|
||||
export const DeleteUserAccountDocument = gql`
|
||||
mutation deleteUserAccount($id: uuid!) {
|
||||
deleteUser(id: $id) {
|
||||
__typename
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type DeleteUserAccountMutationFn = Apollo.MutationFunction<DeleteUserAccountMutation, DeleteUserAccountMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useDeleteUserAccountMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useDeleteUserAccountMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useDeleteUserAccountMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [deleteUserAccountMutation, { data, loading, error }] = useDeleteUserAccountMutation({
|
||||
* variables: {
|
||||
* id: // value for 'id'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useDeleteUserAccountMutation(baseOptions?: Apollo.MutationHookOptions<DeleteUserAccountMutation, DeleteUserAccountMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<DeleteUserAccountMutation, DeleteUserAccountMutationVariables>(DeleteUserAccountDocument, options);
|
||||
}
|
||||
export type DeleteUserAccountMutationHookResult = ReturnType<typeof useDeleteUserAccountMutation>;
|
||||
export type DeleteUserAccountMutationResult = Apollo.MutationResult<DeleteUserAccountMutation>;
|
||||
export type DeleteUserAccountMutationOptions = Apollo.BaseMutationOptions<DeleteUserAccountMutation, DeleteUserAccountMutationVariables>;
|
||||
export const GetPersonalAccessTokensDocument = gql`
|
||||
query GetPersonalAccessTokens {
|
||||
personalAccessTokens: authRefreshTokens(
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/docs
|
||||
|
||||
## 0.7.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1ee021b4a: remove custom domains from roadmap
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -43,7 +43,6 @@ Nhost Run works with container images built for the **arm architecture**. Images
|
||||
|
||||
Some missing functionality we are currently working on and should be added soon:
|
||||
|
||||
1. Custom domains
|
||||
2. Run services with the CLI alongside your project
|
||||
3. Ability to connect services to repositories for automated building and deployment (currently this needs to be done via a third party CI, see [Deployment via CI](/run/ci) for more details).
|
||||
4. Expose TCP/UDP ports
|
||||
1. Run services with the CLI alongside your project
|
||||
2. Ability to connect services to repositories for automated building and deployment (currently this needs to be done via a third party CI, see [Deployment via CI](/run/ci) for more details).
|
||||
3. Expose TCP/UDP ports
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/docs",
|
||||
"version": "0.7.0",
|
||||
"version": "0.7.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.1'
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost-examples/nextjs-server-components
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8b127fbb6]
|
||||
- @nhost/nhost-js@2.2.18
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/nextjs-server-components",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -144,7 +144,7 @@ version = '14.6-20230406-2'
|
||||
[provider]
|
||||
|
||||
[storage]
|
||||
version = '0.3.5'
|
||||
version = '0.4.0'
|
||||
|
||||
[observability]
|
||||
[observability.grafana]
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"postinstall": "pnpm add-nhost-js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nhost/nhost-js": "2.2.17",
|
||||
"@nhost/nhost-js": "2.2.18",
|
||||
"@playwright/test": "^1.31.0",
|
||||
"@sveltejs/adapter-auto": "^2.0.0",
|
||||
"@sveltejs/kit": "^1.5.0",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @nhost-examples/react-apollo
|
||||
|
||||
## 0.1.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6e61dce29: feat: add SignIn with Apple
|
||||
- @nhost/react@2.1.1
|
||||
- @nhost/react-apollo@6.0.1
|
||||
|
||||
## 0.1.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -25,14 +25,14 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.21.2'
|
||||
version = '0.21.4'
|
||||
|
||||
[auth.redirections]
|
||||
clientUrl = 'https://react-apollo.example.nhost.io/'
|
||||
allowedUrls = ['https://react-apollo.example.nhost.io/profile']
|
||||
allowedUrls = ['https://react-apollo.example.nhost.io/profile', 'http://localhost:30000']
|
||||
|
||||
[auth.signUp]
|
||||
enabled = true
|
||||
@@ -79,7 +79,11 @@ enabled = false
|
||||
|
||||
[auth.method.oauth]
|
||||
[auth.method.oauth.apple]
|
||||
enabled = false
|
||||
enabled = true
|
||||
clientId = '{{ secrets.APPLE_SERVICE_IDENTIFIER }}'
|
||||
keyId = '{{ secrets.APPLE_KEY_ID }}'
|
||||
teamId = '{{ secrets.APPLE_TEAM_ID }}'
|
||||
privateKey = '{{ secrets.APPLE_PRIVATE_KEY }}'
|
||||
|
||||
[auth.method.oauth.azuread]
|
||||
tenant = 'common'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost-examples/react-apollo",
|
||||
"version": "0.1.15",
|
||||
"version": "0.1.16",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.7.14",
|
||||
|
||||
70
examples/react-apollo/pnpm-lock.yaml
generated
70
examples/react-apollo/pnpm-lock.yaml
generated
@@ -1,12 +1,16 @@
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
'@apollo/client':
|
||||
specifier: ^3.7.14
|
||||
version: 3.7.14(graphql@16.6.0)(react-dom@18.2.0)(react@18.2.0)(subscriptions-transport-ws@0.9.19)
|
||||
'@mantine/core':
|
||||
specifier: ^4.2.12
|
||||
version: 4.2.12(@babel/core@7.22.1)(@mantine/hooks@4.2.12)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
version: 4.2.12(@babel/core@7.22.1)(@mantine/hooks@4.2.12)(@types/react@18.2.34)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@mantine/dropzone':
|
||||
specifier: ^4.2.12
|
||||
version: 4.2.12(@mantine/core@4.2.12)(@mantine/hooks@4.2.12)(react-dom@18.2.0)(react@18.2.0)
|
||||
@@ -21,7 +25,7 @@ dependencies:
|
||||
version: 4.2.12(@mantine/core@4.2.12)(@mantine/hooks@4.2.12)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@nhost/react':
|
||||
specifier: '*'
|
||||
version: 0.2.0(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)(xstate@4.37.2)
|
||||
version: 0.2.0(@types/react@18.2.34)(react-dom@18.2.0)(react@18.2.0)(xstate@4.37.2)
|
||||
'@nhost/react-apollo':
|
||||
specifier: '*'
|
||||
version: 1.0.1(@apollo/client@3.7.14)(graphql@16.6.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
@@ -64,11 +68,11 @@ devDependencies:
|
||||
specifier: ^6.0.1
|
||||
version: 6.0.1
|
||||
'@types/react':
|
||||
specifier: ^18.2.6
|
||||
version: 18.2.6
|
||||
specifier: ^18.2.14
|
||||
version: 18.2.34
|
||||
'@types/react-dom':
|
||||
specifier: ^18.2.4
|
||||
version: 18.2.4
|
||||
specifier: ^18.2.6
|
||||
version: 18.2.14
|
||||
'@types/totp-generator':
|
||||
specifier: ^0.0.4
|
||||
version: 0.0.4
|
||||
@@ -419,7 +423,7 @@ packages:
|
||||
resolution: {integrity: sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==}
|
||||
dev: false
|
||||
|
||||
/@emotion/react@11.7.1(@babel/core@7.22.1)(@types/react@18.2.6)(react@18.2.0):
|
||||
/@emotion/react@11.7.1(@babel/core@7.22.1)(@types/react@18.2.34)(react@18.2.0):
|
||||
resolution: {integrity: sha512-DV2Xe3yhkF1yT4uAUoJcYL1AmrnO5SVsdfvu+fBuS7IbByDeTVx9+wFmvx9Idzv7/78+9Mgx2Hcmr7Fex3tIyw==}
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
@@ -438,7 +442,7 @@ packages:
|
||||
'@emotion/sheet': 1.2.2
|
||||
'@emotion/utils': 1.0.0
|
||||
'@emotion/weak-memoize': 0.2.5
|
||||
'@types/react': 18.2.6
|
||||
'@types/react': 18.2.34
|
||||
hoist-non-react-statics: 3.3.2
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
@@ -450,7 +454,7 @@ packages:
|
||||
'@emotion/memoize': 0.7.5
|
||||
'@emotion/unitless': 0.7.5
|
||||
'@emotion/utils': 1.0.0
|
||||
csstype: 3.0.9
|
||||
csstype: 3.1.2
|
||||
dev: false
|
||||
|
||||
/@emotion/sheet@1.2.2:
|
||||
@@ -1128,7 +1132,7 @@ packages:
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
dev: true
|
||||
|
||||
/@mantine/core@4.2.12(@babel/core@7.22.1)(@mantine/hooks@4.2.12)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0):
|
||||
/@mantine/core@4.2.12(@babel/core@7.22.1)(@mantine/hooks@4.2.12)(@types/react@18.2.34)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-PZcVUvcSZiZmLR1moKBJFdFIh6a4C+TE2ao91kzTAlH5Qb8t/V3ONbfPk3swHoYr7OSLJQM8vZ7UD5sFDiq0/g==}
|
||||
peerDependencies:
|
||||
'@mantine/hooks': 4.2.12
|
||||
@@ -1136,13 +1140,13 @@ packages:
|
||||
react-dom: '>=16.8.0'
|
||||
dependencies:
|
||||
'@mantine/hooks': 4.2.12(react@18.2.0)
|
||||
'@mantine/styles': 4.2.12(@babel/core@7.22.1)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@mantine/styles': 4.2.12(@babel/core@7.22.1)(@types/react@18.2.34)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@popperjs/core': 2.11.8
|
||||
'@radix-ui/react-scroll-area': 0.1.4(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
react-popper: 2.3.0(@popperjs/core@2.11.8)(react-dom@18.2.0)(react@18.2.0)
|
||||
react-textarea-autosize: 8.4.1(@types/react@18.2.6)(react@18.2.0)
|
||||
react-textarea-autosize: 8.4.1(@types/react@18.2.34)(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- '@types/react'
|
||||
@@ -1156,7 +1160,7 @@ packages:
|
||||
react: '>=16.8.0'
|
||||
react-dom: '>=16.8.0'
|
||||
dependencies:
|
||||
'@mantine/core': 4.2.12(@babel/core@7.22.1)(@mantine/hooks@4.2.12)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@mantine/core': 4.2.12(@babel/core@7.22.1)(@mantine/hooks@4.2.12)(@types/react@18.2.34)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@mantine/hooks': 4.2.12(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
@@ -1179,7 +1183,7 @@ packages:
|
||||
react: '>=16.8.0'
|
||||
react-dom: '>=16.8.0'
|
||||
dependencies:
|
||||
'@mantine/core': 4.2.12(@babel/core@7.22.1)(@mantine/hooks@4.2.12)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@mantine/core': 4.2.12(@babel/core@7.22.1)(@mantine/hooks@4.2.12)(@types/react@18.2.34)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@mantine/hooks': 4.2.12(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
@@ -1194,21 +1198,21 @@ packages:
|
||||
react: '>=16.8.0'
|
||||
react-dom: '>=16.8.0'
|
||||
dependencies:
|
||||
'@mantine/core': 4.2.12(@babel/core@7.22.1)(@mantine/hooks@4.2.12)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@mantine/core': 4.2.12(@babel/core@7.22.1)(@mantine/hooks@4.2.12)(@types/react@18.2.34)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@mantine/hooks': 4.2.12(react@18.2.0)
|
||||
prism-react-renderer: 1.3.5(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@mantine/styles@4.2.12(@babel/core@7.22.1)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0):
|
||||
/@mantine/styles@4.2.12(@babel/core@7.22.1)(@types/react@18.2.34)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-9q1DzW0UNW/ORMGLHfN2XABOSEm0ZQebhNlLD757R6OQouoLuUf9elUwgGOXSyogMlsAYoy84XbJ3ZbbTm4YCA==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
react-dom: '>=16.8.0'
|
||||
dependencies:
|
||||
'@emotion/cache': 11.7.1
|
||||
'@emotion/react': 11.7.1(@babel/core@7.22.1)(@types/react@18.2.6)(react@18.2.0)
|
||||
'@emotion/react': 11.7.1(@babel/core@7.22.1)(@types/react@18.2.34)(react@18.2.0)
|
||||
'@emotion/serialize': 1.0.2
|
||||
'@emotion/utils': 1.0.0
|
||||
clsx: 1.2.1
|
||||
@@ -1256,14 +1260,14 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/@nhost/react@0.2.0(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)(xstate@4.37.2):
|
||||
/@nhost/react@0.2.0(@types/react@18.2.34)(react-dom@18.2.0)(react@18.2.0)(xstate@4.37.2):
|
||||
resolution: {integrity: sha512-V8um4+YVN2dNio8u+zKlxHIub7ZU4Cz2D3wf2dJW+fHHgChh5niNw4vQ3L+JldGe4yAXATF94P8VaQav/Ksgqg==}
|
||||
peerDependencies:
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
react-dom: ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
'@nhost/client': 0.2.0
|
||||
'@xstate/react': 2.0.1(@types/react@18.2.6)(react@18.2.0)(xstate@4.37.2)
|
||||
'@xstate/react': 2.0.1(@types/react@18.2.34)(react@18.2.0)(xstate@4.37.2)
|
||||
immer: 9.0.21
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
@@ -1501,14 +1505,14 @@ packages:
|
||||
/@types/prop-types@15.7.5:
|
||||
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
|
||||
|
||||
/@types/react-dom@18.2.4:
|
||||
resolution: {integrity: sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==}
|
||||
/@types/react-dom@18.2.14:
|
||||
resolution: {integrity: sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==}
|
||||
dependencies:
|
||||
'@types/react': 18.2.6
|
||||
'@types/react': 18.2.34
|
||||
dev: true
|
||||
|
||||
/@types/react@18.2.6:
|
||||
resolution: {integrity: sha512-wRZClXn//zxCFW+ye/D2qY65UsYP1Fpex2YXorHc8awoNamkMZSvBxwxdYVInsHOZZd2Ppq8isnSzJL5Mpf8OA==}
|
||||
/@types/react@18.2.34:
|
||||
resolution: {integrity: sha512-U6eW/alrRk37FU/MS2RYMjx0Va2JGIVXELTODaTIYgvWGCV4Y4TfTUzG8DdmpDNIT0Xpj/R7GfyHOJJrDttcvg==}
|
||||
dependencies:
|
||||
'@types/prop-types': 15.7.5
|
||||
'@types/scheduler': 0.16.3
|
||||
@@ -1643,7 +1647,7 @@ packages:
|
||||
xstate: 4.37.2
|
||||
dev: true
|
||||
|
||||
/@xstate/react@2.0.1(@types/react@18.2.6)(react@18.2.0)(xstate@4.37.2):
|
||||
/@xstate/react@2.0.1(@types/react@18.2.34)(react@18.2.0)(xstate@4.37.2):
|
||||
resolution: {integrity: sha512-sT3hxyzNBw+bm7uT3BP+uXzN0MnRqiaj/U9Yl4OYaMAUJXWsRvSA/ipL7EDf0gVLRGrRhJTCsC0cjWaduAAqnw==}
|
||||
peerDependencies:
|
||||
'@xstate/fsm': ^1.6.5
|
||||
@@ -1656,7 +1660,7 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
use-isomorphic-layout-effect: 1.1.2(@types/react@18.2.6)(react@18.2.0)
|
||||
use-isomorphic-layout-effect: 1.1.2(@types/react@18.2.34)(react@18.2.0)
|
||||
use-subscription: 1.8.0(react@18.2.0)
|
||||
xstate: 4.37.2
|
||||
transitivePeerDependencies:
|
||||
@@ -3174,7 +3178,7 @@ packages:
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/react-textarea-autosize@8.4.1(@types/react@18.2.6)(react@18.2.0):
|
||||
/react-textarea-autosize@8.4.1(@types/react@18.2.34)(react@18.2.0):
|
||||
resolution: {integrity: sha512-aD2C+qK6QypknC+lCMzteOdIjoMbNlgSFmJjCV+DrfTPwp59i/it9mMNf2HDzvRjQgKAyBDPyLJhcrzElf2U4Q==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
@@ -3183,7 +3187,7 @@ packages:
|
||||
'@babel/runtime': 7.22.3
|
||||
react: 18.2.0
|
||||
use-composed-ref: 1.3.0(react@18.2.0)
|
||||
use-latest: 1.2.1(@types/react@18.2.6)(react@18.2.0)
|
||||
use-latest: 1.2.1(@types/react@18.2.34)(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
dev: false
|
||||
@@ -3637,7 +3641,7 @@ packages:
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/use-isomorphic-layout-effect@1.1.2(@types/react@18.2.6)(react@18.2.0):
|
||||
/use-isomorphic-layout-effect@1.1.2(@types/react@18.2.34)(react@18.2.0):
|
||||
resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
@@ -3646,11 +3650,11 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/react': 18.2.6
|
||||
'@types/react': 18.2.34
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/use-latest@1.2.1(@types/react@18.2.6)(react@18.2.0):
|
||||
/use-latest@1.2.1(@types/react@18.2.34)(react@18.2.0):
|
||||
resolution: {integrity: sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
@@ -3659,9 +3663,9 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/react': 18.2.6
|
||||
'@types/react': 18.2.34
|
||||
react: 18.2.0
|
||||
use-isomorphic-layout-effect: 1.1.2(@types/react@18.2.6)(react@18.2.0)
|
||||
use-isomorphic-layout-effect: 1.1.2(@types/react@18.2.34)(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/use-subscription@1.8.0(react@18.2.0):
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { FaGithub, FaGoogle } from 'react-icons/fa/index.js'
|
||||
import { FaApple, FaGithub, FaGoogle } from 'react-icons/fa/index.js'
|
||||
|
||||
import { useProviderLink } from '@nhost/react'
|
||||
|
||||
import AuthLink from './AuthLink'
|
||||
|
||||
export default function OauthLinks() {
|
||||
const { github, google } = useProviderLink({ redirectTo: window.location.origin })
|
||||
const { github, google, apple } = useProviderLink({ redirectTo: window.location.origin })
|
||||
|
||||
return (
|
||||
<>
|
||||
<AuthLink leftIcon={<FaGithub />} link={github} color="#333">
|
||||
@@ -14,6 +15,9 @@ export default function OauthLinks() {
|
||||
<AuthLink leftIcon={<FaGoogle />} link={google} color="#de5246">
|
||||
Continue with Google
|
||||
</AuthLink>
|
||||
<AuthLink leftIcon={<FaApple />} link={apple} color="#333333">
|
||||
Sign In With Apple
|
||||
</AuthLink>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -28,7 +28,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @nhost-examples/vue-apollo
|
||||
|
||||
## 0.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 0c49e757c: feat: add new Storage page to demonstrate how to use the composables `useMultipleFilesUpload` together with `useFileUploadItem`
|
||||
- Updated dependencies [0c49e757c]
|
||||
- @nhost/vue@1.14.0
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@nhost-examples/vue-apollo",
|
||||
"private": true,
|
||||
"version": "0.0.8",
|
||||
"version": "0.0.9",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
@@ -17,14 +17,16 @@
|
||||
"@apollo/client": "^3.7.1",
|
||||
"@mdi/font": "5.9.55",
|
||||
"@nhost/apollo": "*",
|
||||
"@nhost/nhost-js": "*",
|
||||
"@nhost/vue": "*",
|
||||
"@vue/apollo-composable": "4.0.0-alpha.18",
|
||||
"graphql": "15.7.2",
|
||||
"graphql": "^16.8.1",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"roboto-fontface": "*",
|
||||
"vite-plugin-vuetify": "^1.0.1",
|
||||
"vue": "^3.2.41",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue3-dropzone": "^2.1.2",
|
||||
"vuetify": "3.0.0-beta.10",
|
||||
"webfontloader": "^1.0.0"
|
||||
},
|
||||
@@ -35,7 +37,7 @@
|
||||
"@xstate/inspect": "^0.6.2",
|
||||
"sass": "1.32.0",
|
||||
"typescript": "4.9.4",
|
||||
"vite": "^4.0.2",
|
||||
"vite": "^4.5.0",
|
||||
"vue-tsc": "^0.38.9"
|
||||
},
|
||||
"eslintConfig": {
|
||||
|
||||
1657
examples/vue-apollo/pnpm-lock.yaml
generated
Normal file
1657
examples/vue-apollo/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
97
examples/vue-apollo/src/components/FileDropZone.vue
Normal file
97
examples/vue-apollo/src/components/FileDropZone.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, toRaw, unref, type Ref } from 'vue'
|
||||
import { useDropzone, type FileRejectReason } from 'vue3-dropzone'
|
||||
|
||||
const { multiple } = defineProps({
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['onDrop'])
|
||||
|
||||
const files: Ref<File[]> = ref([])
|
||||
const errors: Ref<FileRejectReason[]> = ref([])
|
||||
|
||||
const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
||||
onDrop,
|
||||
multiple
|
||||
})
|
||||
|
||||
function onDrop(acceptFiles: File[], rejectReasons: FileRejectReason[]) {
|
||||
files.value = acceptFiles
|
||||
errors.value = rejectReasons
|
||||
|
||||
emit('onDrop', toRaw(unref(files)))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="dropzone" v-bind="getRootProps()">
|
||||
<div
|
||||
class="border"
|
||||
:class="{
|
||||
isDragActive
|
||||
}"
|
||||
>
|
||||
<input v-bind="getInputProps()" />
|
||||
<p v-if="isDragActive">Drop here ...</p>
|
||||
<p v-else>Drag and drop here, or Click to select</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dropzone,
|
||||
.files {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.border {
|
||||
border: 2px dashed #ccc;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
transition: all 0.3s ease;
|
||||
background: #fff;
|
||||
|
||||
&.isDragActive {
|
||||
border: 2px dashed #ffb300;
|
||||
background: rgb(255 167 18 / 20%);
|
||||
}
|
||||
}
|
||||
|
||||
.file-item {
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: rgb(255 167 18 / 20%);
|
||||
padding: 7px;
|
||||
padding-left: 15px;
|
||||
margin-top: 10px;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.delete-file {
|
||||
background: red;
|
||||
color: #fff;
|
||||
padding: 5px 10px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
34
examples/vue-apollo/src/components/FileUploadItem.vue
Normal file
34
examples/vue-apollo/src/components/FileUploadItem.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<script lang="ts" setup>
|
||||
import { FileItemRef } from '@nhost/nhost-js'
|
||||
import { useFileUploadItem } from '@nhost/vue'
|
||||
|
||||
const { file } = defineProps<{ file: FileItemRef }>()
|
||||
|
||||
const { name, progress } = useFileUploadItem(file)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container">
|
||||
<span class="file_name">{{ name }}</span>
|
||||
<v-progress-linear v-model="progress" color="green">
|
||||
{{ progress }}
|
||||
</v-progress-linear>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.file_name {
|
||||
margin-right: 1rem;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
width: 40%;
|
||||
}
|
||||
</style>
|
||||
@@ -3,8 +3,14 @@
|
||||
<v-list-item title="Home" to="/" value="home" prepend-icon="mdi-home" />
|
||||
<v-list-item title="Profile" to="/profile" value="profile" prepend-icon="mdi-account" />
|
||||
<v-list-item title="Apollo" to="/apollo" value="apollo" prepend-icon="mdi-api" />
|
||||
<v-list-item title="Storage" to="/storage" value="storage" prepend-icon="mdi-server" />
|
||||
<v-list-item title="About" to="/about" value="about" prepend-icon="mdi-information" />
|
||||
<v-list-item v-if="authenticated" title="Sign out" prepend-icon="mdi-exit-to-app" @click="signOutHandler" />
|
||||
<v-list-item
|
||||
v-if="authenticated"
|
||||
title="Sign out"
|
||||
prepend-icon="mdi-exit-to-app"
|
||||
@click="signOutHandler"
|
||||
/>
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
|
||||
129
examples/vue-apollo/src/pages/StoragePage.vue
Normal file
129
examples/vue-apollo/src/pages/StoragePage.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<div className="d-flex align-center flex-column">
|
||||
<h1>Storage</h1>
|
||||
<v-card width="400" class="singleFileUpload" tile>
|
||||
<v-card-title>Upload a single file</v-card-title>
|
||||
<v-card-text>
|
||||
<FileDropZone @on-drop="onDropSingleFile" />
|
||||
<span v-if="isUploading" class="upload_status">Uploading...</span>
|
||||
<span v-if="isUploaded" class="upload_status upload_success">Upload Succeeded</span>
|
||||
<span v-if="isError" class="upload_status upload_error">Upload Failed</span>
|
||||
<div v-if="fileToUpload" class="file_progress">
|
||||
<span class="file_progress_name">{{ fileToUpload.name }}</span>
|
||||
<v-progress-linear v-model="progress" color="green">
|
||||
{{ progress }}
|
||||
</v-progress-linear>
|
||||
<button class="clearButton" @click="clearFile">Clear</button>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-card width="400" tile class="relative">
|
||||
<v-card-title>Upload multiple files</v-card-title>
|
||||
<v-card-text class="footer">
|
||||
<FileDropZone :multiple="true" @on-drop="onDropMultipleFiles" />
|
||||
<span v-if="isUploadingAll" class="upload_status">Uploading...</span>
|
||||
<span v-if="isUploadedAll" class="upload_status upload_success">Upload Succeeded</span>
|
||||
<span v-if="isErrorAll" class="upload_status upload_error">Upload Failed</span>
|
||||
</v-card-text>
|
||||
|
||||
<div v-for="(file, index) of files" :key="index">
|
||||
<FileUploadItem :file="file" />
|
||||
</div>
|
||||
|
||||
<div class="relative buttonsContainer">
|
||||
<v-btn
|
||||
class="mb-2 text-white w-100"
|
||||
:disabled="!files.length"
|
||||
variant="elevated"
|
||||
color="green"
|
||||
@click="uploadAll"
|
||||
>
|
||||
Upload
|
||||
</v-btn>
|
||||
<v-btn class="w-100" @click="clear"> Clear </v-btn>
|
||||
</div>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useFileUpload, useMultipleFilesUpload } from '@nhost/vue'
|
||||
import { ref } from 'vue'
|
||||
import FileDropZone from '../components/FileDropZone.vue'
|
||||
import FileUploadItem from '../components/FileUploadItem.vue'
|
||||
|
||||
const fileToUpload = ref<File | null>(null)
|
||||
|
||||
const { upload, progress, isUploaded, isUploading, isError } = useFileUpload()
|
||||
|
||||
const onDropSingleFile = async ([file]: File[]) => {
|
||||
fileToUpload.value = file
|
||||
upload({ file })
|
||||
}
|
||||
|
||||
const clearFile = () => {
|
||||
fileToUpload.value = null
|
||||
isUploaded.value = false
|
||||
}
|
||||
|
||||
const {
|
||||
add,
|
||||
upload: uploadAll,
|
||||
isUploaded: isUploadedAll,
|
||||
isUploading: isUploadingAll,
|
||||
isError: isErrorAll,
|
||||
files,
|
||||
clear
|
||||
} = useMultipleFilesUpload()
|
||||
|
||||
const onDropMultipleFiles = (files: File[]) => {
|
||||
add({ files })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.buttonsContainer {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.upload_success {
|
||||
color: 'green';
|
||||
}
|
||||
|
||||
.upload_error {
|
||||
color: 'red';
|
||||
}
|
||||
|
||||
.file_progress {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.file_progress_name {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.upload_status {
|
||||
display: block;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.singleFileUpload {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.clearButton {
|
||||
margin-left: 1rem;
|
||||
background: red;
|
||||
color: #fff;
|
||||
padding: 5px 10px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
@@ -13,6 +13,7 @@ import SignUpEmailPasword from './pages/sign-up/EmailPassword.vue'
|
||||
import SignUpEmailPaswordless from './pages/sign-up/EmailPasswordless.vue'
|
||||
import SignUp from './pages/sign-up/IndexPage.vue'
|
||||
import Signout from './pages/SignoutPage.vue'
|
||||
import StoragePage from './pages/StoragePage.vue'
|
||||
|
||||
export const routes: RouteRecordRaw[] = [
|
||||
{ path: '/', component: Index, meta: { auth: true } },
|
||||
@@ -50,5 +51,6 @@ export const routes: RouteRecordRaw[] = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{ path: '/apollo', component: ApolloPage, meta: { auth: true } }
|
||||
{ path: '/apollo', component: ApolloPage, meta: { auth: true } },
|
||||
{ path: '/storage', component: StoragePage, meta: { auth: true } }
|
||||
]
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost/apollo
|
||||
|
||||
## 5.2.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8b127fbb6]
|
||||
- @nhost/nhost-js@2.2.18
|
||||
|
||||
## 5.2.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/apollo",
|
||||
"version": "5.2.21",
|
||||
"version": "5.2.22",
|
||||
"description": "Nhost Apollo Client library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost/react-apollo
|
||||
|
||||
## 6.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/apollo@5.2.22
|
||||
- @nhost/react@2.1.1
|
||||
|
||||
## 6.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/react-apollo",
|
||||
"version": "6.0.0",
|
||||
"version": "6.0.1",
|
||||
"description": "Nhost React Apollo client",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/react-urql
|
||||
|
||||
## 3.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@2.1.1
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/react-urql",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"description": "Nhost React URQL client",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
805
observability/dashboards/ingress_metrics.json
Executable file
805
observability/dashboards/ingress_metrics.json
Executable file
@@ -0,0 +1,805 @@
|
||||
{
|
||||
"__inputs": [
|
||||
{
|
||||
"name": "DS_PROMETHEUS",
|
||||
"label": "Prometheus",
|
||||
"description": "",
|
||||
"type": "datasource",
|
||||
"pluginId": "prometheus",
|
||||
"pluginName": "Prometheus"
|
||||
}
|
||||
],
|
||||
"__elements": {},
|
||||
"__requires": [
|
||||
{
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "9.2.0"
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "prometheus",
|
||||
"name": "Prometheus",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "timeseries",
|
||||
"name": "Time series",
|
||||
"version": ""
|
||||
}
|
||||
],
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"target": {
|
||||
"limit": 100,
|
||||
"matchAny": false,
|
||||
"tags": [],
|
||||
"type": "dashboard"
|
||||
},
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"collapsed": false,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 6,
|
||||
"panels": [],
|
||||
"title": "General",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"description": "Number of requests by method/function",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by(method, ingress) (increase(nginx_ingress_controller_requests{method=~\"$method\",ingress=~\"$ingress\"}[$__rate_interval]))",
|
||||
"format": "time_series",
|
||||
"interval": "2m",
|
||||
"legendFormat": "{{method}} {{ingress}}",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Requests",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"description": "Number of requests by status response",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 1
|
||||
},
|
||||
"id": 21,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by(status) (increase(nginx_ingress_controller_requests{method=~\"$method\",ingress=~\"$ingress\"}[$__rate_interval]))",
|
||||
"format": "time_series",
|
||||
"interval": "2m",
|
||||
"legendFormat": "{{status}}",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Response Status",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"description": "",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "bytes"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 9
|
||||
},
|
||||
"id": 8,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by(ingress, method) (increase(nginx_ingress_controller_response_size_sum{ingress=~\"$ingress\",method=~\"$method\"}[$__rate_interval])) / sum by(ingress, method) (increase(nginx_ingress_controller_requests{ingress=~\"$ingress\",method=~\"$method\"}[$__rate_interval]))",
|
||||
"interval": "2m",
|
||||
"legendFormat": "{{ method }} - {{ ingress }}",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Average Response Size",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "continuous-GrYlRd"
|
||||
},
|
||||
"custom": {
|
||||
"align": "auto",
|
||||
"displayMode": "auto",
|
||||
"filterable": true,
|
||||
"inspect": false
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Time"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.width",
|
||||
"value": 183
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 9
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"footer": {
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
"showHeader": true,
|
||||
"sortBy": [
|
||||
{
|
||||
"desc": true,
|
||||
"displayName": "Value"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pluginVersion": "9.2.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "ceil(sum by(ingress, method) (increase(nginx_ingress_controller_requests{ingress=~\"$ingress\",method=~\"$method\"}[$__range])))",
|
||||
"format": "table",
|
||||
"instant": true,
|
||||
"interval": "2m",
|
||||
"legendFormat": "{{ingress}} {{method}}",
|
||||
"range": false,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Total Requests",
|
||||
"transformations": [],
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
"collapsed": false,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 17
|
||||
},
|
||||
"id": 26,
|
||||
"panels": [],
|
||||
"title": "Response Times",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"description": "",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "s"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 18
|
||||
},
|
||||
"id": 11,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by(method, ingress) (increase(nginx_ingress_controller_response_duration_seconds_sum{method=~\"$method\", ingress=~\"$ingress\"}[$__rate_interval])) / sum by(method, ingress) (increase(nginx_ingress_controller_response_duration_seconds_count{method=~\"$method\", ingress=~\"$ingress\"}[$__rate_interval]))",
|
||||
"interval": "2m",
|
||||
"legendFormat": "{{ ingress }} - {{ method }}",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Average Response Time",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"collapsed": false,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 26
|
||||
},
|
||||
"id": 19,
|
||||
"panels": [],
|
||||
"title": "Errors",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"description": "Number of requests that failed divided by the total number of requests",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percentunit"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 27
|
||||
},
|
||||
"id": 20,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"expr": "sum by(ingress,method) (increase(nginx_ingress_controller_requests{ingress=~\"$ingress\",method=~\"$method\",status=~\"^[4-5].*\"}[$__rate_interval])) / sum by(ingress, method) (increase(nginx_ingress_controller_requests[$__rate_interval]))",
|
||||
"format": "time_series",
|
||||
"interval": "2m",
|
||||
"legendFormat": "{{method}} {{ ingress }}",
|
||||
"range": true,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Error Rate",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "continuous-GrYlRd"
|
||||
},
|
||||
"custom": {
|
||||
"align": "auto",
|
||||
"displayMode": "auto",
|
||||
"filterable": true,
|
||||
"inspect": false
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Time"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.width",
|
||||
"value": 183
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 27
|
||||
},
|
||||
"id": 10,
|
||||
"options": {
|
||||
"footer": {
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
"showHeader": true,
|
||||
"sortBy": [
|
||||
{
|
||||
"desc": true,
|
||||
"displayName": "Value"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pluginVersion": "9.2.0",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"exemplar": false,
|
||||
"expr": "ceil(sum by(ingress, method,status) (increase(nginx_ingress_controller_requests{method=~\"$method\",ingress=~\"$ingress\",status=~\"^[4-5].*\"}[$__range])))",
|
||||
"format": "table",
|
||||
"instant": true,
|
||||
"interval": "2m",
|
||||
"legendFormat": "{{ingress}} {{method}}",
|
||||
"range": false,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Total Errors",
|
||||
"transformations": [],
|
||||
"type": "table"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 37,
|
||||
"style": "dark",
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {},
|
||||
"definition": "label_values(nginx_ingress_controller_requests,ingress)",
|
||||
"hide": 0,
|
||||
"includeAll": true,
|
||||
"multi": false,
|
||||
"name": "ingress",
|
||||
"options": [],
|
||||
"query": {
|
||||
"query": "label_values(nginx_ingress_controller_requests,ingress)",
|
||||
"refId": "StandardVariableQuery"
|
||||
},
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"skipUrlSync": false,
|
||||
"sort": 0,
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"definition": "label_values(nginx_ingress_controller_requests,method)",
|
||||
"hide": 0,
|
||||
"includeAll": true,
|
||||
"multi": false,
|
||||
"name": "method",
|
||||
"options": [],
|
||||
"query": {
|
||||
"query": "label_values(nginx_ingress_controller_requests,method)",
|
||||
"refId": "StandardVariableQuery"
|
||||
},
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"skipUrlSync": false,
|
||||
"sort": 0,
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Ingress Metrics",
|
||||
"uid": "WOWEHb7Sz",
|
||||
"version": 16,
|
||||
"weekStart": ""
|
||||
}
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.2'
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/nextjs
|
||||
|
||||
## 1.13.40
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @nhost/react@2.1.1
|
||||
|
||||
## 1.13.39
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/nextjs",
|
||||
"version": "1.13.39",
|
||||
"version": "1.13.40",
|
||||
"description": "Nhost NextJS library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @nhost/nhost-js
|
||||
|
||||
## 2.2.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 8b127fbb6: feat: export `urlFromSubdomain` helper
|
||||
|
||||
## 2.2.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -25,7 +25,7 @@ httpPoolSize = 100
|
||||
|
||||
[functions]
|
||||
[functions.node]
|
||||
version = 16
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.20.1'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/nhost-js",
|
||||
"version": "2.2.17",
|
||||
"version": "2.2.18",
|
||||
"description": "Nhost JavaScript SDK",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from '@nhost/hasura-auth-js'
|
||||
export * from '@nhost/hasura-storage-js'
|
||||
export * from './clients'
|
||||
export { urlFromSubdomain } from './utils/helpers'
|
||||
export * from './utils/types'
|
||||
|
||||
@@ -5,9 +5,9 @@ export const LOCALHOST_REGEX =
|
||||
/^((?<protocol>http[s]?):\/\/)?(?<host>(localhost|local))(:(?<port>(\d+|__\w+__)))?$/
|
||||
|
||||
/**
|
||||
* `backendUrl` should now be used only when self-hosting
|
||||
* `subdomain` and `region` should be used instead when using the Nhost platform
|
||||
* `
|
||||
* \`backendUrl\` should now be used only when self-hosting
|
||||
* \`subdomain\` and `region` should be used instead when using the Nhost platform
|
||||
*
|
||||
* @param backendOrSubdomain
|
||||
* @param service
|
||||
* @returns
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @nhost/react
|
||||
|
||||
## 2.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8b127fbb6]
|
||||
- @nhost/nhost-js@2.2.18
|
||||
|
||||
## 2.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/react",
|
||||
"version": "2.1.0",
|
||||
"version": "2.1.1",
|
||||
"description": "Nhost React library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# @nhost/vue
|
||||
|
||||
## 1.14.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8b127fbb6]
|
||||
- @nhost/nhost-js@2.2.18
|
||||
|
||||
## 1.14.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 0c49e757c: feat: add new composable `useMultipleFilesUpload`
|
||||
|
||||
## 1.13.39
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nhost/vue",
|
||||
"version": "1.13.39",
|
||||
"version": "1.14.1",
|
||||
"description": "Nhost Vue library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
export * from './client'
|
||||
export * from './useAccessToken'
|
||||
export * from './useAuthInterpreter'
|
||||
export * from './useAuthenticated'
|
||||
export * from './useAuthenticationStatus'
|
||||
export * from './useAuthInterpreter'
|
||||
export * from './useChangeEmail'
|
||||
export * from './useChangePassword'
|
||||
export * from './useConfigMfa'
|
||||
@@ -10,6 +10,7 @@ export * from './useDecodedAccessToken'
|
||||
export * from './useFileUpload'
|
||||
export * from './useHasuraClaim'
|
||||
export * from './useHasuraClaims'
|
||||
export * from './useMultipleFilesUpload'
|
||||
export * from './useNhostClient'
|
||||
export * from './useProviderLink'
|
||||
export * from './useResetPassword'
|
||||
|
||||
@@ -8,10 +8,11 @@ import {
|
||||
uploadFilePromise
|
||||
} from '@nhost/nhost-js'
|
||||
import { useInterpret, useSelector } from '@xstate/vue'
|
||||
import { ToRefs } from 'vue'
|
||||
import { InterpreterFrom } from 'xstate'
|
||||
import { useNhostClient } from './useNhostClient'
|
||||
|
||||
export interface FileUploadComposableResult extends FileUploadState {
|
||||
export interface FileUploadComposableResult extends ToRefs<FileUploadState> {
|
||||
/**
|
||||
* Add the file without uploading it.
|
||||
*/
|
||||
@@ -38,21 +39,41 @@ export type { FileItemRef }
|
||||
/**
|
||||
* Use the composable `useFileUploadItem` to control the file upload of a file in a multiple file upload.
|
||||
*
|
||||
* It has the same signature as `useFileUpload`.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const Item = ({itemRef}) => {
|
||||
* const { name, progress} = useFileUploadItem(itemRef)
|
||||
* return <li>{name} {progress}</li>
|
||||
* }
|
||||
* ```vue
|
||||
* <!-- Parent component or page -->
|
||||
*
|
||||
* const List = () => {
|
||||
* const { list } = useMultipleFilesUpload()
|
||||
* return <ul>
|
||||
* {list.map((itemRef) => <Item key={item.id} itemRef={item} />)}
|
||||
* </ul>
|
||||
* }
|
||||
* <script lang="ts" setup>
|
||||
* const { files } = useMultipleFilesUpload()
|
||||
* <script lang="ts" setup>
|
||||
*
|
||||
* <template>
|
||||
* <div v-for="(file, index) of files" :key="index">
|
||||
* <FileUploadItem :file="file" />
|
||||
* </div>
|
||||
* </template>
|
||||
*
|
||||
*
|
||||
* <!-- FileUploadItem component -->
|
||||
*
|
||||
* <script lang="ts" setup>
|
||||
* import { FileItemRef } from '@nhost/nhost-js'
|
||||
* import { useFileUploadItem } from '@nhost/vue'
|
||||
*
|
||||
* const { file } = defineProps<{ file: FileItemRef }>()
|
||||
*
|
||||
* const { name, progress } = useFileUploadItem(file)
|
||||
* </script>
|
||||
*
|
||||
* <template>
|
||||
* <div>
|
||||
* <span>{{ name }}</span>
|
||||
* <v-progress-linear v-model="progress">
|
||||
* {{ progress }}
|
||||
* </v-progress-linear>
|
||||
* </div>
|
||||
* </template>
|
||||
*
|
||||
* ```
|
||||
*/
|
||||
@@ -65,7 +86,7 @@ export const useFileUploadItem = (
|
||||
ref.send({
|
||||
type: 'ADD',
|
||||
file: params.file,
|
||||
bucketId: params.bucketId || bucketId
|
||||
bucketId: params.bucketId || bucketId.value
|
||||
})
|
||||
}
|
||||
|
||||
@@ -88,14 +109,14 @@ export const useFileUploadItem = (
|
||||
ref.send('DESTROY')
|
||||
}
|
||||
|
||||
const isUploading = useSelector(ref, (state) => state.matches('uploading')).value
|
||||
const isUploaded = useSelector(ref, (state) => state.matches('uploaded')).value
|
||||
const isError = useSelector(ref, (state) => state.matches('error')).value
|
||||
const error = useSelector(ref, (state) => state.context.error || null).value
|
||||
const progress = useSelector(ref, (state) => state.context.progress).value
|
||||
const id = useSelector(ref, (state) => state.context.id).value
|
||||
const bucketId = useSelector(ref, (state) => state.context.bucketId).value
|
||||
const name = useSelector(ref, (state) => state.context.file?.name).value
|
||||
const isUploading = useSelector(ref, (state) => state.matches('uploading'))
|
||||
const isUploaded = useSelector(ref, (state) => state.matches('uploaded'))
|
||||
const isError = useSelector(ref, (state) => state.matches('error'))
|
||||
const error = useSelector(ref, (state) => state.context.error || null)
|
||||
const progress = useSelector(ref, (state) => state.context.progress)
|
||||
const id = useSelector(ref, (state) => state.context.id)
|
||||
const bucketId = useSelector(ref, (state) => state.context.bucketId)
|
||||
const name = useSelector(ref, (state) => state.context.file?.name)
|
||||
|
||||
return {
|
||||
add,
|
||||
@@ -117,7 +138,7 @@ export const useFileUploadItem = (
|
||||
* Use the composable `useFileUpload` to upload a file.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* ```ts
|
||||
* const { add,
|
||||
* upload,
|
||||
* cancel,
|
||||
|
||||
117
packages/vue/src/useMultipleFilesUpload.ts
Normal file
117
packages/vue/src/useMultipleFilesUpload.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import {
|
||||
createMultipleFilesUploadMachine,
|
||||
FileItemRef,
|
||||
MultipleFilesHandlerResult,
|
||||
MultipleFilesUploadState,
|
||||
UploadMultipleFilesActionParams,
|
||||
uploadMultipleFilesPromise
|
||||
} from '@nhost/nhost-js'
|
||||
import { useInterpret, useSelector } from '@xstate/vue'
|
||||
import { Ref, ref, ToRefs } from 'vue'
|
||||
import { useNhostClient } from './useNhostClient'
|
||||
|
||||
export interface MultipleFilesUploadComposableResult extends ToRefs<MultipleFilesUploadState> {
|
||||
/**
|
||||
* Add one or multiple files to add to the list of files to upload.
|
||||
*/
|
||||
add: (
|
||||
params: Required<Pick<UploadMultipleFilesActionParams, 'files'>> &
|
||||
UploadMultipleFilesActionParams
|
||||
) => void
|
||||
/**
|
||||
* Upload the files that has been previously added to the list.
|
||||
*/
|
||||
upload: (params?: UploadMultipleFilesActionParams) => Promise<MultipleFilesHandlerResult>
|
||||
/**
|
||||
* Cancel the ongoing upload. The files that have been successfully uploaded will not be deleted from the server.
|
||||
*/
|
||||
cancel: () => void
|
||||
/**
|
||||
* Clear the list of files.
|
||||
*/
|
||||
clear: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the composable `useMultipleFilesUpload` to upload multiple files.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const {
|
||||
* add,
|
||||
* upload
|
||||
* } = useMultipleFilesUpload()
|
||||
*
|
||||
* const addFiles = async (files) => {
|
||||
* add({files})
|
||||
* }
|
||||
*
|
||||
* const handleSubmit = async (e) => {
|
||||
* e.preventDefault()
|
||||
* await upload()
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @docs https://docs.nhost.io/reference/vue/use-multiple-files-upload
|
||||
*/
|
||||
export const useMultipleFilesUpload = (): MultipleFilesUploadComposableResult => {
|
||||
const { nhost } = useNhostClient()
|
||||
const errors: Ref<FileItemRef[]> = ref([])
|
||||
|
||||
const service = useInterpret(createMultipleFilesUploadMachine, {}, (state) => {
|
||||
if (state.event.type === 'UPLOAD_ERROR') {
|
||||
errors.value = state.context.files.filter((ref) => ref.getSnapshot()?.context.error)
|
||||
} else if (
|
||||
(state.matches('uploaded') || state.event.type === 'CLEAR') &&
|
||||
errors.value.length > 0
|
||||
) {
|
||||
errors.value = []
|
||||
}
|
||||
})
|
||||
|
||||
const add = (
|
||||
params: Required<Pick<UploadMultipleFilesActionParams, 'files'>> &
|
||||
UploadMultipleFilesActionParams
|
||||
) => {
|
||||
service.send({ type: 'ADD', ...params })
|
||||
}
|
||||
|
||||
const upload = (params?: UploadMultipleFilesActionParams) =>
|
||||
uploadMultipleFilesPromise(
|
||||
{
|
||||
url: nhost.storage.url,
|
||||
accessToken: nhost.auth.getAccessToken(),
|
||||
adminSecret: nhost.adminSecret,
|
||||
...params
|
||||
},
|
||||
service
|
||||
)
|
||||
|
||||
const cancel = () => {
|
||||
service.send('CANCEL')
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
service.send('CLEAR')
|
||||
}
|
||||
|
||||
const isUploading = useSelector(service, (state) => state.matches('uploading'))
|
||||
const isUploaded = useSelector(service, (state) => state.matches('uploaded'))
|
||||
const isError = useSelector(service, (state) => state.matches('error'))
|
||||
|
||||
const progress = useSelector(service, (state) => state.context.progress)
|
||||
const files = useSelector(service, (state) => state.context.files)
|
||||
|
||||
return {
|
||||
upload,
|
||||
add,
|
||||
clear,
|
||||
cancel,
|
||||
progress,
|
||||
isUploaded,
|
||||
isUploading,
|
||||
files,
|
||||
isError,
|
||||
errors
|
||||
}
|
||||
}
|
||||
613
pnpm-lock.yaml
generated
613
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user