Updated search queries.

This commit is contained in:
Mike Cao 2024-02-03 23:19:29 -08:00
parent 80a58cbdd1
commit e971f2533d
12 changed files with 90 additions and 147 deletions

View File

@ -12,14 +12,14 @@ import useDashboard from 'store/dashboard';
export function Dashboard() { export function Dashboard() {
const { formatMessage, labels, messages } = useMessages(); const { formatMessage, labels, messages } = useMessages();
const { teamId } = useTeamContext(); const { teamId, renderTeamUrl } = useTeamContext();
const { showCharts, editing } = useDashboard(); const { showCharts, editing } = useDashboard();
const { dir } = useLocale(); const { dir } = useLocale();
const pageSize = 10; const pageSize = 10;
const { result, query, params, setParams } = useWebsites({}, { pageSize }); const { result, query, params, setParams } = useWebsites({ teamId }, { pageSize });
const { page } = params; const { page } = params;
const hasData = !!result?.data; const hasData = !!result?.data?.length;
const handlePageChange = (page: number) => { const handlePageChange = (page: number) => {
setParams({ ...params, page }); setParams({ ...params, page });
@ -36,7 +36,7 @@ export function Dashboard() {
</PageHeader> </PageHeader>
{!hasData && ( {!hasData && (
<EmptyPlaceholder message={formatMessage(messages.noWebsitesConfigured)}> <EmptyPlaceholder message={formatMessage(messages.noWebsitesConfigured)}>
<Link href="/settings/websites"> <Link href={renderTeamUrl('/settings/websites')}>
<Button> <Button>
<Icon rotate={dir === 'rtl' ? 180 : 0}> <Icon rotate={dir === 'rtl' ? 180 : 0}>
<Icons.ArrowRight /> <Icons.ArrowRight />

View File

@ -8,7 +8,7 @@ export default function Websites({ teamId }: { teamId: string }) {
return ( return (
<> <>
<WebsitesHeader showActions={user.role !== 'view-only'} /> <WebsitesHeader teamId={teamId} showActions={user.role !== 'view-only'} />
<WebsitesDataTable teamId={teamId} userId={user.id} allowEdit={true} /> <WebsitesDataTable teamId={teamId} userId={user.id} allowEdit={true} />
</> </>
); );

View File

@ -5,7 +5,7 @@ import { Metadata } from 'next';
export default function WebsitesPage({ params: { teamId, userId } }) { export default function WebsitesPage({ params: { teamId, userId } }) {
return ( return (
<> <>
<WebsitesHeader showActions={false} /> <WebsitesHeader teamId={teamId} showActions={false} />
<WebsitesBrowse teamId={teamId} userId={userId} /> <WebsitesBrowse teamId={teamId} userId={userId} />
</> </>
); );

View File

@ -6,8 +6,8 @@ import { useMessages } from 'components/hooks';
import { useLogin } from 'components/hooks'; import { useLogin } from 'components/hooks';
import { useLocale } from 'components/hooks'; import { useLocale } from 'components/hooks';
import { CURRENT_VERSION } from 'lib/constants'; import { CURRENT_VERSION } from 'lib/constants';
import styles from './ProfileButton.module.css';
import Avatar from 'components/common/Avatar'; import Avatar from 'components/common/Avatar';
import styles from './ProfileButton.module.css';
export function ProfileButton() { export function ProfileButton() {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();

View File

@ -17,6 +17,7 @@ export * from 'components/hooks/useMessages';
export * from 'components/hooks/useNavigation'; export * from 'components/hooks/useNavigation';
export * from 'components/hooks/useSticky'; export * from 'components/hooks/useSticky';
export * from 'components/hooks/useTheme'; export * from 'components/hooks/useTheme';
export * from 'components/hooks/useTeamContext';
export * from 'components/hooks/useTimezone'; export * from 'components/hooks/useTimezone';
export * from './app/(main)/settings/teams/[teamId]/TeamEditForm'; export * from './app/(main)/settings/teams/[teamId]/TeamEditForm';
@ -60,3 +61,6 @@ export * from 'components/common/HoverTooltip';
export * from 'components/common/LinkButton'; export * from 'components/common/LinkButton';
export * from 'components/common/MobileMenu'; export * from 'components/common/MobileMenu';
export * from 'components/common/Pager'; export * from 'components/common/Pager';
export * from 'components/input/TeamsButton';
export * from 'components/input/ThemeButton';

View File

@ -17,27 +17,23 @@ export function getDatabaseType(url = process.env.DATABASE_URL) {
return POSTGRESQL; return POSTGRESQL;
} }
if (process.env.CLICKHOUSE_URL) {
return CLICKHOUSE;
}
return type; return type;
} }
export async function runQuery(queries: any) { export async function runQuery(queries: any) {
const db = getDatabaseType(process.env.CLICKHOUSE_URL || process.env.DATABASE_URL); if (process.env.CLICKHOUSE_URL) {
if (db === POSTGRESQL || db === MYSQL) {
return queries[PRISMA]();
}
if (db === CLICKHOUSE) {
if (queries[KAFKA]) { if (queries[KAFKA]) {
return queries[KAFKA](); return queries[KAFKA]();
} }
return queries[CLICKHOUSE](); return queries[CLICKHOUSE]();
} }
const db = getDatabaseType();
if (db === POSTGRESQL || db === MYSQL) {
return queries[PRISMA]();
}
} }
export function notImplemented() { export function notImplemented() {

View File

@ -24,7 +24,7 @@ const POSTGRESQL_DATE_FORMATS = {
}; };
function getAddIntervalQuery(field: string, interval: string): string { function getAddIntervalQuery(field: string, interval: string): string {
const db = getDatabaseType(process.env.DATABASE_URL); const db = getDatabaseType();
if (db === POSTGRESQL) { if (db === POSTGRESQL) {
return `${field} + interval '${interval}'`; return `${field} + interval '${interval}'`;
@ -36,7 +36,7 @@ function getAddIntervalQuery(field: string, interval: string): string {
} }
function getDayDiffQuery(field1: string, field2: string): string { function getDayDiffQuery(field1: string, field2: string): string {
const db = getDatabaseType(process.env.DATABASE_URL); const db = getDatabaseType();
if (db === POSTGRESQL) { if (db === POSTGRESQL) {
return `${field1}::date - ${field2}::date`; return `${field1}::date - ${field2}::date`;
@ -48,7 +48,7 @@ function getDayDiffQuery(field1: string, field2: string): string {
} }
function getCastColumnQuery(field: string, type: string): string { function getCastColumnQuery(field: string, type: string): string {
const db = getDatabaseType(process.env.DATABASE_URL); const db = getDatabaseType();
if (db === POSTGRESQL) { if (db === POSTGRESQL) {
return `${field}::${type}`; return `${field}::${type}`;
@ -92,7 +92,7 @@ function getTimestampDiffQuery(field1: string, field2: string): string {
} }
} }
function mapFilter(column, operator, name, type = 'varchar') { function mapFilter(column: string, operator: string, name: string, type = 'varchar') {
switch (operator) { switch (operator) {
case OPERATORS.equals: case OPERATORS.equals:
return `${column} = {{${name}::${type}}}`; return `${column} = {{${name}::${type}}}`;
@ -208,16 +208,44 @@ function getQueryMode(): Prisma.QueryMode {
return 'default'; return 'default';
} }
function getSearchParameters(query: string, filters: { [key: string]: any }[]) {
if (!query) return;
const mode = getQueryMode();
const parseFilter = (filter: { [key: string]: any }) => {
const [[key, value]] = Object.entries(filter);
return {
[key]:
typeof value === 'string'
? {
[value]: query,
mode,
}
: parseFilter(value),
};
};
const params = filters.map(filter => parseFilter(filter));
return {
AND: {
OR: params,
},
};
}
export default { export default {
...prisma, ...prisma,
getAddIntervalQuery, getAddIntervalQuery,
getDayDiffQuery,
getCastColumnQuery, getCastColumnQuery,
getDayDiffQuery,
getDateQuery, getDateQuery,
getTimestampDiffQuery,
getFilterQuery, getFilterQuery,
parseFilters, getSearchParameters,
getTimestampDiffQuery,
getQueryMode, getQueryMode,
rawQuery,
pagedQuery, pagedQuery,
parseFilters,
rawQuery,
}; };

View File

@ -3,9 +3,10 @@ import { useAuth, useCors, useValidate } from 'lib/middleware';
import { NextApiRequestQueryBody } from 'lib/types'; import { NextApiRequestQueryBody } from 'lib/types';
import { pageInfo } from 'lib/schema'; import { pageInfo } from 'lib/schema';
import { NextApiResponse } from 'next'; import { NextApiResponse } from 'next';
import { methodNotAllowed, ok } from 'next-basics'; import { methodNotAllowed, ok, unauthorized } from 'next-basics';
import { createReport, getReports } from 'queries'; import { createReport, getReports } from 'queries';
import * as yup from 'yup'; import * as yup from 'yup';
import { canViewTeam, canViewWebsite } from 'lib/auth';
export interface ReportRequestBody { export interface ReportRequestBody {
websiteId: string; websiteId: string;
@ -51,16 +52,23 @@ export default async (
const { page, query, pageSize, websiteId, teamId } = req.query; const { page, query, pageSize, websiteId, teamId } = req.query;
const filters = { const filters = {
page, page,
pageSize: +pageSize || undefined, pageSize,
query, query,
}; };
if (
(websiteId && !(await canViewWebsite(req.auth, websiteId))) ||
(teamId && !(await canViewTeam(req.auth, teamId)))
) {
return unauthorized(res);
}
const data = await getReports( const data = await getReports(
{ {
where: { where: {
userId: !teamId && !websiteId ? userId : undefined,
websiteId,
website: { website: {
id: websiteId,
userId: !websiteId && !teamId ? userId : undefined,
teamId, teamId,
}, },
}, },

View File

@ -20,68 +20,30 @@ export async function getReports(
criteria: ReportFindManyArgs, criteria: ReportFindManyArgs,
filters: ReportSearchFilter = {}, filters: ReportSearchFilter = {},
): Promise<FilterResult<Report[]>> { ): Promise<FilterResult<Report[]>> {
const mode = prisma.getQueryMode(); const { query } = filters;
const { query, userId, websiteId } = filters;
const where: Prisma.ReportWhereInput = { const where: Prisma.ReportWhereInput = {
userId,
websiteId,
...criteria.where, ...criteria.where,
AND: [ ...prisma.getSearchParameters(query, [
{ name: 'contains' },
{ description: 'contains' },
{ type: 'contains' },
{ {
OR: [ user: {
{ username: 'contains',
userId, },
},
],
}, },
{ {
OR: [ website: {
{ name: 'contains',
name: { },
contains: query,
mode,
},
},
{
description: {
contains: query,
mode,
},
},
{
type: {
contains: query,
mode,
},
},
{
user: {
username: {
contains: query,
mode,
},
},
},
{
website: {
name: {
contains: query,
mode,
},
},
},
{
website: {
domain: {
contains: query,
mode,
},
},
},
],
}, },
], {
website: {
domain: 'contains',
},
},
]),
}; };
return prisma.pagedQuery('report', { ...criteria, where }, filters); return prisma.pagedQuery('report', { ...criteria, where }, filters);

View File

@ -24,41 +24,12 @@ export async function getTeams(
criteria: TeamFindManyArgs, criteria: TeamFindManyArgs,
filters: TeamSearchFilter = {}, filters: TeamSearchFilter = {},
): Promise<FilterResult<Team[]>> { ): Promise<FilterResult<Team[]>> {
const mode = prisma.getQueryMode(); const { getSearchParameters } = prisma;
const { userId, query } = filters; const { query } = filters;
const where: Prisma.TeamWhereInput = { const where: Prisma.TeamWhereInput = {
...criteria.where, ...criteria.where,
...(userId && { ...getSearchParameters(query, [{ name: 'contains' }]),
teamUser: {
some: { userId },
},
}),
...(query && {
AND: {
OR: [
{
name: {
startsWith: query,
mode,
},
},
{
teamUser: {
some: {
role: ROLES.teamOwner,
user: {
username: {
startsWith: query,
mode,
},
},
},
},
},
],
},
}),
}; };
return prisma.pagedQuery<TeamFindManyArgs>( return prisma.pagedQuery<TeamFindManyArgs>(

View File

@ -18,18 +18,10 @@ export async function getTeamUsers(
filters?: TeamUserSearchFilter, filters?: TeamUserSearchFilter,
): Promise<FilterResult<TeamUser[]>> { ): Promise<FilterResult<TeamUser[]>> {
const { query } = filters; const { query } = filters;
const mode = prisma.getQueryMode();
const where: Prisma.TeamUserWhereInput = { const where: Prisma.TeamUserWhereInput = {
...criteria.where, ...criteria.where,
user: { ...prisma.getSearchParameters(query, [{ user: { username: 'contains' } }]),
username: query
? {
contains: query,
mode,
}
: undefined,
},
}; };
return prisma.pagedQuery( return prisma.pagedQuery(

View File

@ -52,29 +52,11 @@ export async function getUsers(
criteria: UserFindManyArgs, criteria: UserFindManyArgs,
filters?: UserSearchFilter, filters?: UserSearchFilter,
): Promise<FilterResult<User[]>> { ): Promise<FilterResult<User[]>> {
const { teamId, query } = filters; const { query } = filters;
const mode = prisma.getQueryMode();
const where: Prisma.UserWhereInput = { const where: Prisma.UserWhereInput = {
...(teamId && { ...criteria.where,
teamUser: { ...prisma.getSearchParameters(query, [{ username: 'contains' }]),
some: {
teamId,
},
},
}),
...(query && {
AND: {
OR: [
{
username: {
contains: query,
mode,
},
},
],
},
}),
deletedAt: null, deletedAt: null,
}; };