mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-14 21:10:34 +01:00
Teams refactor: removed team websites.
This commit is contained in:
parent
0d442b751d
commit
f85393f8df
@ -67,7 +67,7 @@
|
|||||||
"@prisma/extension-read-replicas": "^0.3.0",
|
"@prisma/extension-read-replicas": "^0.3.0",
|
||||||
"@react-spring/web": "^9.7.3",
|
"@react-spring/web": "^9.7.3",
|
||||||
"@tanstack/react-query": "^5.12.2",
|
"@tanstack/react-query": "^5.12.2",
|
||||||
"@umami/prisma-client": "^0.8.0",
|
"@umami/prisma-client": "^0.13.0",
|
||||||
"@umami/redis-client": "^0.18.0",
|
"@umami/redis-client": "^0.18.0",
|
||||||
"chalk": "^4.1.1",
|
"chalk": "^4.1.1",
|
||||||
"chart.js": "^4.2.1",
|
"chart.js": "^4.2.1",
|
||||||
|
@ -17,6 +17,12 @@ export function TeamsTable({ data = [] }: { data: any[] }) {
|
|||||||
<GridColumn name="owner" label={formatMessage(labels.owner)}>
|
<GridColumn name="owner" label={formatMessage(labels.owner)}>
|
||||||
{row => row.teamUser.find(({ role }) => role === ROLES.teamOwner)?.user?.username}
|
{row => row.teamUser.find(({ role }) => role === ROLES.teamOwner)?.user?.username}
|
||||||
</GridColumn>
|
</GridColumn>
|
||||||
|
<GridColumn name="websites" label={formatMessage(labels.websites)}>
|
||||||
|
{row => row._count.website}
|
||||||
|
</GridColumn>
|
||||||
|
<GridColumn name="members" label={formatMessage(labels.members)}>
|
||||||
|
{row => row._count.teamUser}
|
||||||
|
</GridColumn>
|
||||||
<GridColumn name="action" label=" " alignment="end">
|
<GridColumn name="action" label=" " alignment="end">
|
||||||
{row => {
|
{row => {
|
||||||
const { id, name, teamUser } = row;
|
const { id, name, teamUser } = row;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import useApi from 'components/hooks/useApi';
|
import useApi from 'components/hooks/useApi';
|
||||||
import TeamMembersTable from './TeamMembersTable';
|
|
||||||
import useFilterQuery from 'components/hooks/useFilterQuery';
|
import useFilterQuery from 'components/hooks/useFilterQuery';
|
||||||
import DataTable from 'components/common/DataTable';
|
import DataTable from 'components/common/DataTable';
|
||||||
import useCache from 'store/cache';
|
import useCache from 'store/cache';
|
||||||
|
import TeamMembersTable from './TeamMembersTable';
|
||||||
|
|
||||||
export function TeamMembers({ teamId, readOnly }: { teamId: string; readOnly: boolean }) {
|
export function TeamMembers({ teamId, readOnly }: { teamId: string; readOnly: boolean }) {
|
||||||
const { get } = useApi();
|
const { get } = useApi();
|
||||||
@ -18,11 +18,9 @@ export function TeamMembers({ teamId, readOnly }: { teamId: string; readOnly: bo
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DataTable queryResult={queryResult}>
|
||||||
<DataTable queryResult={queryResult}>
|
{({ data }) => <TeamMembersTable data={data} teamId={teamId} readOnly={readOnly} />}
|
||||||
{({ data }) => <TeamMembersTable data={data} teamId={teamId} readOnly={readOnly} />}
|
</DataTable>
|
||||||
</DataTable>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@ export function TeamSettings({ teamId }: { teamId: string }) {
|
|||||||
return get(`/teams/${teamId}`);
|
return get(`/teams/${teamId}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
gcTime: 0,
|
|
||||||
});
|
});
|
||||||
const canEdit = data?.teamUser?.find(
|
const canEdit = data?.teamUser?.find(
|
||||||
({ userId, role }) => role === ROLES.teamOwner && userId === user.id,
|
({ userId, role }) => role === ROLES.teamOwner && userId === user.id,
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
import useApi from 'components/hooks/useApi';
|
|
||||||
import { useState } from 'react';
|
|
||||||
import { Button, Form, FormButtons, GridColumn, Loading, SubmitButton, Toggle } from 'react-basics';
|
|
||||||
import useMessages from 'components/hooks/useMessages';
|
|
||||||
import WebsitesDataTable from 'app/(main)/settings/websites/WebsitesDataTable';
|
|
||||||
import Empty from 'components/common/Empty';
|
|
||||||
import { setValue } from 'store/cache';
|
|
||||||
import { useUser } from 'components/hooks';
|
|
||||||
|
|
||||||
export function TeamWebsiteAddForm({
|
|
||||||
teamId,
|
|
||||||
onSave,
|
|
||||||
onClose,
|
|
||||||
}: {
|
|
||||||
teamId: string;
|
|
||||||
onSave: () => void;
|
|
||||||
onClose: () => void;
|
|
||||||
}) {
|
|
||||||
const { user } = useUser();
|
|
||||||
const { formatMessage, labels } = useMessages();
|
|
||||||
const { get, post, useQuery, useMutation } = useApi();
|
|
||||||
const { mutate, error } = useMutation({
|
|
||||||
mutationFn: (data: any) => post(`/teams/${teamId}/websites`, data),
|
|
||||||
});
|
|
||||||
const { data: websites, isLoading } = useQuery({
|
|
||||||
queryKey: ['websites'],
|
|
||||||
queryFn: () => get('/websites'),
|
|
||||||
});
|
|
||||||
const [selected, setSelected] = useState([]);
|
|
||||||
const hasData = websites && websites.data.length > 0;
|
|
||||||
|
|
||||||
const handleSubmit = () => {
|
|
||||||
mutate(
|
|
||||||
{ websiteIds: selected },
|
|
||||||
{
|
|
||||||
onSuccess: async () => {
|
|
||||||
setValue('team:websites', Date.now());
|
|
||||||
onSave?.();
|
|
||||||
onClose?.();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSelect = id => {
|
|
||||||
setSelected(state => (state.includes(id) ? state.filter(n => n !== id) : state.concat(id)));
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{isLoading && !hasData && <Loading icon="dots" position="center" />}
|
|
||||||
{!isLoading && !hasData && <Empty />}
|
|
||||||
{hasData && (
|
|
||||||
<Form onSubmit={handleSubmit} error={error}>
|
|
||||||
<WebsitesDataTable userId={user.id} showActions={false}>
|
|
||||||
<GridColumn name="select" label={formatMessage(labels.selectWebsite)} alignment="end">
|
|
||||||
{row => (
|
|
||||||
<Toggle
|
|
||||||
key={row.id}
|
|
||||||
value={row.id}
|
|
||||||
checked={selected?.includes(row.id)}
|
|
||||||
onChange={handleSelect.bind(null, row.id)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</GridColumn>
|
|
||||||
</WebsitesDataTable>
|
|
||||||
<FormButtons flex>
|
|
||||||
<SubmitButton variant="primary" disabled={selected?.length === 0}>
|
|
||||||
{formatMessage(labels.addWebsite)}
|
|
||||||
</SubmitButton>
|
|
||||||
<Button onClick={onClose}>{formatMessage(labels.cancel)}</Button>
|
|
||||||
</FormButtons>
|
|
||||||
</Form>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TeamWebsiteAddForm;
|
|
@ -1,13 +1,13 @@
|
|||||||
import useFilterQuery from 'components/hooks/useFilterQuery';
|
import WebsitesTable from 'app/(main)/settings/websites/WebsitesTable';
|
||||||
import DataTable from 'components/common/DataTable';
|
import DataTable from 'components/common/DataTable';
|
||||||
|
import useFilterQuery from 'components/hooks/useFilterQuery';
|
||||||
import useApi from 'components/hooks/useApi';
|
import useApi from 'components/hooks/useApi';
|
||||||
import useUser from 'components/hooks/useUser';
|
import useUser from 'components/hooks/useUser';
|
||||||
import useCache from 'store/cache';
|
import useCache from 'store/cache';
|
||||||
import WebsitesTable from '../../websites/WebsitesTable';
|
|
||||||
|
|
||||||
export function TeamWebsites({ teamId }: { teamId: string; readOnly: boolean }) {
|
export function TeamWebsites({ teamId }: { teamId: string; readOnly: boolean }) {
|
||||||
const { user } = useUser();
|
|
||||||
const { get } = useApi();
|
const { get } = useApi();
|
||||||
|
const { user } = useUser();
|
||||||
const modified = useCache(state => state?.['team:websites']);
|
const modified = useCache(state => state?.['team:websites']);
|
||||||
const queryResult = useFilterQuery({
|
const queryResult = useFilterQuery({
|
||||||
queryKey: ['team:websites', { teamId, modified }],
|
queryKey: ['team:websites', { teamId, modified }],
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
import { Metadata } from 'next';
|
||||||
import TeamsDataTable from './TeamsDataTable';
|
import TeamsDataTable from './TeamsDataTable';
|
||||||
import TeamsHeader from './TeamsHeader';
|
import TeamsHeader from './TeamsHeader';
|
||||||
import { Metadata } from 'next';
|
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
if (process.env.cloudMode) {
|
if (process.env.cloudMode) {
|
||||||
@ -16,5 +16,5 @@ export default function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Teams Settings | umami',
|
title: 'Teams Settings - Umami',
|
||||||
};
|
};
|
||||||
|
@ -3,10 +3,9 @@ import useApi from 'components/hooks/useApi';
|
|||||||
import useFilterQuery from 'components/hooks/useFilterQuery';
|
import useFilterQuery from 'components/hooks/useFilterQuery';
|
||||||
import DataTable from 'components/common/DataTable';
|
import DataTable from 'components/common/DataTable';
|
||||||
import UsersTable from './UsersTable';
|
import UsersTable from './UsersTable';
|
||||||
import UsersHeader from './UsersHeader';
|
|
||||||
import useCache from 'store/cache';
|
import useCache from 'store/cache';
|
||||||
|
|
||||||
export function UsersDataTable() {
|
export function UsersDataTable({ showActions }: { showActions: boolean }) {
|
||||||
const { get } = useApi();
|
const { get } = useApi();
|
||||||
const modified = useCache((state: any) => state?.users);
|
const modified = useCache((state: any) => state?.users);
|
||||||
const queryResult = useFilterQuery({
|
const queryResult = useFilterQuery({
|
||||||
@ -15,10 +14,9 @@ export function UsersDataTable() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<DataTable queryResult={queryResult}>
|
||||||
<UsersHeader />
|
{({ data }) => <UsersTable data={data} showActions={showActions} />}
|
||||||
<DataTable queryResult={queryResult}>{({ data }) => <UsersTable data={data} />}</DataTable>
|
</DataTable>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,13 @@ import useMessages from 'components/hooks/useMessages';
|
|||||||
import useLocale from 'components/hooks/useLocale';
|
import useLocale from 'components/hooks/useLocale';
|
||||||
import UserDeleteButton from './UserDeleteButton';
|
import UserDeleteButton from './UserDeleteButton';
|
||||||
|
|
||||||
export function UsersTable({ data = [] }: { data: any[] }) {
|
export function UsersTable({
|
||||||
|
data = [],
|
||||||
|
showActions = true,
|
||||||
|
}: {
|
||||||
|
data: any[];
|
||||||
|
showActions?: boolean;
|
||||||
|
}) {
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const { dateLocale } = useLocale();
|
const { dateLocale } = useLocale();
|
||||||
const breakpoint = useBreakpoint();
|
const breakpoint = useBreakpoint();
|
||||||
@ -29,24 +35,26 @@ export function UsersTable({ data = [] }: { data: any[] }) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
</GridColumn>
|
</GridColumn>
|
||||||
<GridColumn name="action" label=" " alignment="end">
|
{showActions && (
|
||||||
{row => {
|
<GridColumn name="action" label=" " alignment="end">
|
||||||
const { id, username } = row;
|
{row => {
|
||||||
return (
|
const { id, username } = row;
|
||||||
<>
|
return (
|
||||||
<Link href={`/settings/users/${id}`}>
|
<>
|
||||||
<Button>
|
<Link href={`/settings/users/${id}`}>
|
||||||
<Icon>
|
<Button>
|
||||||
<Icons.Edit />
|
<Icon>
|
||||||
</Icon>
|
<Icons.Edit />
|
||||||
<Text>{formatMessage(labels.edit)}</Text>
|
</Icon>
|
||||||
</Button>
|
<Text>{formatMessage(labels.edit)}</Text>
|
||||||
</Link>
|
</Button>
|
||||||
<UserDeleteButton userId={id} username={username} />
|
</Link>
|
||||||
</>
|
<UserDeleteButton userId={id} username={username} />
|
||||||
);
|
</>
|
||||||
}}
|
);
|
||||||
</GridColumn>
|
}}
|
||||||
|
</GridColumn>
|
||||||
|
)}
|
||||||
</GridTable>
|
</GridTable>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
import UsersDataTable from './UsersDataTable';
|
|
||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
|
import UsersDataTable from './UsersDataTable';
|
||||||
|
import UsersHeader from './UsersHeader';
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
return <UsersDataTable />;
|
return (
|
||||||
|
<>
|
||||||
|
<UsersHeader />
|
||||||
|
<UsersDataTable />
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Users | umami',
|
title: 'Users | umami',
|
||||||
|
@ -52,6 +52,7 @@ export const labels = defineMessages({
|
|||||||
deleteWebsite: { id: 'label.delete-website', defaultMessage: 'Delete website' },
|
deleteWebsite: { id: 'label.delete-website', defaultMessage: 'Delete website' },
|
||||||
reset: { id: 'label.reset', defaultMessage: 'Reset' },
|
reset: { id: 'label.reset', defaultMessage: 'Reset' },
|
||||||
addWebsite: { id: 'label.add-website', defaultMessage: 'Add website' },
|
addWebsite: { id: 'label.add-website', defaultMessage: 'Add website' },
|
||||||
|
addMember: { id: 'label.add-member', defaultMessage: 'Add member' },
|
||||||
addDescription: { id: 'label.add-description', defaultMessage: 'Add description' },
|
addDescription: { id: 'label.add-description', defaultMessage: 'Add description' },
|
||||||
changePassword: { id: 'label.change-password', defaultMessage: 'Change password' },
|
changePassword: { id: 'label.change-password', defaultMessage: 'Change password' },
|
||||||
currentPassword: { id: 'label.current-password', defaultMessage: 'Current password' },
|
currentPassword: { id: 'label.current-password', defaultMessage: 'Current password' },
|
||||||
|
@ -18,7 +18,6 @@ export * from 'components/hooks/useTimezone';
|
|||||||
export * from 'components/hooks/useUser';
|
export * from 'components/hooks/useUser';
|
||||||
export * from 'components/hooks/useWebsite';
|
export * from 'components/hooks/useWebsite';
|
||||||
|
|
||||||
export * from 'app/(main)/settings/teams/[id]/TeamWebsiteAddForm';
|
|
||||||
export * from 'app/(main)/settings/teams/[id]/TeamEditForm';
|
export * from 'app/(main)/settings/teams/[id]/TeamEditForm';
|
||||||
export * from 'app/(main)/settings/teams/[id]/TeamMemberRemoveButton';
|
export * from 'app/(main)/settings/teams/[id]/TeamMemberRemoveButton';
|
||||||
export * from 'app/(main)/settings/teams/[id]/TeamMembers';
|
export * from 'app/(main)/settings/teams/[id]/TeamMembers';
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { Report } from '@prisma/client';
|
import { Report } from '@prisma/client';
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
import redis from '@umami/redis-client';
|
import redis from '@umami/redis-client';
|
||||||
import { PERMISSIONS, ROLE_PERMISSIONS, SHARE_TOKEN_HEADER } from 'lib/constants';
|
import { PERMISSIONS, ROLE_PERMISSIONS, ROLES, SHARE_TOKEN_HEADER } from 'lib/constants';
|
||||||
import { secret } from 'lib/crypto';
|
import { secret } from 'lib/crypto';
|
||||||
import { createSecureToken, ensureArray, getRandomChars, parseToken } from 'next-basics';
|
import { createSecureToken, ensureArray, getRandomChars, parseToken } from 'next-basics';
|
||||||
import { findTeamWebsiteByUserId, getTeamUser, getTeamWebsite } from 'queries';
|
import { getTeamUser, getWebsiteById } from 'queries';
|
||||||
import { loadWebsite } from './load';
|
import { loadWebsite } from './load';
|
||||||
import { Auth } from './types';
|
import { Auth } from './types';
|
||||||
import { NextApiRequest } from 'next';
|
import { NextApiRequest } from 'next';
|
||||||
@ -55,8 +55,6 @@ export async function canViewWebsite({ user, shareToken }: Auth, websiteId: stri
|
|||||||
if (user.id === website?.userId) {
|
if (user.id === website?.userId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!(await findTeamWebsiteByUserId(websiteId, user.id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function canViewAllWebsites({ user }: Auth) {
|
export async function canViewAllWebsites({ user }: Auth) {
|
||||||
@ -178,16 +176,12 @@ export async function canDeleteTeamWebsite({ user }: Auth, teamId: string, websi
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const teamWebsite = await getTeamWebsite(teamId, websiteId);
|
const teamWebsite = await getWebsiteById(websiteId);
|
||||||
|
|
||||||
if (teamWebsite?.website?.userId === user.id) {
|
if (teamWebsite && teamWebsite.teamId === teamId) {
|
||||||
return true;
|
const teamUser = await getTeamUser(teamId, user.id);
|
||||||
}
|
|
||||||
|
|
||||||
if (teamWebsite) {
|
return teamUser.role === ROLES.teamOwner || teamUser.role === ROLES.teamMember;
|
||||||
const teamUser = await getTeamUser(teamWebsite.teamId, user.id);
|
|
||||||
|
|
||||||
return hasPermission(teamUser.role, PERMISSIONS.teamUpdate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -125,6 +125,7 @@ export const ROLES = {
|
|||||||
viewOnly: 'view-only',
|
viewOnly: 'view-only',
|
||||||
teamOwner: 'team-owner',
|
teamOwner: 'team-owner',
|
||||||
teamMember: 'team-member',
|
teamMember: 'team-member',
|
||||||
|
teamGuest: 'team-guest',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const PERMISSIONS = {
|
export const PERMISSIONS = {
|
||||||
|
@ -68,7 +68,12 @@ export default async (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
log(`Login from ip ${getIpAddress(req)} with username "${username.replace(/["\r\n]/g, '')}" failed.`);
|
log(
|
||||||
|
`Login from ip ${getIpAddress(req)} with username "${username.replace(
|
||||||
|
/["\r\n]/g,
|
||||||
|
'',
|
||||||
|
)}" failed.`,
|
||||||
|
);
|
||||||
|
|
||||||
return unauthorized(res, 'message.incorrect-username-password');
|
return unauthorized(res, 'message.incorrect-username-password');
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import { pageInfo } from 'lib/schema';
|
|||||||
import { NextApiResponse } from 'next';
|
import { NextApiResponse } from 'next';
|
||||||
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
|
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
|
||||||
import { getWebsitesByTeamId } from 'queries';
|
import { getWebsitesByTeamId } from 'queries';
|
||||||
import { createTeamWebsites } from 'queries/admin/teamWebsite';
|
|
||||||
|
|
||||||
export interface TeamWebsiteRequestQuery extends SearchFilter {
|
export interface TeamWebsiteRequestQuery extends SearchFilter {
|
||||||
id: string;
|
id: string;
|
||||||
@ -52,17 +51,5 @@ export default async (
|
|||||||
return ok(res, websites);
|
return ok(res, websites);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.method === 'POST') {
|
|
||||||
if (!(await canViewTeam(req.auth, teamId))) {
|
|
||||||
return unauthorized(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { websiteIds } = req.body;
|
|
||||||
|
|
||||||
const websites = await createTeamWebsites(teamId, websiteIds);
|
|
||||||
|
|
||||||
return ok(res, websites);
|
|
||||||
}
|
|
||||||
|
|
||||||
return methodNotAllowed(res);
|
return methodNotAllowed(res);
|
||||||
};
|
};
|
||||||
|
@ -10,8 +10,9 @@ export interface GetTeamOptions {
|
|||||||
|
|
||||||
async function getTeam(where: Prisma.TeamWhereInput, options: GetTeamOptions = {}): Promise<Team> {
|
async function getTeam(where: Prisma.TeamWhereInput, options: GetTeamOptions = {}): Promise<Team> {
|
||||||
const { includeTeamUser = false } = options;
|
const { includeTeamUser = false } = options;
|
||||||
|
const { client } = prisma;
|
||||||
|
|
||||||
return prisma.client.team.findFirst({
|
return client.team.findFirst({
|
||||||
where,
|
where,
|
||||||
include: {
|
include: {
|
||||||
teamUser: includeTeamUser,
|
teamUser: includeTeamUser,
|
||||||
@ -27,14 +28,15 @@ export function getTeamByAccessCode(accessCode: string, options: GetTeamOptions
|
|||||||
return getTeam({ accessCode }, options);
|
return getTeam({ accessCode }, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createTeam(data: Prisma.TeamCreateInput, userId: string): Promise<Team> {
|
export async function createTeam(data: Prisma.TeamCreateInput, userId: string): Promise<any> {
|
||||||
const { id } = data;
|
const { id } = data;
|
||||||
|
const { client, transaction } = prisma;
|
||||||
|
|
||||||
return prisma.transaction([
|
return transaction([
|
||||||
prisma.client.team.create({
|
client.team.create({
|
||||||
data,
|
data,
|
||||||
}),
|
}),
|
||||||
prisma.client.teamUser.create({
|
client.teamUser.create({
|
||||||
data: {
|
data: {
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
teamId: id,
|
teamId: id,
|
||||||
@ -46,7 +48,9 @@ export async function createTeam(data: Prisma.TeamCreateInput, userId: string):
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function updateTeam(teamId: string, data: Prisma.TeamUpdateInput): Promise<Team> {
|
export async function updateTeam(teamId: string, data: Prisma.TeamUpdateInput): Promise<Team> {
|
||||||
return prisma.client.team.update({
|
const { client } = prisma;
|
||||||
|
|
||||||
|
return client.team.update({
|
||||||
where: {
|
where: {
|
||||||
id: teamId,
|
id: teamId,
|
||||||
},
|
},
|
||||||
@ -61,13 +65,22 @@ export async function deleteTeam(
|
|||||||
teamId: string,
|
teamId: string,
|
||||||
): Promise<Promise<[Prisma.BatchPayload, Prisma.BatchPayload, Team]>> {
|
): Promise<Promise<[Prisma.BatchPayload, Prisma.BatchPayload, Team]>> {
|
||||||
const { client, transaction } = prisma;
|
const { client, transaction } = prisma;
|
||||||
|
const cloudMode = process.env.CLOUD_MODE;
|
||||||
|
|
||||||
|
if (cloudMode) {
|
||||||
|
return transaction([
|
||||||
|
client.team.update({
|
||||||
|
data: {
|
||||||
|
deletedAt: new Date(),
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
id: teamId,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
return transaction([
|
return transaction([
|
||||||
client.teamWebsite.deleteMany({
|
|
||||||
where: {
|
|
||||||
teamId,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
client.teamUser.deleteMany({
|
client.teamUser.deleteMany({
|
||||||
where: {
|
where: {
|
||||||
teamId,
|
teamId,
|
||||||
@ -87,6 +100,7 @@ export async function getTeams(
|
|||||||
): Promise<FilterResult<Team[]>> {
|
): Promise<FilterResult<Team[]>> {
|
||||||
const { userId, query } = filters;
|
const { userId, query } = filters;
|
||||||
const mode = prisma.getQueryMode();
|
const mode = prisma.getQueryMode();
|
||||||
|
const { client } = prisma;
|
||||||
|
|
||||||
const where: Prisma.TeamWhereInput = {
|
const where: Prisma.TeamWhereInput = {
|
||||||
...(userId && {
|
...(userId && {
|
||||||
@ -123,7 +137,7 @@ export async function getTeams(
|
|||||||
...filters,
|
...filters,
|
||||||
});
|
});
|
||||||
|
|
||||||
const teams = await prisma.client.team.findMany({
|
const teams = await client.team.findMany({
|
||||||
where: {
|
where: {
|
||||||
...where,
|
...where,
|
||||||
},
|
},
|
||||||
@ -131,7 +145,7 @@ export async function getTeams(
|
|||||||
...(options?.include && { include: options?.include }),
|
...(options?.include && { include: options?.include }),
|
||||||
});
|
});
|
||||||
|
|
||||||
const count = await prisma.client.team.count({ where });
|
const count = await client.team.count({ where });
|
||||||
|
|
||||||
return { data: teams, count, ...getParameters };
|
return { data: teams, count, ...getParameters };
|
||||||
}
|
}
|
||||||
@ -154,6 +168,9 @@ export async function getTeamsByUserId(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
_count: {
|
||||||
|
select: { website: true, teamUser: true },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -68,14 +68,6 @@ export async function deleteTeamUser(teamId: string, userId: string): Promise<Te
|
|||||||
const { client, transaction } = prisma;
|
const { client, transaction } = prisma;
|
||||||
|
|
||||||
return transaction([
|
return transaction([
|
||||||
client.teamWebsite.deleteMany({
|
|
||||||
where: {
|
|
||||||
teamId: teamId,
|
|
||||||
website: {
|
|
||||||
userId: userId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
client.teamUser.deleteMany({
|
client.teamUser.deleteMany({
|
||||||
where: {
|
where: {
|
||||||
teamId,
|
teamId,
|
||||||
|
@ -1,127 +0,0 @@
|
|||||||
import { Prisma, Team, TeamUser, TeamWebsite, Website } from '@prisma/client';
|
|
||||||
import { ROLES } from 'lib/constants';
|
|
||||||
import { uuid } from 'lib/crypto';
|
|
||||||
import prisma from 'lib/prisma';
|
|
||||||
|
|
||||||
export async function getTeamWebsite(
|
|
||||||
teamId: string,
|
|
||||||
websiteId: string,
|
|
||||||
): Promise<
|
|
||||||
TeamWebsite & {
|
|
||||||
website: Website;
|
|
||||||
}
|
|
||||||
> {
|
|
||||||
return prisma.client.teamWebsite.findFirst({
|
|
||||||
where: {
|
|
||||||
teamId,
|
|
||||||
websiteId,
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
website: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function findTeamWebsiteByUserId(
|
|
||||||
websiteId: string,
|
|
||||||
userId: string,
|
|
||||||
): Promise<TeamWebsite> {
|
|
||||||
return prisma.client.teamWebsite.findFirst({
|
|
||||||
where: {
|
|
||||||
websiteId,
|
|
||||||
team: {
|
|
||||||
teamUser: {
|
|
||||||
some: {
|
|
||||||
userId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getTeamWebsites(teamId: string): Promise<
|
|
||||||
(TeamWebsite & {
|
|
||||||
team: Team & { teamUser: TeamUser[] };
|
|
||||||
website: Website & {
|
|
||||||
user: { id: string; username: string };
|
|
||||||
};
|
|
||||||
})[]
|
|
||||||
> {
|
|
||||||
return prisma.client.teamWebsite.findMany({
|
|
||||||
where: {
|
|
||||||
teamId,
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
team: {
|
|
||||||
include: {
|
|
||||||
teamUser: {
|
|
||||||
where: {
|
|
||||||
role: ROLES.teamOwner,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
website: {
|
|
||||||
include: {
|
|
||||||
user: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
username: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
orderBy: [
|
|
||||||
{
|
|
||||||
team: {
|
|
||||||
name: 'asc',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createTeamWebsite(teamId: string, websiteId: string): Promise<TeamWebsite> {
|
|
||||||
return prisma.client.teamWebsite.create({
|
|
||||||
data: {
|
|
||||||
id: uuid(),
|
|
||||||
teamId,
|
|
||||||
websiteId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createTeamWebsites(teamId: string, websiteIds: string[]) {
|
|
||||||
const currentTeamWebsites = await getTeamWebsites(teamId);
|
|
||||||
|
|
||||||
// filter out websites that already exists on the team
|
|
||||||
const addWebsites = websiteIds.filter(
|
|
||||||
websiteId => !currentTeamWebsites.some(a => a.websiteId === websiteId),
|
|
||||||
);
|
|
||||||
|
|
||||||
const teamWebsites: Prisma.TeamWebsiteCreateManyInput[] = addWebsites.map(a => {
|
|
||||||
return {
|
|
||||||
id: uuid(),
|
|
||||||
teamId,
|
|
||||||
websiteId: a,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return prisma.client.teamWebsite.createMany({
|
|
||||||
data: teamWebsites,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function deleteTeamWebsite(
|
|
||||||
teamId: string,
|
|
||||||
websiteId: string,
|
|
||||||
): Promise<Prisma.BatchPayload> {
|
|
||||||
return prisma.client.teamWebsite.deleteMany({
|
|
||||||
where: {
|
|
||||||
teamId,
|
|
||||||
websiteId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
@ -105,6 +105,7 @@ export async function getUsersByTeamId(teamId: string, filter?: UserSearchFilter
|
|||||||
include: {
|
include: {
|
||||||
teamUser: {
|
teamUser: {
|
||||||
select: {
|
select: {
|
||||||
|
teamId: true,
|
||||||
role: true,
|
role: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -188,7 +189,27 @@ export async function deleteUser(
|
|||||||
|
|
||||||
const teamIds = teams.map(a => a.id);
|
const teamIds = teams.map(a => a.id);
|
||||||
|
|
||||||
return prisma
|
if (cloudMode) {
|
||||||
|
return client.transaction([
|
||||||
|
client.website.updateMany({
|
||||||
|
data: {
|
||||||
|
deletedAt: new Date(),
|
||||||
|
},
|
||||||
|
where: { id: { in: websiteIds } },
|
||||||
|
}),
|
||||||
|
client.user.update({
|
||||||
|
data: {
|
||||||
|
username: getRandomChars(32),
|
||||||
|
deletedAt: new Date(),
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return client
|
||||||
.transaction([
|
.transaction([
|
||||||
client.eventData.deleteMany({
|
client.eventData.deleteMany({
|
||||||
where: { websiteId: { in: websiteIds } },
|
where: { websiteId: { in: websiteIds } },
|
||||||
@ -199,29 +220,6 @@ export async function deleteUser(
|
|||||||
client.session.deleteMany({
|
client.session.deleteMany({
|
||||||
where: { websiteId: { in: websiteIds } },
|
where: { websiteId: { in: websiteIds } },
|
||||||
}),
|
}),
|
||||||
client.teamWebsite.deleteMany({
|
|
||||||
where: {
|
|
||||||
OR: [
|
|
||||||
{
|
|
||||||
websiteId: {
|
|
||||||
in: websiteIds,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
teamId: {
|
|
||||||
in: teamIds,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
client.teamWebsite.deleteMany({
|
|
||||||
where: {
|
|
||||||
teamId: {
|
|
||||||
in: teamIds,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
client.teamUser.deleteMany({
|
client.teamUser.deleteMany({
|
||||||
where: {
|
where: {
|
||||||
OR: [
|
OR: [
|
||||||
@ -257,33 +255,16 @@ export async function deleteUser(
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
cloudMode
|
client.website.deleteMany({
|
||||||
? client.website.updateMany({
|
where: { id: { in: websiteIds } },
|
||||||
data: {
|
}),
|
||||||
deletedAt: new Date(),
|
client.user.delete({
|
||||||
},
|
where: {
|
||||||
where: { id: { in: websiteIds } },
|
id: userId,
|
||||||
})
|
},
|
||||||
: client.website.deleteMany({
|
}),
|
||||||
where: { id: { in: websiteIds } },
|
|
||||||
}),
|
|
||||||
cloudMode
|
|
||||||
? client.user.update({
|
|
||||||
data: {
|
|
||||||
username: getRandomChars(32),
|
|
||||||
deletedAt: new Date(),
|
|
||||||
},
|
|
||||||
where: {
|
|
||||||
id: userId,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
: client.user.delete({
|
|
||||||
where: {
|
|
||||||
id: userId,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
])
|
])
|
||||||
.then(async data => {
|
.then(async (data: any) => {
|
||||||
if (cache.enabled) {
|
if (cache.enabled) {
|
||||||
const ids = websites.map(a => a.id);
|
const ids = websites.map(a => a.id);
|
||||||
|
|
||||||
|
@ -260,7 +260,7 @@ export async function deleteWebsite(
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
cloudMode
|
cloudMode
|
||||||
? prisma.client.website.update({
|
? client.website.update({
|
||||||
data: {
|
data: {
|
||||||
deletedAt: new Date(),
|
deletedAt: new Date(),
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
export * from './admin/report';
|
export * from './admin/report';
|
||||||
export * from './admin/team';
|
export * from './admin/team';
|
||||||
export * from './admin/teamUser';
|
export * from './admin/teamUser';
|
||||||
export * from './admin/teamWebsite';
|
|
||||||
export * from './admin/user';
|
export * from './admin/user';
|
||||||
export * from './admin/website';
|
export * from './admin/website';
|
||||||
export * from './analytics/events/getEventMetrics';
|
export * from './analytics/events/getEventMetrics';
|
||||||
|
64
yarn.lock
64
yarn.lock
@ -2597,13 +2597,15 @@
|
|||||||
"@typescript-eslint/types" "6.14.0"
|
"@typescript-eslint/types" "6.14.0"
|
||||||
eslint-visitor-keys "^3.4.1"
|
eslint-visitor-keys "^3.4.1"
|
||||||
|
|
||||||
"@umami/prisma-client@^0.8.0":
|
"@umami/prisma-client@^0.13.0":
|
||||||
version "0.8.0"
|
version "0.13.0"
|
||||||
resolved "https://registry.yarnpkg.com/@umami/prisma-client/-/prisma-client-0.8.0.tgz#9f866c813b15b7ab0e7632506316bf1e5d2e74cc"
|
resolved "https://registry.yarnpkg.com/@umami/prisma-client/-/prisma-client-0.13.0.tgz#00ed90adf36e8e8cb7301ab557ad617dd946188f"
|
||||||
integrity sha512-ix3/75CO3eVlf1Rg0cUIjoHDFJV7nxx5sSh1NnvbjyGn8EsTpZ7fVYF874w8+ENQsaKFIMftUSGGiwvgxaZN3g==
|
integrity sha512-HkhwTH7cxkbqlxw6LK8QGbEaIl0aYZeVf5bUwncv68C/RaQrQ0/g9x6TzHo6uKlSgk2LtavnGwxYmjxD1fdGQw==
|
||||||
dependencies:
|
dependencies:
|
||||||
|
"@prisma/extension-read-replicas" "^0.3.0"
|
||||||
chalk "^4.1.2"
|
chalk "^4.1.2"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
|
sql-formatter "^15.1.2"
|
||||||
|
|
||||||
"@umami/redis-client@^0.18.0":
|
"@umami/redis-client@^0.18.0":
|
||||||
version "0.18.0"
|
version "0.18.0"
|
||||||
@ -3377,7 +3379,7 @@ commander@11.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67"
|
||||||
integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==
|
integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==
|
||||||
|
|
||||||
commander@2, commander@^2.20.0, commander@^2.20.3:
|
commander@2, commander@^2.19.0, commander@^2.20.0, commander@^2.20.3:
|
||||||
version "2.20.3"
|
version "2.20.3"
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||||
@ -3933,6 +3935,11 @@ dir-glob@^3.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
path-type "^4.0.0"
|
path-type "^4.0.0"
|
||||||
|
|
||||||
|
discontinuous-range@1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a"
|
||||||
|
integrity sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==
|
||||||
|
|
||||||
doctrine@^2.1.0:
|
doctrine@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
|
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
|
||||||
@ -4793,6 +4800,11 @@ get-port-please@^3.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/get-port-please/-/get-port-please-3.1.1.tgz#2556623cddb4801d823c0a6a15eec038abb483be"
|
resolved "https://registry.yarnpkg.com/get-port-please/-/get-port-please-3.1.1.tgz#2556623cddb4801d823c0a6a15eec038abb483be"
|
||||||
integrity sha512-3UBAyM3u4ZBVYDsxOQfJDxEa6XTbpBDrOjp4mf7ExFRt5BKs/QywQQiJsh2B+hxcZLSapWqCRvElUe8DnKcFHA==
|
integrity sha512-3UBAyM3u4ZBVYDsxOQfJDxEa6XTbpBDrOjp4mf7ExFRt5BKs/QywQQiJsh2B+hxcZLSapWqCRvElUe8DnKcFHA==
|
||||||
|
|
||||||
|
get-stdin@=8.0.0:
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53"
|
||||||
|
integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==
|
||||||
|
|
||||||
get-stream@^6.0.0, get-stream@^6.0.1:
|
get-stream@^6.0.0, get-stream@^6.0.1:
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
|
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
|
||||||
@ -6308,6 +6320,11 @@ moment-timezone@^0.5.35:
|
|||||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
|
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
|
||||||
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
|
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
|
||||||
|
|
||||||
|
moo@^0.5.0:
|
||||||
|
version "0.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.2.tgz#f9fe82473bc7c184b0d32e2215d3f6e67278733c"
|
||||||
|
integrity sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==
|
||||||
|
|
||||||
mri@^1.2.0:
|
mri@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
|
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
|
||||||
@ -6353,6 +6370,16 @@ natural-compare@^1.4.0:
|
|||||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||||
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
|
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
|
||||||
|
|
||||||
|
nearley@^2.20.1:
|
||||||
|
version "2.20.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.20.1.tgz#246cd33eff0d012faf197ff6774d7ac78acdd474"
|
||||||
|
integrity sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==
|
||||||
|
dependencies:
|
||||||
|
commander "^2.19.0"
|
||||||
|
moo "^0.5.0"
|
||||||
|
railroad-diagrams "^1.0.0"
|
||||||
|
randexp "0.4.6"
|
||||||
|
|
||||||
next-basics@^0.39.0:
|
next-basics@^0.39.0:
|
||||||
version "0.39.0"
|
version "0.39.0"
|
||||||
resolved "https://registry.yarnpkg.com/next-basics/-/next-basics-0.39.0.tgz#1ec448a1c12966a82067445bfb9319b7e883dd6a"
|
resolved "https://registry.yarnpkg.com/next-basics/-/next-basics-0.39.0.tgz#1ec448a1c12966a82067445bfb9319b7e883dd6a"
|
||||||
@ -7507,6 +7534,19 @@ raf-schd@^4.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a"
|
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a"
|
||||||
integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==
|
integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==
|
||||||
|
|
||||||
|
railroad-diagrams@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e"
|
||||||
|
integrity sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==
|
||||||
|
|
||||||
|
randexp@0.4.6:
|
||||||
|
version "0.4.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3"
|
||||||
|
integrity sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==
|
||||||
|
dependencies:
|
||||||
|
discontinuous-range "1.0.0"
|
||||||
|
ret "~0.1.10"
|
||||||
|
|
||||||
randombytes@^2.1.0:
|
randombytes@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
||||||
@ -7883,6 +7923,11 @@ restore-cursor@^4.0.0:
|
|||||||
onetime "^5.1.0"
|
onetime "^5.1.0"
|
||||||
signal-exit "^3.0.2"
|
signal-exit "^3.0.2"
|
||||||
|
|
||||||
|
ret@~0.1.10:
|
||||||
|
version "0.1.15"
|
||||||
|
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
|
||||||
|
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
|
||||||
|
|
||||||
reusify@^1.0.4:
|
reusify@^1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
||||||
@ -8280,6 +8325,15 @@ sprintf-js@~1.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||||
integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
|
integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
|
||||||
|
|
||||||
|
sql-formatter@^15.1.2:
|
||||||
|
version "15.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/sql-formatter/-/sql-formatter-15.1.2.tgz#86df2592eedf6d422244e10e00a74380c22791b7"
|
||||||
|
integrity sha512-zBrLBclCNurCsQaO6yMvkXzHvv7eJPjiF8LIEQ5HdBV/x6UuWIZwqss3mlZ/6HLj+VYhFKeHpQnyLuZWG2agKQ==
|
||||||
|
dependencies:
|
||||||
|
argparse "^2.0.1"
|
||||||
|
get-stdin "=8.0.0"
|
||||||
|
nearley "^2.20.1"
|
||||||
|
|
||||||
stable@^0.1.8:
|
stable@^0.1.8:
|
||||||
version "0.1.8"
|
version "0.1.8"
|
||||||
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
|
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
|
||||||
|
Loading…
Reference in New Issue
Block a user