Skip to content

Commit 93967de

Browse files
authored
feat: search app deployment version by operation name (#7060)
1 parent d1ec149 commit 93967de

File tree

7 files changed

+81
-7
lines changed

7 files changed

+81
-7
lines changed

.changeset/thirty-laws-hang.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'hive': minor
3+
---
4+
5+
add search to app deployment version by operation name

packages/services/api/src/modules/app-deployments/module.graphql.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ export default gql`
55
id: ID!
66
name: String!
77
version: String!
8-
documents(first: Int, after: String): GraphQLDocumentConnection
8+
documents(
9+
first: Int
10+
after: String
11+
filter: AppDeploymentDocumentsFilterInput
12+
): GraphQLDocumentConnection
913
totalDocumentCount: Int!
1014
status: AppDeploymentStatus!
1115
"""
@@ -54,6 +58,10 @@ export default gql`
5458
node: AppDeployment!
5559
}
5660
61+
input AppDeploymentDocumentsFilterInput {
62+
operationName: String
63+
}
64+
5765
extend type Target {
5866
"""
5967
The app deployments for this target.

packages/services/api/src/modules/app-deployments/providers/app-deployments-manager.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,14 @@ export class AppDeploymentsManager {
192192
args: {
193193
cursor: string | null;
194194
first: number | null;
195+
operationName: string;
195196
},
196197
) {
197198
return await this.appDeployments.getPaginatedGraphQLDocuments({
198199
appDeploymentId: appDeployment.id,
199200
cursor: args.cursor,
200201
first: args.first,
202+
operationName: args.operationName,
201203
});
202204
}
203205

packages/services/api/src/modules/app-deployments/providers/app-deployments.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,9 +690,11 @@ export class AppDeployments {
690690
appDeploymentId: string;
691691
cursor: string | null;
692692
first: number | null;
693+
operationName: string;
693694
}) {
694695
const limit = args.first ? (args.first > 0 ? Math.min(args.first, 20) : 20) : 20;
695696
const cursor = args.cursor ? decodeHashBasedCursor(args.cursor) : null;
697+
const operationName = args.operationName.trim();
696698
const result = await this.clickhouse.query({
697699
query: cSql`
698700
SELECT
@@ -705,7 +707,8 @@ export class AppDeployments {
705707
WHERE
706708
"app_deployment_id" = ${args.appDeploymentId}
707709
${cursor?.id ? cSql`AND "document_hash" > ${cursor.id}` : cSql``}
708-
ORDER BY "app_deployment_id", "document_hash"
710+
${operationName.length ? cSql`AND "operation_name" ILIKE CONCAT('%', ${operationName}, '%')` : cSql``}
711+
ORDER BY "app_deployment_id", ${operationName.length ? cSql`positionCaseInsensitive("operation_name", ${operationName}) ASC, "operation_name" ASC` : cSql`"document_hash"`}
709712
LIMIT 1 BY "app_deployment_id", "document_hash"
710713
LIMIT ${cSql.raw(String(limit + 1))}
711714
`,

packages/services/api/src/modules/app-deployments/resolvers/AppDeployment.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const AppDeployment: AppDeploymentResolvers = {
2121
.getPaginatedDocumentsForAppDeployment(appDeployment, {
2222
cursor: args.after ?? null,
2323
first: args.first ?? null,
24+
operationName: args.filter?.operationName ?? '',
2425
});
2526
},
2627
totalDocumentCount: async (appDeployment, _, { injector }) => {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { useCallback } from 'react';
2+
import { Input } from '@/components/ui/input';
3+
import { useRouter } from '@tanstack/react-router';
4+
5+
export function AppFilter() {
6+
const router = useRouter();
7+
const cb = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
8+
void router.navigate({
9+
search: {
10+
...router.latestLocation.search,
11+
search: e.target.value === '' ? undefined : e.target.value,
12+
},
13+
replace: true,
14+
});
15+
}, []);
16+
const initialValue =
17+
'search' in router.latestLocation.search &&
18+
typeof router.latestLocation.search.search === 'string'
19+
? router.latestLocation.search.search
20+
: '';
21+
22+
return (
23+
<Input
24+
className="min-w-[200px] grow cursor-text"
25+
placeholder="Search by operation name..."
26+
onChange={cb}
27+
defaultValue={initialValue}
28+
/>
29+
);
30+
}

packages/web/app/src/pages/target-app-version.tsx

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { useState } from 'react';
1+
import { useEffect, useState } from 'react';
22
import ghost from '../../public/images/figures/ghost.svg?url';
33
import { LoaderCircleIcon } from 'lucide-react';
44
import { useClient, useQuery } from 'urql';
5+
import { AppFilter } from '@/components/apps/AppFilter';
56
import { Page, TargetLayout } from '@/components/layouts/target';
67
import { Button } from '@/components/ui/button';
78
import { CardDescription } from '@/components/ui/card';
@@ -40,6 +41,7 @@ const TargetAppsVersionQuery = graphql(`
4041
$appVersion: String!
4142
$first: Int
4243
$after: String
44+
$documentsFilter: AppDeploymentDocumentsFilterInput
4345
) {
4446
target(
4547
reference: {
@@ -56,7 +58,7 @@ const TargetAppsVersionQuery = graphql(`
5658
id
5759
name
5860
version
59-
documents(first: $first, after: $after) {
61+
documents(first: $first, after: $after, filter: $documentsFilter) {
6062
pageInfo {
6163
hasNextPage
6264
endCursor
@@ -82,6 +84,21 @@ function TargetAppVersionContent(props: {
8284
appName: string;
8385
appVersion: string;
8486
}) {
87+
const router = useRouter();
88+
const search =
89+
typeof router.latestLocation.search.search === 'string'
90+
? router.latestLocation.search.search
91+
: '';
92+
const [debouncedSearch, setDebouncedSearch] = useState('');
93+
useEffect(() => {
94+
const handler = setTimeout(() => {
95+
setDebouncedSearch(search);
96+
}, 500); // 500ms debounce delay
97+
98+
return () => {
99+
clearTimeout(handler);
100+
};
101+
}, [search]);
85102
const [data] = useQuery({
86103
query: TargetAppsVersionQuery,
87104
variables: {
@@ -92,9 +109,11 @@ function TargetAppVersionContent(props: {
92109
appVersion: props.appVersion,
93110
first: 20,
94111
after: null,
112+
documentsFilter: {
113+
operationName: debouncedSearch,
114+
},
95115
},
96116
});
97-
const router = useRouter();
98117
const client = useClient();
99118
const [isLoadingMore, setIsLoadingMore] = useState(false);
100119

@@ -197,7 +216,9 @@ function TargetAppVersionContent(props: {
197216
</CardDescription> */}
198217
</>
199218
}
200-
/>
219+
>
220+
<AppFilter />
221+
</SubPageLayoutHeader>
201222
<div className="mt-4" />
202223
{data.fetching || data.stale ? (
203224
<div className="flex h-fit flex-1 items-center justify-center">
@@ -208,7 +229,11 @@ function TargetAppVersionContent(props: {
208229
</div>
209230
) : !data.data?.target?.appDeployment?.documents?.edges.length ? (
210231
<EmptyList
211-
title="No documents have been uploaded for this app deployment"
232+
title={
233+
debouncedSearch
234+
? 'No documents found matching that operation name'
235+
: 'No documents have been uploaded for this app deployment'
236+
}
212237
description="You can upload documents via the Hive CLI"
213238
docsUrl="/features/schema-registry#app-deplyments"
214239
/>

0 commit comments

Comments
 (0)