From da27a1606bbb0e97f4e71ae274ebace626bbdb6c Mon Sep 17 00:00:00 2001 From: Laurin Quast Date: Thu, 27 Jul 2023 14:14:18 +0200 Subject: [PATCH] use more client preset (#2661) --- .github/workflows/typescript-typecheck.yaml | 2 +- package.json | 2 +- packages/web/app/package.json | 1 - .../[orgId]/[projectId]/[targetId]/index.tsx | 2 +- .../[projectId]/[targetId]/settings.tsx | 14 +- packages/web/app/pages/index.tsx | 18 ++- .../components/common/activities/common.ts | 11 +- .../app/src/components/organization/Usage.tsx | 13 +- .../components/target/history/MarkAsValid.tsx | 26 +++- .../components/target/operations/Filters.tsx | 128 +++++++++++++---- .../src/components/target/operations/List.tsx | 111 ++++++++++----- .../components/target/operations/Stats.tsx | 129 ++++++++++++++---- .../components/v2/modals/delete-project.tsx | 19 ++- .../components/v2/modals/delete-target.tsx | 20 ++- .../web/app/src/config/supertokens/backend.ts | 2 +- ...utation.delete-persisted-operation.graphql | 9 -- .../graphql/mutation.delete-project.graphql | 12 -- .../graphql/mutation.delete-target.graphql | 13 -- .../graphql/mutation.send-feedback.graphql | 3 - .../mutation.set-target-validation.graphql | 8 -- ....update-organization-member-access.graphql | 10 -- ...ation.update-schema-version-status.graphql | 5 - .../mutation.update-target-name.graphql | 14 -- .../query.general-operations-stats.graphql | 49 ------- .../query.has-collected-operations.graphql | 3 - .../graphql/query.operations-stats.graphql | 16 --- .../query.org-usage-estimation.graphql | 7 - .../src/graphql/query.organizations.graphql | 8 -- .../graphql/query.project-activities.graphql | 18 --- .../query.projects-with-targets.graphql | 14 -- .../app/src/graphql/query.projects.graphql | 8 -- .../graphql/query.target-activities.graphql | 14 -- .../web/app/src/graphql/query.targets.graphql | 8 -- ...party-email-password-node-oidc-provider.ts | 2 +- packages/web/app/src/lib/urql-cache.ts | 26 +--- pnpm-lock.yaml | 5 +- turbo.json | 5 +- 37 files changed, 392 insertions(+), 363 deletions(-) delete mode 100644 packages/web/app/src/graphql/mutation.delete-persisted-operation.graphql delete mode 100644 packages/web/app/src/graphql/mutation.delete-project.graphql delete mode 100644 packages/web/app/src/graphql/mutation.delete-target.graphql delete mode 100644 packages/web/app/src/graphql/mutation.send-feedback.graphql delete mode 100644 packages/web/app/src/graphql/mutation.set-target-validation.graphql delete mode 100644 packages/web/app/src/graphql/mutation.update-organization-member-access.graphql delete mode 100644 packages/web/app/src/graphql/mutation.update-schema-version-status.graphql delete mode 100644 packages/web/app/src/graphql/mutation.update-target-name.graphql delete mode 100644 packages/web/app/src/graphql/query.general-operations-stats.graphql delete mode 100644 packages/web/app/src/graphql/query.has-collected-operations.graphql delete mode 100644 packages/web/app/src/graphql/query.operations-stats.graphql delete mode 100644 packages/web/app/src/graphql/query.org-usage-estimation.graphql delete mode 100644 packages/web/app/src/graphql/query.organizations.graphql delete mode 100644 packages/web/app/src/graphql/query.project-activities.graphql delete mode 100644 packages/web/app/src/graphql/query.projects-with-targets.graphql delete mode 100644 packages/web/app/src/graphql/query.projects.graphql delete mode 100644 packages/web/app/src/graphql/query.target-activities.graphql delete mode 100644 packages/web/app/src/graphql/query.targets.graphql diff --git a/.github/workflows/typescript-typecheck.yaml b/.github/workflows/typescript-typecheck.yaml index edf3eaed2..82a2df011 100644 --- a/.github/workflows/typescript-typecheck.yaml +++ b/.github/workflows/typescript-typecheck.yaml @@ -23,6 +23,6 @@ jobs: uses: SimenB/github-actions-cpu-cores@v1 - name: typecheck - run: pnpm typecheck --concurrency ${{ steps.cpu-cores.outputs.count }} + run: pnpm run --workspace-concurrency ${{ steps.cpu-cores.outputs.count }} -r typecheck env: NODE_OPTIONS: '--max-old-space-size=4096' diff --git a/package.json b/package.json index 0860c9a72..f9a4daa76 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "test": "vitest", "test:e2e": "CYPRESS_BASE_URL=$HIVE_APP_BASE_URL cypress run", "test:integration": "cd integration-tests && pnpm test:integration", - "typecheck": "pnpm turbo typecheck --color", + "typecheck": "pnpm run -r typecheck", "upload-sourcemaps": "./scripts/upload-sourcemaps.sh", "workspace": "pnpm run --filter $1 $2" }, diff --git a/packages/web/app/package.json b/packages/web/app/package.json index 918855d1a..58420ea71 100644 --- a/packages/web/app/package.json +++ b/packages/web/app/package.json @@ -99,7 +99,6 @@ "@graphql-codegen/client-preset-swc-plugin": "0.2.0", "@graphql-typed-document-node/core": "3.2.0", "@hive/emails": "workspace:*", - "@hive/server": "workspace:*", "@next/bundle-analyzer": "13.4.11", "@storybook/addon-essentials": "7.0.23", "@storybook/addon-interactions": "7.0.23", diff --git a/packages/web/app/pages/[orgId]/[projectId]/[targetId]/index.tsx b/packages/web/app/pages/[orgId]/[projectId]/[targetId]/index.tsx index bc11f06e7..93d5485e1 100644 --- a/packages/web/app/pages/[orgId]/[projectId]/[targetId]/index.tsx +++ b/packages/web/app/pages/[orgId]/[projectId]/[targetId]/index.tsx @@ -149,13 +149,13 @@ const SchemaView_TargetFragment = graphql(` cleanId latestSchemaVersion { id - valid schemas { nodes { __typename ...SchemaView_SchemaFragment } } + ...MarkAsValid_SchemaVersionFragment } } `); diff --git a/packages/web/app/pages/[orgId]/[projectId]/[targetId]/settings.tsx b/packages/web/app/pages/[orgId]/[projectId]/[targetId]/settings.tsx index bc9a98efc..55add7cd0 100644 --- a/packages/web/app/pages/[orgId]/[projectId]/[targetId]/settings.tsx +++ b/packages/web/app/pages/[orgId]/[projectId]/[targetId]/settings.tsx @@ -30,11 +30,21 @@ import { import { Combobox } from '@/components/v2/combobox'; import { CreateAccessTokenModal, DeleteTargetModal } from '@/components/v2/modals'; import { FragmentType, graphql, useFragment } from '@/gql'; -import { SetTargetValidationDocument } from '@/graphql'; import { canAccessTarget, TargetAccessScope } from '@/lib/access/target'; import { useRouteSelector, useToggle } from '@/lib/hooks'; import { withSessionProtection } from '@/lib/supertokens/guard'; +const SetTargetValidationMutation = graphql(` + mutation Settings_SetTargetValidation($input: SetTargetValidationInput!) { + setTargetValidation(input: $input) { + id + validationSettings { + ...TargetValidationSettingsFields + } + } + } +`); + const RegistryAccessTokens_MeFragment = graphql(` fragment RegistryAccessTokens_MeFragment on Member { ...CanAccessTarget_MemberFragment @@ -379,7 +389,7 @@ function floorDate(date: Date): Date { const ConditionalBreakingChanges = (): ReactElement => { const router = useRouteSelector(); - const [targetValidation, setValidation] = useMutation(SetTargetValidationDocument); + const [targetValidation, setValidation] = useMutation(SetTargetValidationMutation); const [mutation, updateValidation] = useMutation( TargetSettingsPage_UpdateTargetValidationSettingsMutation, ); diff --git a/packages/web/app/pages/index.tsx b/packages/web/app/pages/index.tsx index c9bd85b8e..ded89ea6e 100644 --- a/packages/web/app/pages/index.tsx +++ b/packages/web/app/pages/index.tsx @@ -8,12 +8,12 @@ import { Title } from '@/components/common'; import { DataWrapper } from '@/components/v2'; import { LAST_VISITED_ORG_KEY } from '@/constants'; import { env } from '@/env/backend'; -import { OrganizationsDocument } from '@/graphql'; +import { graphql } from '@/gql'; import { writeLastVisitedOrganization } from '@/lib/cookies'; import { useRouteSelector } from '@/lib/hooks/use-route-selector'; import { withSessionProtection } from '@/lib/supertokens/guard'; // eslint-disable-next-line import/no-extraneous-dependencies -- TODO: should we move to "dependencies"? -import { InternalApi } from '@hive/server'; +import { type InternalApi } from '@hive/server'; import { createTRPCProxyClient, httpLink } from '@trpc/client'; async function getSuperTokensUserIdFromRequest( @@ -67,8 +67,20 @@ export const getServerSideProps = withSessionProtection(async ({ req, res }) => }; }); +export const OrganizationsQuery = graphql(` + query organizations { + organizations { + nodes { + ...OrganizationFields + cleanId + } + total + } + } +`); + function Home(): ReactElement { - const [query] = useQuery({ query: OrganizationsDocument }); + const [query] = useQuery({ query: OrganizationsQuery }); const router = useRouteSelector(); useEffect(() => { diff --git a/packages/web/app/src/components/common/activities/common.ts b/packages/web/app/src/components/common/activities/common.ts index 8709a926b..6865a0811 100644 --- a/packages/web/app/src/components/common/activities/common.ts +++ b/packages/web/app/src/components/common/activities/common.ts @@ -1,10 +1,3 @@ -import { - OrganizationActivitiesQuery, - ProjectActivitiesQuery, - TargetActivitiesQuery, -} from '@/graphql'; +import { OrganizationActivitiesQuery } from '@/graphql'; -export type ActivityNode = - | OrganizationActivitiesQuery['organizationActivities']['nodes'][0] - | ProjectActivitiesQuery['projectActivities']['nodes'][0] - | TargetActivitiesQuery['targetActivities']['nodes'][0]; +export type ActivityNode = OrganizationActivitiesQuery['organizationActivities']['nodes'][0]; diff --git a/packages/web/app/src/components/organization/Usage.tsx b/packages/web/app/src/components/organization/Usage.tsx index 35ffe06f6..da41a7908 100644 --- a/packages/web/app/src/components/organization/Usage.tsx +++ b/packages/web/app/src/components/organization/Usage.tsx @@ -2,7 +2,6 @@ import { ReactElement } from 'react'; import { useQuery } from 'urql'; import { DataWrapper, Table, TBody, Td, Th, THead, Tr } from '@/components/v2'; import { FragmentType, graphql, useFragment } from '@/gql'; -import { UsageEstimationDocument } from '@/graphql'; import { Scale } from '../common'; import { calculatePeriod } from '../common/TimeFilter'; @@ -17,6 +16,16 @@ const OrganizationUsageEstimationView_OrganizationFragment = graphql(` } `); +const Usage_UsageEstimationQuery = graphql(` + query Usage_UsageEstimationQuery($range: DateRangeInput!, $organization: ID!) { + usageEstimation(range: $range) { + org(selector: { organization: $organization }) { + operations + } + } + } +`); + export function OrganizationUsageEstimationView(props: { organization: FragmentType; }): ReactElement { @@ -27,7 +36,7 @@ export function OrganizationUsageEstimationView(props: { const period = calculatePeriod('month'); const [query] = useQuery({ - query: UsageEstimationDocument, + query: Usage_UsageEstimationQuery, variables: { organization: organization.cleanId, range: period, diff --git a/packages/web/app/src/components/target/history/MarkAsValid.tsx b/packages/web/app/src/components/target/history/MarkAsValid.tsx index 3975fdd59..8936c5df0 100644 --- a/packages/web/app/src/components/target/history/MarkAsValid.tsx +++ b/packages/web/app/src/components/target/history/MarkAsValid.tsx @@ -1,16 +1,30 @@ import { ReactElement, useCallback } from 'react'; import { useMutation } from 'urql'; import { Button, Tooltip } from '@/components/v2'; -import { SchemaVersionFieldsFragment, UpdateSchemaVersionStatusDocument } from '@/graphql'; +import { FragmentType, graphql, useFragment } from '@/gql'; import { useRouteSelector } from '@/lib/hooks'; -export function MarkAsValid({ - version, -}: { - version: Pick; +const UpdateSchemaVersionStatusMutation = graphql(` + mutation updateSchemaVersionStatus($input: SchemaVersionUpdateInput!) { + updateSchemaVersionStatus(input: $input) { + ...SchemaVersionFields + } + } +`); + +const MarkAsValid_SchemaVersionFragment = graphql(` + fragment MarkAsValid_SchemaVersionFragment on SchemaVersion { + id + valid + } +`); + +export function MarkAsValid(props: { + version: FragmentType; }): ReactElement | null { const router = useRouteSelector(); - const [mutation, mutate] = useMutation(UpdateSchemaVersionStatusDocument); + const version = useFragment(MarkAsValid_SchemaVersionFragment, props.version); + const [mutation, mutate] = useMutation(UpdateSchemaVersionStatusMutation); const markAsValid = useCallback(async () => { await mutate({ input: { diff --git a/packages/web/app/src/components/target/operations/Filters.tsx b/packages/web/app/src/components/target/operations/Filters.tsx index 9d242e32a..a1774cff3 100644 --- a/packages/web/app/src/components/target/operations/Filters.tsx +++ b/packages/web/app/src/components/target/operations/Filters.tsx @@ -4,26 +4,43 @@ import { FixedSizeList, ListChildComponentProps } from 'react-window'; import { useQuery } from 'urql'; import { useDebouncedCallback } from 'use-debounce'; import { Button, Checkbox, Drawer, Input, Spinner } from '@/components/v2'; -import { DateRangeInput, OperationsStatsDocument, OperationStatsFieldsFragment } from '@/graphql'; +import { FragmentType, graphql, useFragment } from '@/gql'; +import { DateRangeInput } from '@/graphql'; import { useFormattedNumber, useRouteSelector, useToggle } from '@/lib/hooks'; import { ChevronUpIcon } from '@radix-ui/react-icons'; +const OperationsFilter_OperationStatsConnectionFragment = graphql(` + fragment OperationsFilter_OperationStatsConnectionFragment on OperationStatsConnection { + nodes { + id + operationHash + name + ...OperationRow_OperationStatsFragment + } + } +`); + function OperationsFilter({ onClose, isOpen, onFilter, - operations, + operationStatsConnection, selected, }: { onClose(): void; onFilter(keys: string[]): void; isOpen: boolean; - operations: readonly OperationStatsFieldsFragment[]; + operationStatsConnection: FragmentType; selected?: string[]; }): ReactElement { + const operations = useFragment( + OperationsFilter_OperationStatsConnectionFragment, + operationStatsConnection, + ); + function getOperationHashes() { const items: string[] = []; - for (const op of operations) { + for (const op of operations.nodes) { if (op.operationHash) { items.push(op.operationHash); } @@ -51,7 +68,9 @@ function OperationsFilter({ const [searchTerm, setSearchTerm] = useState(''); const debouncedFilter = useDebouncedCallback((value: string) => { setVisibleOperations( - operations.filter(op => op.name.toLocaleLowerCase().includes(value.toLocaleLowerCase())), + operations.nodes.filter(op => + op.name.toLocaleLowerCase().includes(value.toLocaleLowerCase()), + ), ); }, 500); @@ -65,7 +84,7 @@ function OperationsFilter({ [setSearchTerm, debouncedFilter], ); - const [visibleOperations, setVisibleOperations] = useState(operations); + const [visibleOperations, setVisibleOperations] = useState(operations.nodes); const selectAll = useCallback(() => { setSelectedItems(getOperationHashes()); @@ -82,7 +101,7 @@ function OperationsFilter({ @@ -103,7 +122,7 @@ function OperationsFilter({ value={searchTerm} onClear={() => { setSearchTerm(''); - setVisibleOperations(operations); + setVisibleOperations(operations.nodes); }} />
@@ -151,6 +170,17 @@ function OperationsFilter({ ); } +const OperationsFilterContainer_OperationStatsQuery = graphql(` + query OperationsFilterContainer_OperationStatsQuery($selector: OperationsStatsSelectorInput!) { + operationsStats(selector: $selector) { + operations { + ...OperationsFilter_OperationStatsConnectionFragment + total + } + } + } +`); + function OperationsFilterContainer({ period, isOpen, @@ -166,7 +196,7 @@ function OperationsFilterContainer({ }): ReactElement | null { const router = useRouteSelector(); const [query] = useQuery({ - query: OperationsStatsDocument, + query: OperationsFilterContainer_OperationStatsQuery, variables: { selector: { organization: router.organizationId, @@ -186,32 +216,40 @@ function OperationsFilterContainer({ return ; } - const allOperations = query.data.operationsStats?.operations?.nodes ?? []; - return ( { - onFilter(hashes.length === allOperations.length ? [] : hashes); + onFilter(hashes.length === query.data?.operationsStats.operations.total ? [] : hashes); }} /> ); } +const OperationRow_OperationStatsFragment = graphql(` + fragment OperationRow_OperationStatsFragment on OperationStats { + id + name + operationHash + count + } +`); + function OperationRow({ - operation, + operationStats, selected, onSelect, style, }: { - operation: OperationStatsFieldsFragment; + operationStats: FragmentType; selected: boolean; onSelect(id: string, selected: boolean): void; style: any; }): ReactElement { + const operation = useFragment(OperationRow_OperationStatsFragment, operationStats); const requests = useFormattedNumber(operation.count); const hash = operation.operationHash || ''; const change = useCallback(() => { @@ -261,17 +299,25 @@ export function OperationsFilterTrigger({ ); } +const ClientRow_ClientStatsFragment = graphql(` + fragment ClientRow_ClientStatsFragment on ClientStats { + name + count + } +`); + function ClientRow({ - client, selected, onSelect, style, + ...props }: { - client: { name: string; count: number }; + client: FragmentType; selected: boolean; onSelect(id: string, selected: boolean): void; style: any; }): ReactElement { + const client = useFragment(ClientRow_ClientStatsFragment, props.client); const requests = useFormattedNumber(client.count); const hash = client.name; const change = useCallback(() => { @@ -294,21 +340,34 @@ function ClientRow({ ); } +const ClientsFilter_ClientStatsConnectionFragment = graphql(` + fragment ClientsFilter_ClientStatsConnectionFragment on ClientStatsConnection { + nodes { + name + ...ClientRow_ClientStatsFragment + } + } +`); + function ClientsFilter({ onClose, isOpen, onFilter, - clients, + clientStatsConnection, selected, }: { onClose(): void; onFilter(keys: string[]): void; isOpen: boolean; - clients: readonly { name: string; count: number }[]; + clientStatsConnection: FragmentType; selected?: string[]; }): ReactElement { + const clientConnection = useFragment( + ClientsFilter_ClientStatsConnectionFragment, + clientStatsConnection, + ); function getClientNames() { - return clients.map(client => client.name); + return clientConnection.nodes.map(client => client.name); } const [selectedItems, setSelectedItems] = useState(() => @@ -331,7 +390,9 @@ function ClientsFilter({ const [searchTerm, setSearchTerm] = useState(''); const debouncedFilter = useDebouncedCallback((value: string) => { setVisibleOperations( - clients.filter(client => client.name.toLocaleLowerCase().includes(value.toLocaleLowerCase())), + clientConnection.nodes.filter(client => + client.name.toLocaleLowerCase().includes(value.toLocaleLowerCase()), + ), ); }, 500); @@ -345,11 +406,11 @@ function ClientsFilter({ [setSearchTerm, debouncedFilter], ); - const [visibleOperations, setVisibleOperations] = useState(clients); + const [visibleOperations, setVisibleOperations] = useState(clientConnection.nodes); const selectAll = useCallback(() => { setSelectedItems(getClientNames()); - }, [clients]); + }, [clientConnection.nodes]); const selectNone = useCallback(() => { setSelectedItems([]); }, [setSelectedItems]); @@ -383,7 +444,7 @@ function ClientsFilter({ value={searchTerm} onClear={() => { setSearchTerm(''); - setVisibleOperations(clients); + setVisibleOperations(clientConnection.nodes); }} />
@@ -431,6 +492,19 @@ function ClientsFilter({ ); } +const ClientsFilterContainer_ClientStatsQuery = graphql(` + query ClientsFilterContainer_ClientStats($selector: OperationsStatsSelectorInput!) { + operationsStats(selector: $selector) { + clients { + ...ClientsFilter_ClientStatsConnectionFragment + nodes { + __typename + } + } + } + } +`); + function ClientsFilterContainer({ period, isOpen, @@ -446,7 +520,7 @@ function ClientsFilterContainer({ }): ReactElement | null { const router = useRouteSelector(); const [query] = useQuery({ - query: OperationsStatsDocument, + query: ClientsFilterContainer_ClientStatsQuery, variables: { selector: { organization: router.organizationId, @@ -466,11 +540,11 @@ function ClientsFilterContainer({ return ; } - const allClients = query.data.operationsStats?.clients?.nodes ?? []; + const allClients = query.data.operationsStats?.clients.nodes ?? []; return ( void; }): ReactElement { @@ -322,53 +322,83 @@ function OperationsTable({ ); } +const OperationsTableContainer_OperationsStatsFragment = graphql(` + fragment OperationsTableContainer_OperationsStatsFragment on OperationsStats { + clients { + nodes { + name + } + } + operations { + nodes { + id + name + operationHash + kind + duration { + p90 + p95 + p99 + } + countOk + count + percentage + } + } + } +`); + function OperationsTableContainer({ - operations, operationsFilter, organization, project, target, - clients, clientFilter, setClientFilter, className, + ...props }: { - operations: readonly OperationStatsFieldsFragment[]; + operationStats: FragmentType | null; operationsFilter: readonly string[]; organization: string; project: string; target: string; - clients: readonly { name: string }[]; clientFilter: string | null; setClientFilter: (client: string) => void; className?: string; }): ReactElement { + const operationStats = useFragment( + OperationsTableContainer_OperationsStatsFragment, + props.operationStats, + ); const data = useMemo(() => { const records: Operation[] = []; - for (const op of operations) { - if ( - operationsFilter.length > 0 && - op.operationHash && - !operationsFilter.includes(op.operationHash) - ) { - continue; + if (operationStats) { + for (const op of operationStats.operations.nodes) { + if ( + operationsFilter.length > 0 && + op.operationHash && + !operationsFilter.includes(op.operationHash) + ) { + continue; + } + records.push({ + id: op.id, + name: op.name, + kind: op.kind, + p90: op.duration.p90, + p95: op.duration.p95, + p99: op.duration.p99, + failureRate: 1 - op.countOk / op.count, + requests: op.count, + percentage: op.percentage, + hash: op.operationHash!, + }); } - records.push({ - id: op.id, - name: op.name, - kind: op.kind, - p90: op.duration.p90, - p95: op.duration.p95, - p99: op.duration.p99, - failureRate: 1 - op.countOk / op.count, - requests: op.count, - percentage: op.percentage, - hash: op.operationHash!, - }); } return records; - }, [operations, operationsFilter]); + }, [operationStats?.operations.nodes, operationsFilter]); const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 20 }); const [sorting, setSorting] = useState([]); @@ -403,13 +433,31 @@ function OperationsTableContainer({ organization={organization} project={project} target={target} - clients={clients} + clients={operationStats?.clients.nodes ?? null} clientFilter={clientFilter} setClientFilter={setClientFilter} /> ); } +const OperationsList_OperationsStatsQuery = graphql(` + query OperationsList_OperationsStats($selector: OperationsStatsSelectorInput!) { + operationsStats(selector: $selector) { + clients { + nodes { + __typename + } + } + operations { + nodes { + __typename + } + } + ...OperationsTableContainer_OperationsStatsFragment + } + } +`); + export function OperationsList({ className, organization, @@ -429,7 +477,7 @@ export function OperationsList({ }): ReactElement { const [clientFilter, setClientFilter] = useState(null); const [query, refetch] = useQuery({ - query: OperationsStatsDocument, + query: OperationsList_OperationsStatsQuery, variables: { selector: { organization, @@ -441,8 +489,6 @@ export function OperationsList({ }, }, }); - const operations = query.data?.operationsStats?.operations?.nodes ?? []; - const clients = query.data?.operationsStats?.clients?.nodes ?? []; return ( refetch({ requestPolicy: 'cache-and-network' })} > | null; }): ReactElement { + const { failuresOverTime = [], requestsOverTime = [] } = + useFragment(OverTimeStats_OperationsStatsFragment, operationStats) ?? {}; + const styles = useChartStyles(); const interval = resolutionToMilliseconds(resolution, period); const requests = useMemo(() => { @@ -250,15 +283,34 @@ function OverTimeStats({ ); } -function ClientsStats({ - clients = [], -}: { - clients?: GeneralOperationsStatsQuery['operationsStats']['clients']['nodes']; +const ClientsStats_OperationsStatsFragment = graphql(` + fragment ClientsStats_OperationsStatsFragment on OperationsStats { + clients { + nodes { + name + count + percentage + versions { + version + count + percentage + } + } + total + } + } +`); + +function ClientsStats(props: { + operationStats: FragmentType | null; }): ReactElement { const styles = useChartStyles(); + const operationStats = useFragment(ClientsStats_OperationsStatsFragment, props.operationStats); const sortedClients = useMemo(() => { - return clients?.length ? clients.slice().sort((a, b) => b.count - a.count) : []; - }, [clients]); + return operationStats?.clients.nodes?.length + ? operationStats.clients.nodes.slice().sort((a, b) => b.count - a.count) + : []; + }, [operationStats?.clients.nodes]); const byClient = useMemo(() => { let values: string[] = []; const labels: string[] = []; @@ -438,20 +490,36 @@ function ClientsStats({ ); } +const LatencyOverTimeStats_OperationStatsFragment = graphql(` + fragment LatencyOverTimeStats_OperationStatsFragment on OperationsStats { + durationOverTime(resolution: $resolution) { + date + duration { + p75 + p90 + p95 + p99 + } + } + } +`); + function LatencyOverTimeStats({ period, resolution, - duration = [], + operationStats, }: { period: { from: string; to: string; }; resolution: number; - duration?: GeneralOperationsStatsQuery['operationsStats']['durationOverTime']; + operationStats?: FragmentType | null; }): ReactElement { const styles = useChartStyles(); const interval = resolutionToMilliseconds(resolution, period); + const { durationOverTime: duration = [] } = + useFragment(LatencyOverTimeStats_OperationStatsFragment, operationStats) ?? {}; const p75 = useMemo(() => { if (duration?.length) { return fullSeries( @@ -576,20 +644,30 @@ function LatencyOverTimeStats({ ); } +const RpmOverTimeStats_OperationStatsFragment = graphql(` + fragment RpmOverTimeStats_OperationStatsFragment on OperationsStats { + requestsOverTime(resolution: $resolution) { + date + value + } + } +`); + function RpmOverTimeStats({ period, resolution, - requestsOverTime = [], + operationStats, }: { period: { from: string; to: string; }; resolution: number; - requestsOverTime?: GeneralOperationsStatsQuery['operationsStats']['requestsOverTime']; + operationStats: FragmentType | null; }): ReactElement { const styles = useChartStyles(); - const requests = requestsOverTime ?? []; + const { requestsOverTime: requests = [] } = + useFragment(RpmOverTimeStats_OperationStatsFragment, operationStats) ?? {}; const interval = resolutionToMilliseconds(resolution, period); const windowInM = interval / (60 * 1000); @@ -703,7 +781,7 @@ export function OperationsStats({ }): ReactElement { const resolution = 90; const [query, refetchQuery] = useQuery({ - query: GeneralOperationsStatsDocument, + query: Stats_GeneralOperationsStatsQuery, variables: { selector: { organization, @@ -749,15 +827,14 @@ export function OperationsStats({
- +
@@ -766,7 +843,7 @@ export function OperationsStats({
@@ -774,7 +851,7 @@ export function OperationsStats({ diff --git a/packages/web/app/src/components/v2/modals/delete-project.tsx b/packages/web/app/src/components/v2/modals/delete-project.tsx index 97602f3b9..44dbcd721 100644 --- a/packages/web/app/src/components/v2/modals/delete-project.tsx +++ b/packages/web/app/src/components/v2/modals/delete-project.tsx @@ -2,10 +2,25 @@ import { ReactElement } from 'react'; import { useRouter } from 'next/router'; import { useMutation } from 'urql'; import { Button, Heading, Modal } from '@/components/v2'; -import { DeleteProjectDocument } from '@/graphql'; +import { graphql } from '@/gql'; import { useRouteSelector } from '@/lib/hooks'; import { TrashIcon } from '@radix-ui/react-icons'; +export const DeleteProjectMutation = graphql(` + mutation deleteProject($selector: ProjectSelectorInput!) { + deleteProject(selector: $selector) { + selector { + organization + project + } + deletedProject { + __typename + id + } + } + } +`); + export const DeleteProjectModal = ({ isOpen, toggleModalOpen, @@ -13,7 +28,7 @@ export const DeleteProjectModal = ({ isOpen: boolean; toggleModalOpen: () => void; }): ReactElement => { - const [, mutate] = useMutation(DeleteProjectDocument); + const [, mutate] = useMutation(DeleteProjectMutation); const router = useRouteSelector(); const { replace } = useRouter(); diff --git a/packages/web/app/src/components/v2/modals/delete-target.tsx b/packages/web/app/src/components/v2/modals/delete-target.tsx index 605a6c98f..bb0ebe0b7 100644 --- a/packages/web/app/src/components/v2/modals/delete-target.tsx +++ b/packages/web/app/src/components/v2/modals/delete-target.tsx @@ -2,9 +2,25 @@ import { ReactElement } from 'react'; import { useRouter } from 'next/router'; import { useMutation } from 'urql'; import { Button, Heading, Modal } from '@/components/v2'; -import { DeleteTargetDocument } from '@/graphql'; +import { graphql } from '@/gql'; import { TrashIcon } from '@radix-ui/react-icons'; +export const DeleteTargetMutation = graphql(` + mutation deleteTarget($selector: TargetSelectorInput!) { + deleteTarget(selector: $selector) { + selector { + organization + project + target + } + deletedTarget { + __typename + id + } + } + } +`); + export const DeleteTargetModal = ({ isOpen, toggleModalOpen, @@ -18,7 +34,7 @@ export const DeleteTargetModal = ({ projectId: string; targetId: string; }): ReactElement => { - const [, mutate] = useMutation(DeleteTargetDocument); + const [, mutate] = useMutation(DeleteTargetMutation); const { replace } = useRouter(); return ( diff --git a/packages/web/app/src/config/supertokens/backend.ts b/packages/web/app/src/config/supertokens/backend.ts index c0653a0af..490e6d1d1 100644 --- a/packages/web/app/src/config/supertokens/backend.ts +++ b/packages/web/app/src/config/supertokens/backend.ts @@ -17,7 +17,7 @@ import { createThirdPartyEmailPasswordNodeOktaProvider } from '@/lib/supertokens // eslint-disable-next-line import/no-extraneous-dependencies -- TODO: should we move to "dependencies"? import { EmailsApi } from '@hive/emails'; // eslint-disable-next-line import/no-extraneous-dependencies -- TODO: should we move to "dependencies"? -import { InternalApi } from '@hive/server'; +import { type InternalApi } from '@hive/server'; import { createTRPCProxyClient, CreateTRPCProxyClient, httpLink } from '@trpc/client'; import { fetch } from '@whatwg-node/fetch'; diff --git a/packages/web/app/src/graphql/mutation.delete-persisted-operation.graphql b/packages/web/app/src/graphql/mutation.delete-persisted-operation.graphql deleted file mode 100644 index 07b9cea85..000000000 --- a/packages/web/app/src/graphql/mutation.delete-persisted-operation.graphql +++ /dev/null @@ -1,9 +0,0 @@ -mutation deletePersistedOperation($input: PersistedOperationSelectorInput!) { - deletePersistedOperation(selector: $input) { - deletedPersistedOperation { - __typename - id - operationHash - } - } -} diff --git a/packages/web/app/src/graphql/mutation.delete-project.graphql b/packages/web/app/src/graphql/mutation.delete-project.graphql deleted file mode 100644 index b25e23774..000000000 --- a/packages/web/app/src/graphql/mutation.delete-project.graphql +++ /dev/null @@ -1,12 +0,0 @@ -mutation deleteProject($selector: ProjectSelectorInput!) { - deleteProject(selector: $selector) { - selector { - organization - project - } - deletedProject { - __typename - id - } - } -} diff --git a/packages/web/app/src/graphql/mutation.delete-target.graphql b/packages/web/app/src/graphql/mutation.delete-target.graphql deleted file mode 100644 index c8f356c4f..000000000 --- a/packages/web/app/src/graphql/mutation.delete-target.graphql +++ /dev/null @@ -1,13 +0,0 @@ -mutation deleteTarget($selector: TargetSelectorInput!) { - deleteTarget(selector: $selector) { - selector { - organization - project - target - } - deletedTarget { - __typename - id - } - } -} diff --git a/packages/web/app/src/graphql/mutation.send-feedback.graphql b/packages/web/app/src/graphql/mutation.send-feedback.graphql deleted file mode 100644 index d13b13acf..000000000 --- a/packages/web/app/src/graphql/mutation.send-feedback.graphql +++ /dev/null @@ -1,3 +0,0 @@ -mutation sendFeedback($feedback: String!) { - sendFeedback(feedback: $feedback) -} diff --git a/packages/web/app/src/graphql/mutation.set-target-validation.graphql b/packages/web/app/src/graphql/mutation.set-target-validation.graphql deleted file mode 100644 index 47fb4abc4..000000000 --- a/packages/web/app/src/graphql/mutation.set-target-validation.graphql +++ /dev/null @@ -1,8 +0,0 @@ -mutation setTargetValidation($input: SetTargetValidationInput!) { - setTargetValidation(input: $input) { - id - validationSettings { - ...TargetValidationSettingsFields - } - } -} diff --git a/packages/web/app/src/graphql/mutation.update-organization-member-access.graphql b/packages/web/app/src/graphql/mutation.update-organization-member-access.graphql deleted file mode 100644 index 73e59f94c..000000000 --- a/packages/web/app/src/graphql/mutation.update-organization-member-access.graphql +++ /dev/null @@ -1,10 +0,0 @@ -mutation updateOrganizationMemberAccess($input: OrganizationMemberAccessInput!) { - updateOrganizationMemberAccess(input: $input) { - selector { - organization - } - organization { - ...OrganizationFields - } - } -} diff --git a/packages/web/app/src/graphql/mutation.update-schema-version-status.graphql b/packages/web/app/src/graphql/mutation.update-schema-version-status.graphql deleted file mode 100644 index 6fd3a2376..000000000 --- a/packages/web/app/src/graphql/mutation.update-schema-version-status.graphql +++ /dev/null @@ -1,5 +0,0 @@ -mutation updateSchemaVersionStatus($input: SchemaVersionUpdateInput!) { - updateSchemaVersionStatus(input: $input) { - ...SchemaVersionFields - } -} diff --git a/packages/web/app/src/graphql/mutation.update-target-name.graphql b/packages/web/app/src/graphql/mutation.update-target-name.graphql deleted file mode 100644 index 4a6456311..000000000 --- a/packages/web/app/src/graphql/mutation.update-target-name.graphql +++ /dev/null @@ -1,14 +0,0 @@ -mutation updateTargetName($input: UpdateTargetNameInput!) { - updateTargetName(input: $input) { - ok { - selector { - organization - project - target - } - updatedTarget { - ...TargetFields - } - } - } -} diff --git a/packages/web/app/src/graphql/query.general-operations-stats.graphql b/packages/web/app/src/graphql/query.general-operations-stats.graphql deleted file mode 100644 index a92da3f6e..000000000 --- a/packages/web/app/src/graphql/query.general-operations-stats.graphql +++ /dev/null @@ -1,49 +0,0 @@ -query generalOperationsStats($selector: OperationsStatsSelectorInput!, $resolution: Int!) { - operationsStats(selector: $selector) { - ... on OperationsStats { - totalRequests - totalFailures - totalOperations - duration { - p75 - p90 - p95 - p99 - } - } - ... on OperationsStats { - failuresOverTime(resolution: $resolution) { - date - value - } - requestsOverTime(resolution: $resolution) { - date - value - } - durationOverTime(resolution: $resolution) { - date - duration { - p75 - p90 - p95 - p99 - } - } - } - ... on OperationsStats { - clients { - nodes { - name - count - percentage - versions { - version - count - percentage - } - } - total - } - } - } -} diff --git a/packages/web/app/src/graphql/query.has-collected-operations.graphql b/packages/web/app/src/graphql/query.has-collected-operations.graphql deleted file mode 100644 index 0cd391d8a..000000000 --- a/packages/web/app/src/graphql/query.has-collected-operations.graphql +++ /dev/null @@ -1,3 +0,0 @@ -query hasCollectedOperations($selector: TargetSelectorInput!) { - hasCollectedOperations(selector: $selector) -} diff --git a/packages/web/app/src/graphql/query.operations-stats.graphql b/packages/web/app/src/graphql/query.operations-stats.graphql deleted file mode 100644 index b4c3cc199..000000000 --- a/packages/web/app/src/graphql/query.operations-stats.graphql +++ /dev/null @@ -1,16 +0,0 @@ -query operationsStats($selector: OperationsStatsSelectorInput!) { - operationsStats(selector: $selector) { - operations { - nodes { - ...OperationStatsFields - } - total - } - clients { - nodes { - name - count - } - } - } -} diff --git a/packages/web/app/src/graphql/query.org-usage-estimation.graphql b/packages/web/app/src/graphql/query.org-usage-estimation.graphql deleted file mode 100644 index 5f1fea32a..000000000 --- a/packages/web/app/src/graphql/query.org-usage-estimation.graphql +++ /dev/null @@ -1,7 +0,0 @@ -query usageEstimation($range: DateRangeInput!, $organization: ID!) { - usageEstimation(range: $range) { - org(selector: { organization: $organization }) { - operations - } - } -} diff --git a/packages/web/app/src/graphql/query.organizations.graphql b/packages/web/app/src/graphql/query.organizations.graphql deleted file mode 100644 index 802ce2ac4..000000000 --- a/packages/web/app/src/graphql/query.organizations.graphql +++ /dev/null @@ -1,8 +0,0 @@ -query organizations { - organizations { - nodes { - ...OrganizationFields - } - total - } -} diff --git a/packages/web/app/src/graphql/query.project-activities.graphql b/packages/web/app/src/graphql/query.project-activities.graphql deleted file mode 100644 index 19f9e1cf1..000000000 --- a/packages/web/app/src/graphql/query.project-activities.graphql +++ /dev/null @@ -1,18 +0,0 @@ -query projectActivities($selector: ProjectActivitiesSelector!) { - projectActivities(selector: $selector) { - nodes { - __typename - id - createdAt - ...ProjectCreated - ...ProjectDeleted - ...ProjectNameUpdated - ...ProjectIdUpdated - ...TargetCreated - ...TargetDeleted - ...TargetNameUpdated - ...TargetIdUpdated - } - total - } -} diff --git a/packages/web/app/src/graphql/query.projects-with-targets.graphql b/packages/web/app/src/graphql/query.projects-with-targets.graphql deleted file mode 100644 index 0ee36cd84..000000000 --- a/packages/web/app/src/graphql/query.projects-with-targets.graphql +++ /dev/null @@ -1,14 +0,0 @@ -query projectsWithTargets($selector: OrganizationSelectorInput!) { - projects(selector: $selector) { - nodes { - ...ProjectFields - targets { - nodes { - ...TargetFields - } - total - } - } - total - } -} diff --git a/packages/web/app/src/graphql/query.projects.graphql b/packages/web/app/src/graphql/query.projects.graphql deleted file mode 100644 index b0a1708e9..000000000 --- a/packages/web/app/src/graphql/query.projects.graphql +++ /dev/null @@ -1,8 +0,0 @@ -query projects($selector: OrganizationSelectorInput!) { - projects(selector: $selector) { - nodes { - ...ProjectFields - } - total - } -} diff --git a/packages/web/app/src/graphql/query.target-activities.graphql b/packages/web/app/src/graphql/query.target-activities.graphql deleted file mode 100644 index b105f3cf7..000000000 --- a/packages/web/app/src/graphql/query.target-activities.graphql +++ /dev/null @@ -1,14 +0,0 @@ -query targetActivities($selector: TargetActivitiesSelector!) { - targetActivities(selector: $selector) { - nodes { - __typename - id - createdAt - ...TargetCreated - ...TargetDeleted - ...TargetNameUpdated - ...TargetIdUpdated - } - total - } -} diff --git a/packages/web/app/src/graphql/query.targets.graphql b/packages/web/app/src/graphql/query.targets.graphql deleted file mode 100644 index 661de4a6d..000000000 --- a/packages/web/app/src/graphql/query.targets.graphql +++ /dev/null @@ -1,8 +0,0 @@ -query targets($selector: ProjectSelectorInput!) { - targets(selector: $selector) { - total - nodes { - ...TargetFields - } - } -} diff --git a/packages/web/app/src/lib/supertokens/third-party-email-password-node-oidc-provider.ts b/packages/web/app/src/lib/supertokens/third-party-email-password-node-oidc-provider.ts index aa66c09da..25af31c46 100644 --- a/packages/web/app/src/lib/supertokens/third-party-email-password-node-oidc-provider.ts +++ b/packages/web/app/src/lib/supertokens/third-party-email-password-node-oidc-provider.ts @@ -4,7 +4,7 @@ import { TypeInput as ThirdPartEmailPasswordTypeInput } from 'supertokens-node/r import zod from 'zod'; import { env } from '@/env/backend'; // eslint-disable-next-line import/no-extraneous-dependencies -- TODO: should we move to "dependencies"? -import { InternalApi } from '@hive/server'; +import { type InternalApi } from '@hive/server'; import { CreateTRPCProxyClient } from '@trpc/client'; const OIDCProfileInfoSchema = zod.object({ diff --git a/packages/web/app/src/lib/urql-cache.ts b/packages/web/app/src/lib/urql-cache.ts index 43fc50f2b..854ad1f17 100644 --- a/packages/web/app/src/lib/urql-cache.ts +++ b/packages/web/app/src/lib/urql-cache.ts @@ -14,20 +14,17 @@ import type { CreateOrganizationMutation } from '@/components/v2/modals/create-o import type { CreateProjectMutation } from '@/components/v2/modals/create-project'; import type { CreateTarget_CreateTargetMutation } from '@/components/v2/modals/create-target'; import type { DeleteOrganizationDocument } from '@/components/v2/modals/delete-organization'; +import { type DeleteProjectMutation } from '@/components/v2/modals/delete-project'; +import { type DeleteTargetMutation } from '@/components/v2/modals/delete-target'; import { graphql } from '@/gql'; import { ResultOf, VariablesOf } from '@graphql-typed-document-node/core'; import { Cache, QueryInput, UpdateResolver } from '@urql/exchange-graphcache'; +import { OrganizationsQuery } from '../../pages'; import { CollectionsQuery } from '../../pages/[orgId]/[projectId]/[targetId]/laboratory'; import { TokensDocument, type DeleteTokensDocument, } from '../../pages/[orgId]/[projectId]/[targetId]/settings'; -import { - DeletePersistedOperationDocument, - DeleteProjectDocument, - DeleteTargetDocument, - OrganizationsDocument, -} from '../graphql'; const TargetsDocument = graphql(` query targets($selector: ProjectSelectorInput!) { @@ -85,7 +82,7 @@ const createOrganization: TypedDocumentNodeUpdateResolver { if (createOrganization.ok) { @@ -127,7 +124,7 @@ const createProject: TypedDocumentNodeUpdateResolver = ( +const deleteProject: TypedDocumentNodeUpdateResolver = ( { deleteProject }, _args, cache, @@ -171,7 +168,7 @@ const createTarget: TypedDocumentNodeUpdateResolver = ( +const deleteTarget: TypedDocumentNodeUpdateResolver = ( { deleteTarget }, _args, cache, @@ -279,16 +276,6 @@ const addAlert: TypedDocumentNodeUpdateResolver = ({ deletePersistedOperation }, _args, cache) => { - const operation = deletePersistedOperation.deletedPersistedOperation; - - cache.invalidate({ - __typename: operation.__typename, - id: operation.id, - }); -}; const deleteDocumentCollection: TypedDocumentNodeUpdateResolver = ( mutation, @@ -387,7 +374,6 @@ export const Mutation = { addAlertChannel, deleteAlertChannels, addAlert, - deletePersistedOperation, deleteDocumentCollection, deleteOperationInDocumentCollection, createOperationInDocumentCollection, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dd4e08f16..c13a4fbe6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.1' +lockfileVersion: '6.0' settings: autoInstallPeers: true @@ -1703,9 +1703,6 @@ importers: '@hive/emails': specifier: workspace:* version: link:../../services/emails - '@hive/server': - specifier: workspace:* - version: link:../../services/server '@next/bundle-analyzer': specifier: 13.4.11 version: 13.4.11 diff --git a/turbo.json b/turbo.json index 2bd16e1f6..62f003ca8 100644 --- a/turbo.json +++ b/turbo.json @@ -39,8 +39,9 @@ "dependsOn": ["^build", "@graphql-hive/client#build"], "outputs": ["dist/**"] }, - "typecheck": { - "outputs": [""] + "@hive/server#build": { + "dependsOn": ["^build", "@hive/app#build"], + "outputs": ["dist/**"] }, "check:build": { "outputs": [""]