This is an automated email from the ASF dual-hosted git repository. young pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/apisix-dashboard.git
The following commit(s) were added to refs/heads/master by this push: new 40e616779 refactor: standardize request methods (#3075) 40e616779 is described below commit 40e6167794afb0ebd6c682b8daff32f86c8d6660 Author: YYYoung <isk...@outlook.com> AuthorDate: Wed May 21 14:03:01 2025 +0800 refactor: standardize request methods (#3075) * refactor: use table pagination in all list pages * feat: gen hooks from factory func * fix: logic * fix: detail query options * fix: * chore * fix: credentials params * fix(useSearchParams): `setParams` type --- src/apis/consumer_groups.ts | 48 ++--- src/apis/consumers.ts | 40 ++-- src/apis/credentials.ts | 75 ++++--- src/apis/global_rules.ts | 44 ++++ src/apis/hooks.ts | 221 ++++++++++++++++++--- src/apis/plugin_configs.ts | 42 ++-- src/apis/plugins.ts | 19 -- src/apis/protos.ts | 43 ++-- src/apis/routes.ts | 1 - src/apis/secrets.ts | 55 +++-- src/apis/services.ts | 40 ++-- src/apis/ssls.ts | 42 ++-- src/apis/stream_routes.ts | 48 ++--- src/apis/upstreams.ts | 1 - src/routes/consumer_groups/add.tsx | 6 +- src/routes/consumer_groups/detail.$id.tsx | 12 +- src/routes/consumer_groups/index.tsx | 30 +-- src/routes/consumers/add.tsx | 5 +- .../consumers/detail.$username/credentials/add.tsx | 12 +- .../detail.$username/credentials/detail.$id.tsx | 21 +- .../detail.$username/credentials/index.tsx | 18 +- src/routes/consumers/detail.$username/index.tsx | 8 +- src/routes/consumers/index.tsx | 34 +--- src/routes/global_rules/add.tsx | 31 ++- src/routes/global_rules/detail.$id.tsx | 34 ++-- src/routes/global_rules/index.tsx | 122 +++++------- src/routes/plugin_configs/add.tsx | 6 +- src/routes/plugin_configs/detail.$id.tsx | 18 +- src/routes/plugin_configs/index.tsx | 30 +-- src/routes/protos/add.tsx | 22 +- src/routes/protos/detail.$id.tsx | 12 +- src/routes/protos/index.tsx | 28 +-- src/routes/secrets/add.tsx | 12 +- src/routes/secrets/detail.$manager.$id.tsx | 13 +- src/routes/secrets/index.tsx | 28 +-- src/routes/services/add.tsx | 11 +- src/routes/services/detail.$id.tsx | 19 +- src/routes/services/index.tsx | 27 +-- src/routes/ssls/add.tsx | 12 +- src/routes/ssls/detail.$id.tsx | 9 +- src/routes/ssls/index.tsx | 28 +-- src/routes/stream_routes/add.tsx | 15 +- src/routes/stream_routes/detail.$id.tsx | 18 +- src/routes/stream_routes/index.tsx | 27 +-- src/routes/upstreams/add.tsx | 2 +- src/routes/upstreams/detail.$id.tsx | 2 +- src/types/schema/pageSearch.ts | 51 ++--- src/utils/usePagination.ts | 174 ---------------- src/utils/useSearchParams.ts | 24 ++- src/utils/useTablePagination.ts | 19 +- 50 files changed, 682 insertions(+), 977 deletions(-) diff --git a/src/apis/consumer_groups.ts b/src/apis/consumer_groups.ts index 189e46a88..f7f73864e 100644 --- a/src/apis/consumer_groups.ts +++ b/src/apis/consumer_groups.ts @@ -14,41 +14,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { queryOptions } from '@tanstack/react-query'; +import type { AxiosInstance } from 'axios'; import { API_CONSUMER_GROUPS } from '@/config/constant'; -import { req } from '@/config/req'; import type { APISIXType } from '@/types/schema/apisix'; import type { PageSearchType } from '@/types/schema/pageSearch'; -export const getConsumerGroupListQueryOptions = (props: PageSearchType) => { - const { page, pageSize } = props; - return queryOptions({ - queryKey: ['consumer_groups', page, pageSize], - queryFn: () => - req - .get<unknown, APISIXType['RespConsumerGroupList']>( - API_CONSUMER_GROUPS, - { - params: { page, page_size: pageSize }, - } - ) - .then((v) => v.data), - }); -}; +export const getConsumerGroupListReq = ( + req: AxiosInstance, + params: PageSearchType +) => + req + .get<unknown, APISIXType['RespConsumerGroupList']>(API_CONSUMER_GROUPS, { + params, + }) + .then((v) => v.data); -export const getConsumerGroupQueryOptions = (id: string) => - queryOptions({ - queryKey: ['consumer_group', id], - queryFn: () => - req - .get<unknown, APISIXType['RespConsumerGroupDetail']>( - `${API_CONSUMER_GROUPS}/${id}` - ) - .then((v) => v.data), - }); +export const getConsumerGroupReq = (req: AxiosInstance, id: string) => + req + .get<unknown, APISIXType['RespConsumerGroupDetail']>( + `${API_CONSUMER_GROUPS}/${id}` + ) + .then((v) => v.data); -export const putConsumerGroupReq = (data: APISIXType['ConsumerGroupPut']) => { +export const putConsumerGroupReq = ( + req: AxiosInstance, + data: APISIXType['ConsumerGroupPut'] +) => { const { id, ...rest } = data; return req.put< APISIXType['ConsumerGroupPut'], diff --git a/src/apis/consumers.ts b/src/apis/consumers.ts index f19aa1831..c4779df1c 100644 --- a/src/apis/consumers.ts +++ b/src/apis/consumers.ts @@ -14,36 +14,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { queryOptions } from '@tanstack/react-query'; +import type { AxiosInstance } from 'axios'; import { API_CONSUMERS } from '@/config/constant'; -import { req } from '@/config/req'; import type { APISIXType } from '@/types/schema/apisix'; import type { PageSearchType } from '@/types/schema/pageSearch'; -export const getConsumerListQueryOptions = (props: PageSearchType) => { - const { page, pageSize } = props; - return queryOptions({ - queryKey: ['consumers', page, pageSize], - queryFn: () => - req - .get<unknown, APISIXType['RespConsumerList']>(API_CONSUMERS, { - params: { page, page_size: pageSize }, - }) - .then((v) => v.data), - }); -}; +export const getConsumerListReq = (req: AxiosInstance, params: PageSearchType) => + req + .get<unknown, APISIXType['RespConsumerList']>(API_CONSUMERS, { + params, + }) + .then((v) => v.data); -export const getConsumerQueryOptions = (username: string) => - queryOptions({ - queryKey: ['consumer', username], - queryFn: () => - req - .get<unknown, APISIXType['RespConsumerDetail']>(`${API_CONSUMERS}/${username}`) - .then((v) => v.data), - }); +export const getConsumerReq = (req: AxiosInstance, username: string) => + req + .get<unknown, APISIXType['RespConsumerDetail']>( + `${API_CONSUMERS}/${username}` + ) + .then((v) => v.data); -export const putConsumerReq = (data: APISIXType['ConsumerPut']) => { +export const putConsumerReq = ( + req: AxiosInstance, + data: APISIXType['ConsumerPut'] +) => { return req.put<APISIXType['ConsumerPut'], APISIXType['RespConsumerDetail']>( API_CONSUMERS, data diff --git a/src/apis/credentials.ts b/src/apis/credentials.ts index 94537171b..574459825 100644 --- a/src/apis/credentials.ts +++ b/src/apis/credentials.ts @@ -14,55 +14,48 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { queryOptions } from '@tanstack/react-query'; + +import type { AxiosInstance } from 'axios'; import { API_CREDENTIALS, SKIP_INTERCEPTOR_HEADER } from '@/config/constant'; -import { req } from '@/config/req'; import type { APISIXType } from '@/types/schema/apisix'; import type { APISIXListResponse } from '@/types/schema/apisix/type'; -type WithUsername = Pick<APISIXType['Consumer'], 'username'>; -export const getCredentialListQueryOptions = (props: WithUsername) => { - const { username } = props; - return queryOptions({ - queryKey: ['credentials', username], - queryFn: () => - req - .get<unknown, APISIXType['RespCredentialList']>( - API_CREDENTIALS(username), - { - headers: { - [SKIP_INTERCEPTOR_HEADER]: ['404'], - }, - } - ) - .then((v) => v.data) - .catch((e) => { - // 404 means credentials is empty - if (e.response.status === 404) { - const res: APISIXListResponse<APISIXType['Credential']> = { - total: 0, - list: [], - }; - return res; - } - throw e; - }), - }); -}; +export type WithUsername = Pick<APISIXType['Consumer'], 'username'>; + +export const getCredentialListReq = (req: AxiosInstance, params: WithUsername) => + req + .get<unknown, APISIXType['RespCredentialList']>( + API_CREDENTIALS(params.username), + { + headers: { + [SKIP_INTERCEPTOR_HEADER]: ['404'], + }, + params, + } + ) + .then((v) => v.data) + .catch((e) => { + // 404 means credentials is empty + if (e.response.status === 404) { + const res: APISIXListResponse<APISIXType['Credential']> = { + total: 0, + list: [], + }; + return res; + } + throw e; + }); -export const getCredentialQueryOptions = (username: string, id: string) => - queryOptions({ - queryKey: ['credential', username, id], - queryFn: () => - req - .get<unknown, APISIXType['RespCredentialDetail']>( - `${API_CREDENTIALS(username)}/${id}` - ) - .then((v) => v.data), - }); +export const getCredentialReq = (req: AxiosInstance, username: string, id: string) => + req + .get<unknown, APISIXType['RespCredentialDetail']>( + `${API_CREDENTIALS(username)}/${id}` + ) + .then((v) => v.data); export const putCredentialReq = ( + req: AxiosInstance, data: APISIXType['CredentialPut'] & WithUsername ) => { const { username, id, ...rest } = data; diff --git a/src/apis/global_rules.ts b/src/apis/global_rules.ts new file mode 100644 index 000000000..4572f7ad0 --- /dev/null +++ b/src/apis/global_rules.ts @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { AxiosInstance } from 'axios'; + +import { API_GLOBAL_RULES } from '@/config/constant'; +import type { APISIXType } from '@/types/schema/apisix'; + +export const getGlobalRuleListReq = (req: AxiosInstance) => + req + .get<unknown, APISIXType['RespGlobalRuleList']>(API_GLOBAL_RULES) + .then((v) => v.data); + +export const getGlobalRuleReq = (req: AxiosInstance, id: string) => + req + .get<unknown, APISIXType['RespGlobalRuleDetail']>( + `${API_GLOBAL_RULES}/${id}` + ) + .then((v) => v.data); + +export const putGlobalRuleReq = ( + req: AxiosInstance, + data: APISIXType['GlobalRulePut'] +) => { + const { id, ...rest } = data; + return req.put< + APISIXType['GlobalRulePut'], + APISIXType['RespGlobalRuleDetail'] + >(`${API_GLOBAL_RULES}/${id}`, rest); +}; diff --git a/src/apis/hooks.ts b/src/apis/hooks.ts index f1e6d569a..118fa6b12 100644 --- a/src/apis/hooks.ts +++ b/src/apis/hooks.ts @@ -15,47 +15,208 @@ * limitations under the License. */ import { queryOptions, useSuspenseQuery } from '@tanstack/react-query'; +import type { AxiosInstance } from 'axios'; -import { getUpstreamListReq } from '@/apis/upstreams'; +import { getRouteListReq, getRouteReq } from '@/apis/routes'; +import { getUpstreamListReq, getUpstreamReq } from '@/apis/upstreams'; import { req } from '@/config/req'; +import type { + APISIXDetailResponse, + APISIXListResponse, +} from '@/types/schema/apisix/type'; import { type PageSearchType } from '@/types/schema/pageSearch'; import { useSearchParams } from '@/utils/useSearchParams'; -import { useTablePagination } from '@/utils/useTablePagination'; +import { + type ListPageKeys, + useTablePagination, +} from '@/utils/useTablePagination'; -import { getRouteListReq, getRouteReq } from './routes'; +import { + getConsumerGroupListReq, + getConsumerGroupReq, +} from './consumer_groups'; +import { getConsumerListReq, getConsumerReq } from './consumers'; +import { getCredentialListReq, getCredentialReq } from './credentials'; +import { getGlobalRuleListReq, getGlobalRuleReq } from './global_rules'; +import { getPluginConfigListReq, getPluginConfigReq } from './plugin_configs'; +import { getProtoListReq, getProtoReq } from './protos'; +import { getSecretListReq, getSecretReq } from './secrets'; +import { getServiceListReq, getServiceReq } from './services'; +import { getSSLListReq, getSSLReq } from './ssls'; +import { getStreamRouteListReq, getStreamRouteReq } from './stream_routes'; -export const getUpstreamListQueryOptions = (props: PageSearchType) => { - return queryOptions({ - queryKey: ['upstreams', props.page, props.page_size], - queryFn: () => getUpstreamListReq(req, props), - }); -}; +const genDetailQueryOptions = + <T extends unknown[], R>( + key: string, + getDetailReq: ( + req: AxiosInstance, + ...args: T + ) => Promise<APISIXDetailResponse<R>> + ) => + (...args: T) => { + return queryOptions({ + queryKey: [key, ...args], + queryFn: () => getDetailReq(req, ...args), + }); + }; +/** simple factory func for list query options which support extends PageSearchType */ +const genListQueryOptions = + <P extends PageSearchType, R>( + key: string, + listReq: (req: AxiosInstance, props: P) => Promise<APISIXListResponse<R>> + ) => + (props: P) => { + return queryOptions({ + queryKey: [key, props], + queryFn: () => listReq(req, props), + }); + }; -export const useUpstreamList = () => { - const { params, setParams } = useSearchParams('/upstreams/'); - const upstreamQuery = useSuspenseQuery(getUpstreamListQueryOptions(params)); - const { data, isLoading, refetch } = upstreamQuery; - const pagination = useTablePagination({ data, setParams, params }); - return { data, isLoading, refetch, pagination }; +/** simple hook factory func for list hooks which support extends PageSearchType */ +export const genUseList = <T extends ListPageKeys, P extends PageSearchType, R>( + routeId: T, + listQueryOptions: ReturnType<typeof genListQueryOptions<P, R>> +) => { + return () => { + const { params, setParams } = useSearchParams<T, P>(routeId); + const listQuery = useSuspenseQuery(listQueryOptions(params)); + const { data, isLoading, refetch } = listQuery; + const opts = { data, setParams, params }; + const pagination = useTablePagination(opts); + return { data, isLoading, refetch, pagination }; + }; }; -export const getRouteListQueryOptions = (props: PageSearchType) => { +export const getUpstreamQueryOptions = genDetailQueryOptions( + 'upstream', + getUpstreamReq +); +export const getUpstreamListQueryOptions = genListQueryOptions( + 'upstreams', + getUpstreamListReq +); +export const useUpstreamList = genUseList( + '/upstreams/', + getUpstreamListQueryOptions +); + +export const getRouteQueryOptions = genDetailQueryOptions('route', getRouteReq); +export const getRouteListQueryOptions = genListQueryOptions( + 'routes', + getRouteListReq +); +export const useRouteList = genUseList('/routes/', getRouteListQueryOptions); + +export const getConsumerGroupQueryOptions = genDetailQueryOptions( + 'consumer_group', + getConsumerGroupReq +); +export const getConsumerGroupListQueryOptions = genListQueryOptions( + 'consumer_groups', + getConsumerGroupListReq +); +export const useConsumerGroupList = genUseList( + '/consumer_groups/', + getConsumerGroupListQueryOptions +); + +export const getStreamRouteQueryOptions = genDetailQueryOptions( + 'stream_route', + getStreamRouteReq +); +export const getStreamRouteListQueryOptions = genListQueryOptions( + 'stream_routes', + getStreamRouteListReq +); +export const useStreamRouteList = genUseList( + '/stream_routes/', + getStreamRouteListQueryOptions +); + +export const getServiceQueryOptions = genDetailQueryOptions( + 'service', + getServiceReq +); +export const getServiceListQueryOptions = genListQueryOptions( + 'services', + getServiceListReq +); +export const useServiceList = genUseList( + '/services/', + getServiceListQueryOptions +); + +export const getGlobalRuleQueryOptions = genDetailQueryOptions( + 'global_rule', + getGlobalRuleReq +); +export const getGlobalRuleListQueryOptions = genListQueryOptions( + 'global_rules', + getGlobalRuleListReq +); +export const useGlobalRuleList = genUseList( + '/global_rules/', + getGlobalRuleListQueryOptions +); + +export const getPluginConfigQueryOptions = genDetailQueryOptions( + 'plugin_config', + getPluginConfigReq +); +export const getPluginConfigListQueryOptions = genListQueryOptions( + 'plugin_configs', + getPluginConfigListReq +); +export const usePluginConfigList = genUseList( + '/plugin_configs/', + getPluginConfigListQueryOptions +); + +export const getSSLQueryOptions = genDetailQueryOptions('ssl', getSSLReq); +export const getSSLListQueryOptions = genListQueryOptions('ssls', getSSLListReq); +export const useSSLList = genUseList('/ssls/', getSSLListQueryOptions); + +export const getConsumerQueryOptions = genDetailQueryOptions( + 'consumer', + getConsumerReq +); +export const getConsumerListQueryOptions = genListQueryOptions( + 'consumers', + getConsumerListReq +); +export const useConsumerList = genUseList( + '/consumers/', + getConsumerListQueryOptions +); + +export const getCredentialQueryOptions = genDetailQueryOptions( + 'credential', + getCredentialReq +); +export const getCredentialListQueryOptions = (username: string) => { return queryOptions({ - queryKey: ['routes', props.page, props.page_size], - queryFn: () => getRouteListReq(req, props), + queryKey: ['credentials', username], + queryFn: () => getCredentialListReq(req, { username }), }); }; - -export const useRouteList = () => { - const { params, setParams } = useSearchParams('/routes/'); - const routeQuery = useSuspenseQuery(getRouteListQueryOptions(params)); - const { data, isLoading, refetch } = routeQuery; - const pagination = useTablePagination({ data, setParams, params }); - return { data, isLoading, refetch, pagination }; +export const useCredentialsList = (username: string) => { + const credentialQuery = useSuspenseQuery( + getCredentialListQueryOptions(username) + ); + const { data, isLoading, refetch } = credentialQuery; + return { data, isLoading, refetch }; }; -export const getRouteQueryOptions = (id: string) => - queryOptions({ - queryKey: ['route', id], - queryFn: () => getRouteReq(req, id), - }); +export const getProtoQueryOptions = genDetailQueryOptions('proto', getProtoReq); +export const getProtoListQueryOptions = genListQueryOptions('protos', getProtoListReq); +export const useProtoList = genUseList('/protos/', getProtoListQueryOptions); + +export const getSecretQueryOptions = genDetailQueryOptions( + 'secret', + getSecretReq +); +export const getSecretListQueryOptions = genListQueryOptions( + 'secrets', + getSecretListReq +); +export const useSecretList = genUseList('/secrets/', getSecretListQueryOptions); diff --git a/src/apis/plugin_configs.ts b/src/apis/plugin_configs.ts index b873bc285..41d3d6a1f 100644 --- a/src/apis/plugin_configs.ts +++ b/src/apis/plugin_configs.ts @@ -14,38 +14,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { queryOptions } from '@tanstack/react-query'; +import type { AxiosInstance } from 'axios'; import { API_PLUGIN_CONFIGS } from '@/config/constant'; -import { req } from '@/config/req'; import type { APISIXType } from '@/types/schema/apisix'; import type { PageSearchType } from '@/types/schema/pageSearch'; -export const getPluginConfigListQueryOptions = (props: PageSearchType) => { - const { page, pageSize } = props; - return queryOptions({ - queryKey: ['plugin_configs', page, pageSize], - queryFn: () => - req - .get<unknown, APISIXType['RespPluginConfigList']>(API_PLUGIN_CONFIGS, { - params: { page, page_size: pageSize }, - }) - .then((v) => v.data), - }); -}; +export const getPluginConfigListReq = (req: AxiosInstance, params: PageSearchType) => + req + .get<unknown, APISIXType['RespPluginConfigList']>(API_PLUGIN_CONFIGS, { + params, + }) + .then((v) => v.data); -export const getPluginConfigQueryOptions = (id: string) => - queryOptions({ - queryKey: ['plugin_config', id], - queryFn: () => - req - .get<unknown, APISIXType['RespPluginConfigDetail']>( - `${API_PLUGIN_CONFIGS}/${id}` - ) - .then((v) => v.data), - }); +export const getPluginConfigReq = (req: AxiosInstance, id: string) => + req + .get<unknown, APISIXType['RespPluginConfigDetail']>( + `${API_PLUGIN_CONFIGS}/${id}` + ) + .then((v) => v.data); -export const putPluginConfigReq = (data: APISIXType['PluginConfigPut']) => { +export const putPluginConfigReq = ( + req: AxiosInstance, + data: APISIXType['PluginConfigPut'] +) => { const { id, ...rest } = data; return req.put< APISIXType['PluginConfigPut'], diff --git a/src/apis/plugins.ts b/src/apis/plugins.ts index 7fcb9cc2c..8e14b343c 100644 --- a/src/apis/plugins.ts +++ b/src/apis/plugins.ts @@ -19,7 +19,6 @@ import type { AxiosRequestConfig } from 'axios'; import type { PluginConfig } from '@/components/form-slice/FormItemPlugins/PluginEditorDrawer'; import { - API_GLOBAL_RULES, API_PLUGIN_METADATA, API_PLUGINS, API_PLUGINS_LIST, @@ -27,24 +26,6 @@ import { import { req } from '@/config/req'; import type { APISIXType } from '@/types/schema/apisix'; -export const putGlobalRuleReq = (data: APISIXType['GlobalRulePut']) => { - const { id, ...rest } = data; - return req.put< - APISIXType['GlobalRulePut'], - APISIXType['RespGlobalRuleDetail'] - >(`${API_GLOBAL_RULES}/${id}`, rest); -}; - -export const getGlobalRuleQueryOptions = (id: string) => - queryOptions({ - queryKey: ['global_rule', id], - queryFn: () => - req - .get<unknown, APISIXType['RespGlobalRuleDetail']>( - `${API_GLOBAL_RULES}/${id}` - ) - .then((v) => v.data), - }); export type NeedPluginSchema = { schema: APISIXType['PluginSchemaKeys']; diff --git a/src/apis/protos.ts b/src/apis/protos.ts index 352e80209..fe0e93d46 100644 --- a/src/apis/protos.ts +++ b/src/apis/protos.ts @@ -14,39 +14,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { queryOptions } from '@tanstack/react-query'; +import type { AxiosInstance } from 'axios'; import { API_PROTOS } from '@/config/constant'; -import { req } from '@/config/req'; import type { APISIXType } from '@/types/schema/apisix'; import type { PageSearchType } from '@/types/schema/pageSearch'; -export const getProtoListQueryOptions = (props: PageSearchType) => { - const { page, pageSize } = props; - return queryOptions({ - queryKey: ['protos', page, pageSize], - queryFn: () => - req - .get<unknown, APISIXType['RespProtoList']>(API_PROTOS, { - params: { - page, - page_size: pageSize, - }, - }) - .then((v) => v.data), - }); -}; +export const getProtoListReq = (req: AxiosInstance, params: PageSearchType) => + req + .get<unknown, APISIXType['RespProtoList']>(API_PROTOS, { + params, + }) + .then((v) => v.data); -export const getProtoQueryOptions = (id: string) => - queryOptions({ - queryKey: ['proto', id], - queryFn: () => - req - .get<unknown, APISIXType['RespProtoDetail']>(`${API_PROTOS}/${id}`) - .then((v) => v.data), - }); +export const getProtoReq = (req: AxiosInstance, id: string) => + req + .get<unknown, APISIXType['RespProtoDetail']>(`${API_PROTOS}/${id}`) + .then((v) => v.data); -export const putProtoReq = (data: APISIXType['Proto']) => { +export const putProtoReq = (req: AxiosInstance, data: APISIXType['Proto']) => { const { id, ...rest } = data; return req.put<APISIXType['Proto'], APISIXType['RespProtoDetail']>( `${API_PROTOS}/${id}`, @@ -54,7 +40,10 @@ export const putProtoReq = (data: APISIXType['Proto']) => { ); }; -export const postProtoReq = (data: APISIXType['ProtoPost']) => { +export const postProtoReq = ( + req: AxiosInstance, + data: APISIXType['ProtoPost'] +) => { return req.post<APISIXType['ProtoPost'], APISIXType['RespProtoList']>( API_PROTOS, data diff --git a/src/apis/routes.ts b/src/apis/routes.ts index c541bf70b..2eeadacc7 100644 --- a/src/apis/routes.ts +++ b/src/apis/routes.ts @@ -46,7 +46,6 @@ export const deleteAllRoutes = async (req: AxiosInstance) => { const res = await getRouteListReq(req, { page: 1, page_size: 1000, - pageSize: 1000, }); if (res.total === 0) return; return await Promise.all( diff --git a/src/apis/secrets.ts b/src/apis/secrets.ts index d3f5e4070..46ec64349 100644 --- a/src/apis/secrets.ts +++ b/src/apis/secrets.ts @@ -14,10 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { queryOptions } from '@tanstack/react-query'; +import type { AxiosInstance } from 'axios'; import { API_SECRETS } from '@/config/constant'; -import { req } from '@/config/req'; import type { APISIXType } from '@/types/schema/apisix'; import type { PageSearchType } from '@/types/schema/pageSearch'; @@ -37,41 +36,35 @@ export const preParseSecretItem = <T extends APISIXType['RespSecretItem']>( return { ...data, value: { ...data.value, manager, id: realId } }; }; -export const getSecretListQueryOptions = (props: PageSearchType) => { - const { page, pageSize } = props; - return queryOptions({ - queryKey: ['secrets', page, pageSize], - queryFn: () => - req - .get<unknown, APISIXType['RespSecretList']>(API_SECRETS, { - params: { page, page_size: pageSize }, - }) - .then((v) => { - const { list, ...rest } = v.data; - return { - ...rest, - list: list.map(preParseSecretItem), - }; - }), - }); -}; +export const getSecretListReq = (req: AxiosInstance, params: PageSearchType) => + req + .get<unknown, APISIXType['RespSecretList']>(API_SECRETS, { + params, + }) + .then((v) => { + const { list, ...rest } = v.data; + return { + ...rest, + list: list.map(preParseSecretItem), + }; + }); -export const getSecretQueryOptions = ( +export const getSecretReq = ( + req: AxiosInstance, props: Pick<APISIXType['Secret'], 'id' | 'manager'> ) => { const { id, manager } = props; - return queryOptions({ - queryKey: ['secret', manager, id], - queryFn: () => - req - .get<unknown, APISIXType['RespSecretDetail']>( - `${API_SECRETS}/${manager}/${id}` - ) - .then((v) => preParseSecretItem(v.data)), - }); + return req + .get<unknown, APISIXType['RespSecretDetail']>( + `${API_SECRETS}/${manager}/${id}` + ) + .then((v) => preParseSecretItem(v.data)); }; -export const putSecretReq = (data: APISIXType['Secret']) => { +export const putSecretReq = ( + req: AxiosInstance, + data: APISIXType['Secret'] +) => { const { manager, id, ...rest } = data; return req.put<APISIXType['Secret'], APISIXType['RespSecretDetail']>( `${API_SECRETS}/${manager}/${id}`, diff --git a/src/apis/services.ts b/src/apis/services.ts index 5918879db..dd7eb9aa6 100644 --- a/src/apis/services.ts +++ b/src/apis/services.ts @@ -14,38 +14,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { queryOptions } from '@tanstack/react-query'; +import type { AxiosInstance } from 'axios'; import { API_SERVICES } from '@/config/constant'; -import { req } from '@/config/req'; import type { APISIXType } from '@/types/schema/apisix'; import type { PageSearchType } from '@/types/schema/pageSearch'; export type ServicePostType = APISIXType['ServicePost']; -export const getServiceListQueryOptions = (props: PageSearchType) => { - const { page, pageSize } = props; - return queryOptions({ - queryKey: ['services', page, pageSize], - queryFn: () => - req - .get<unknown, APISIXType['RespServiceList']>(API_SERVICES, { - params: { page, page_size: pageSize }, - }) - .then((v) => v.data), - }); -}; +export const getServiceListReq = (req: AxiosInstance, params: PageSearchType) => + req + .get<unknown, APISIXType['RespServiceList']>(API_SERVICES, { + params, + }) + .then((v) => v.data); -export const getServiceQueryOptions = (id: string) => - queryOptions({ - queryKey: ['service', id], - queryFn: () => - req - .get<unknown, APISIXType['RespServiceDetail']>(`${API_SERVICES}/${id}`) - .then((v) => v.data), - }); +export const getServiceReq = (req: AxiosInstance, id: string) => + req + .get<unknown, APISIXType['RespServiceDetail']>(`${API_SERVICES}/${id}`) + .then((v) => v.data); -export const putServiceReq = (data: APISIXType['Service']) => { +export const putServiceReq = ( + req: AxiosInstance, + data: APISIXType['Service'] +) => { const { id, ...rest } = data; return req.put<APISIXType['Service'], APISIXType['RespServiceDetail']>( `${API_SERVICES}/${id}`, @@ -53,7 +45,7 @@ export const putServiceReq = (data: APISIXType['Service']) => { ); }; -export const postServiceReq = (data: ServicePostType) => +export const postServiceReq = (req: AxiosInstance, data: ServicePostType) => req.post<ServicePostType, APISIXType['RespServiceDetail']>( API_SERVICES, data diff --git a/src/apis/ssls.ts b/src/apis/ssls.ts index 89e3cafff..4499fd8ea 100644 --- a/src/apis/ssls.ts +++ b/src/apis/ssls.ts @@ -14,42 +14,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { queryOptions } from '@tanstack/react-query'; +import type { AxiosInstance } from 'axios'; +import type { SSLPostType } from '@/components/form-slice/FormPartSSL/schema'; import { API_SSLS } from '@/config/constant'; -import { req } from '@/config/req'; import type { APISIXType } from '@/types/schema/apisix'; import type { PageSearchType } from '@/types/schema/pageSearch'; -export const getSSLListQueryOptions = (props: PageSearchType) => { - const { page, pageSize } = props; - return queryOptions({ - queryKey: ['ssls', page, pageSize], - queryFn: () => - req - .get<unknown, APISIXType['RespSSLList']>(API_SSLS, { - params: { - page, - page_size: pageSize, - }, - }) - .then((v) => v.data), - }); -}; +export const getSSLListReq = (req: AxiosInstance, params: PageSearchType) => + req + .get<unknown, APISIXType['RespSSLList']>(API_SSLS, { + params, + }) + .then((v) => v.data); -export const getSSLDetailQueryOptions = (id: string) => - queryOptions({ - queryKey: ['ssl', id], - queryFn: () => - req - .get<unknown, APISIXType['RespSSLDetail']>(`${API_SSLS}/${id}`) - .then((v) => v.data), - }); +export const getSSLReq = (req: AxiosInstance, id: string) => + req + .get<unknown, APISIXType['RespSSLDetail']>(`${API_SSLS}/${id}`) + .then((v) => v.data); -export const putSSLReq = (data: APISIXType['SSL']) => { +export const putSSLReq = (req: AxiosInstance, data: APISIXType['SSL']) => { const { id, ...rest } = data; return req.put<APISIXType['SSL'], APISIXType['RespSSLDetail']>( `${API_SSLS}/${id}`, rest ); }; + +export const postSSLReq = (req: AxiosInstance, data: SSLPostType) => + req.post<APISIXType['SSL'], APISIXType['RespSSLDetail']>(API_SSLS, data); diff --git a/src/apis/stream_routes.ts b/src/apis/stream_routes.ts index 2f57af4e2..0e26ae225 100644 --- a/src/apis/stream_routes.ts +++ b/src/apis/stream_routes.ts @@ -14,39 +14,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { queryOptions } from '@tanstack/react-query'; + +import type { AxiosInstance } from 'axios'; import type { StreamRoutePostType } from '@/components/form-slice/FormPartStreamRoute/schema'; import { API_STREAM_ROUTES } from '@/config/constant'; -import { req } from '@/config/req'; import type { APISIXType } from '@/types/schema/apisix'; import type { PageSearchType } from '@/types/schema/pageSearch'; -export const getStreamRouteListQueryOptions = (props: PageSearchType) => { - const { page, pageSize } = props; - return queryOptions({ - queryKey: ['stream_routes', page, pageSize], - queryFn: () => - req - .get<unknown, APISIXType['RespStreamRouteList']>(API_STREAM_ROUTES, { - params: { page, page_size: pageSize }, - }) - .then((v) => v.data), - }); -}; +export const getStreamRouteListReq = (req: AxiosInstance, params: PageSearchType) => + req + .get<unknown, APISIXType['RespStreamRouteList']>(API_STREAM_ROUTES, { + params, + }) + .then((v) => v.data); -export const getStreamRouteQueryOptions = (id: string) => - queryOptions({ - queryKey: ['stream_route', id], - queryFn: () => - req - .get<unknown, APISIXType['RespStreamRouteDetail']>( - `${API_STREAM_ROUTES}/${id}` - ) - .then((v) => v.data), - }); +export const getStreamRouteReq = (req: AxiosInstance, id: string) => + req + .get<unknown, APISIXType['RespStreamRouteDetail']>( + `${API_STREAM_ROUTES}/${id}` + ) + .then((v) => v.data); -export const putStreamRouteReq = (data: APISIXType['StreamRoute']) => { +export const putStreamRouteReq = ( + req: AxiosInstance, + data: APISIXType['StreamRoute'] +) => { const { id, ...rest } = data; return req.put< APISIXType['StreamRoute'], @@ -54,7 +47,10 @@ export const putStreamRouteReq = (data: APISIXType['StreamRoute']) => { >(`${API_STREAM_ROUTES}/${id}`, rest); }; -export const postStreamRouteReq = (data: StreamRoutePostType) => +export const postStreamRouteReq = ( + req: AxiosInstance, + data: StreamRoutePostType +) => req.post<unknown, APISIXType['RespStreamRouteDetail']>( API_STREAM_ROUTES, data diff --git a/src/apis/upstreams.ts b/src/apis/upstreams.ts index 1938b3828..a7f484834 100644 --- a/src/apis/upstreams.ts +++ b/src/apis/upstreams.ts @@ -55,7 +55,6 @@ export const deleteAllUpstreams = async (req: AxiosInstance) => { const res = await getUpstreamListReq(req, { page: 1, page_size: 1000, - pageSize: 1000, }); if (res.total === 0) return; return await Promise.all( diff --git a/src/routes/consumer_groups/add.tsx b/src/routes/consumer_groups/add.tsx index da57d00b1..1b09c9a44 100644 --- a/src/routes/consumer_groups/add.tsx +++ b/src/routes/consumer_groups/add.tsx @@ -27,7 +27,8 @@ import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartPluginConfig } from '@/components/form-slice/FormPartPluginConfig'; import { FormTOCBox } from '@/components/form-slice/FormSection'; import PageHeader from '@/components/page/PageHeader'; -import { APISIX } from '@/types/schema/apisix'; +import { req } from '@/config/req'; +import { APISIX, type APISIXType } from '@/types/schema/apisix'; import { pipeProduce } from '@/utils/producer'; const ConsumerGroupAddForm = () => { @@ -35,7 +36,8 @@ const ConsumerGroupAddForm = () => { const router = useRouter(); const putConsumerGroup = useMutation({ - mutationFn: putConsumerGroupReq, + mutationFn: (d: APISIXType['ConsumerGroupPut']) => + putConsumerGroupReq(req, d), async onSuccess(response) { notifications.show({ message: t('info.add.success', { name: t('consumerGroups.singular') }), diff --git a/src/routes/consumer_groups/detail.$id.tsx b/src/routes/consumer_groups/detail.$id.tsx index 497c1008e..c306a226b 100644 --- a/src/routes/consumer_groups/detail.$id.tsx +++ b/src/routes/consumer_groups/detail.$id.tsx @@ -28,17 +28,16 @@ import { FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { useBoolean } from 'react-use'; -import { - getConsumerGroupQueryOptions, - putConsumerGroupReq, -} from '@/apis/consumer_groups'; +import { putConsumerGroupReq } from '@/apis/consumer_groups'; +import { getConsumerGroupQueryOptions } from '@/apis/hooks'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartPluginConfig } from '@/components/form-slice/FormPartPluginConfig'; import { FormTOCBox } from '@/components/form-slice/FormSection'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { API_CONSUMER_GROUPS } from '@/config/constant'; -import { APISIX } from '@/types/schema/apisix'; +import { req } from '@/config/req'; +import { APISIX, type APISIXType } from '@/types/schema/apisix'; import { pipeProduce } from '@/utils/producer'; type Props = { @@ -55,7 +54,8 @@ const ConsumerGroupDetailForm = (props: Props) => { const { data } = consumerGroupQuery; const putConsumerGroup = useMutation({ - mutationFn: putConsumerGroupReq, + mutationFn: (d: APISIXType['ConsumerGroupPut']) => + putConsumerGroupReq(req, d), async onSuccess() { notifications.show({ message: t('info.edit.success', { name: t('consumerGroups.singular') }), diff --git a/src/routes/consumer_groups/index.tsx b/src/routes/consumer_groups/index.tsx index 747df0be2..108ce06b6 100644 --- a/src/routes/consumer_groups/index.tsx +++ b/src/routes/consumer_groups/index.tsx @@ -16,12 +16,11 @@ */ import type { ProColumns } from '@ant-design/pro-components'; import { ProTable } from '@ant-design/pro-components'; -import { useSuspenseQuery } from '@tanstack/react-query'; import { createFileRoute } from '@tanstack/react-router'; -import { useEffect, useMemo } from 'react'; +import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { getConsumerGroupListQueryOptions } from '@/apis/consumer_groups'; +import { getConsumerGroupListQueryOptions, useConsumerGroupList } from '@/apis/hooks'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { ToAddPageBtn, ToDetailPageBtn } from '@/components/page/ToAddPageBtn'; @@ -30,25 +29,10 @@ import { API_CONSUMER_GROUPS } from '@/config/constant'; import { queryClient } from '@/config/global'; import type { APISIXType } from '@/types/schema/apisix'; import { pageSearchSchema } from '@/types/schema/pageSearch'; -import { usePagination } from '@/utils/usePagination'; function ConsumerGroupsList() { const { t } = useTranslation(); - - const { pagination, handlePageChange, updateTotal } = usePagination({ - queryKey: 'consumer_groups', - }); - - const consumerGroupsQuery = useSuspenseQuery( - getConsumerGroupListQueryOptions(pagination) - ); - const { data, isLoading, refetch } = consumerGroupsQuery; - - useEffect(() => { - if (data?.total) { - updateTotal(data.total); - } - }, [data?.total, updateTotal]); + const { data, isLoading, refetch, pagination } = useConsumerGroupList(); const columns = useMemo< ProColumns<APISIXType['RespConsumerGroupItem']>[] @@ -115,13 +99,7 @@ function ConsumerGroupsList() { loading={isLoading} search={false} options={false} - pagination={{ - current: pagination.page, - pageSize: pagination.pageSize, - total: pagination.total, - showSizeChanger: true, - onChange: handlePageChange, - }} + pagination={pagination} cardProps={{ bodyStyle: { padding: 0 } }} toolbar={{ menu: { diff --git a/src/routes/consumers/add.tsx b/src/routes/consumers/add.tsx index c7e8adb72..137cf6936 100644 --- a/src/routes/consumers/add.tsx +++ b/src/routes/consumers/add.tsx @@ -26,7 +26,8 @@ import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartConsumer } from '@/components/form-slice/FormPartConsumer'; import { FormTOCBox } from '@/components/form-slice/FormSection'; import PageHeader from '@/components/page/PageHeader'; -import { APISIX } from '@/types/schema/apisix'; +import { req } from '@/config/req'; +import { APISIX, type APISIXType } from '@/types/schema/apisix'; import { pipeProduce } from '@/utils/producer'; const ConsumerAddForm = () => { @@ -34,7 +35,7 @@ const ConsumerAddForm = () => { const router = useRouter(); const putConsumer = useMutation({ - mutationFn: putConsumerReq, + mutationFn: (d: APISIXType['ConsumerPut']) => putConsumerReq(req, d), async onSuccess(_, res) { notifications.show({ message: t('info.add.success', { name: t('consumers.singular') }), diff --git a/src/routes/consumers/detail.$username/credentials/add.tsx b/src/routes/consumers/detail.$username/credentials/add.tsx index f157bd89b..d5f3dd844 100644 --- a/src/routes/consumers/detail.$username/credentials/add.tsx +++ b/src/routes/consumers/detail.$username/credentials/add.tsx @@ -28,7 +28,8 @@ import { FormPartCredential } from '@/components/form-slice/FormPartCredential'; import { FormTOCBox } from '@/components/form-slice/FormSection'; import PageHeader from '@/components/page/PageHeader'; import { DetailCredentialsTabs } from '@/components/page-slice/consumers/DetailCredentialsTabs'; -import { APISIX } from '@/types/schema/apisix'; +import { req } from '@/config/req'; +import { APISIX, type APISIXType } from '@/types/schema/apisix'; import { pipeProduce } from '@/utils/producer'; const CredentialAddForm = () => { @@ -39,7 +40,8 @@ const CredentialAddForm = () => { }); const putCredential = useMutation({ - mutationFn: putCredentialReq, + mutationFn: (d: APISIXType['CredentialPut']) => + putCredentialReq(req, pipeProduce()({ ...d, username })), async onSuccess(_, res) { notifications.show({ message: t('info.add.success', { @@ -66,11 +68,7 @@ const CredentialAddForm = () => { return ( <FormProvider {...form}> - <form - onSubmit={form.handleSubmit((d) => - putCredential.mutateAsync({ username, ...pipeProduce()(d) }) - )} - > + <form onSubmit={form.handleSubmit((d) => putCredential.mutateAsync(d))}> <FormPartCredential /> <FormSubmitBtn>{t('form.btn.add')}</FormSubmitBtn> </form> diff --git a/src/routes/consumers/detail.$username/credentials/detail.$id.tsx b/src/routes/consumers/detail.$username/credentials/detail.$id.tsx index f13235aa0..d848bcea0 100644 --- a/src/routes/consumers/detail.$username/credentials/detail.$id.tsx +++ b/src/routes/consumers/detail.$username/credentials/detail.$id.tsx @@ -28,10 +28,8 @@ import { FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { useBoolean } from 'react-use'; -import { - getCredentialQueryOptions, - putCredentialReq, -} from '@/apis/credentials'; +import { putCredentialReq } from '@/apis/credentials'; +import { getCredentialQueryOptions } from '@/apis/hooks'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartCredential } from '@/components/form-slice/FormPartCredential'; import { FormTOCBox } from '@/components/form-slice/FormSection'; @@ -39,7 +37,8 @@ import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { DetailCredentialsTabs } from '@/components/page-slice/consumers/DetailCredentialsTabs'; import { API_CREDENTIALS } from '@/config/constant'; -import { APISIX } from '@/types/schema/apisix'; +import { req } from '@/config/req'; +import { APISIX, type APISIXType } from '@/types/schema/apisix'; import { pipeProduce } from '@/utils/producer'; type CredentialFormProps = { @@ -75,7 +74,8 @@ const CredentialDetailForm = (props: CredentialFormProps) => { }, [credentialData, form, isLoading]); const putCredential = useMutation({ - mutationFn: putCredentialReq, + mutationFn: (d: APISIXType['CredentialPut']) => + putCredentialReq(req, pipeProduce()({ ...d, username })), async onSuccess() { notifications.show({ message: t('info.edit.success', { name: t('credentials.singular') }), @@ -92,14 +92,7 @@ const CredentialDetailForm = (props: CredentialFormProps) => { return ( <FormProvider {...form}> - <form - onSubmit={form.handleSubmit((d) => { - putCredential.mutateAsync({ - username, - ...pipeProduce()(d), - }); - })} - > + <form onSubmit={form.handleSubmit((d) => putCredential.mutateAsync(d))}> <FormPartCredential showDate /> {!readOnly && ( <Group> diff --git a/src/routes/consumers/detail.$username/credentials/index.tsx b/src/routes/consumers/detail.$username/credentials/index.tsx index ff0291967..d331ec245 100644 --- a/src/routes/consumers/detail.$username/credentials/index.tsx +++ b/src/routes/consumers/detail.$username/credentials/index.tsx @@ -16,12 +16,14 @@ */ import type { ProColumns } from '@ant-design/pro-components'; import { ProTable } from '@ant-design/pro-components'; -import { useSuspenseQuery } from '@tanstack/react-query'; import { createFileRoute, useParams } from '@tanstack/react-router'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { getCredentialListQueryOptions } from '@/apis/credentials'; +import { + getCredentialListQueryOptions, + useCredentialsList, +} from '@/apis/hooks'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { ToAddPageBtn, ToDetailPageBtn } from '@/components/page/ToAddPageBtn'; @@ -36,11 +38,7 @@ function CredentialsList() { const { username } = useParams({ from: '/consumers/detail/$username/credentials/', }); - - const credentialsQuery = useSuspenseQuery( - getCredentialListQueryOptions({ username }) - ); - const { data, isLoading, refetch } = credentialsQuery; + const { data, isLoading, refetch } = useCredentialsList(username); const columns = useMemo< ProColumns<APISIXType['RespCredentialItem']>[] @@ -142,10 +140,8 @@ function RouteComponent() { ); } -export const Route = createFileRoute( - '/consumers/detail/$username/credentials/' -)({ +export const Route = createFileRoute('/consumers/detail/$username/credentials/')({ component: RouteComponent, loader: ({ params }) => - queryClient.ensureQueryData(getCredentialListQueryOptions(params)), + queryClient.ensureQueryData(getCredentialListQueryOptions(params.username)), }); diff --git a/src/routes/consumers/detail.$username/index.tsx b/src/routes/consumers/detail.$username/index.tsx index b44ec4150..e7585dded 100644 --- a/src/routes/consumers/detail.$username/index.tsx +++ b/src/routes/consumers/detail.$username/index.tsx @@ -28,7 +28,8 @@ import { FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { useBoolean } from 'react-use'; -import { getConsumerQueryOptions, putConsumerReq } from '@/apis/consumers'; +import { putConsumerReq } from '@/apis/consumers'; +import { getConsumerQueryOptions } from '@/apis/hooks'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartConsumer } from '@/components/form-slice/FormPartConsumer'; import { FormTOCBox } from '@/components/form-slice/FormSection'; @@ -37,7 +38,8 @@ import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { DetailCredentialsTabs } from '@/components/page-slice/consumers/DetailCredentialsTabs'; import { API_CONSUMERS } from '@/config/constant'; -import { APISIX } from '@/types/schema/apisix'; +import { req } from '@/config/req'; +import { APISIX, type APISIXType } from '@/types/schema/apisix'; import { pipeProduce } from '@/utils/producer'; type Props = { @@ -68,7 +70,7 @@ const ConsumerDetailForm = (props: Props) => { }, [consumerData, form, isLoading]); const putConsumer = useMutation({ - mutationFn: putConsumerReq, + mutationFn: (d: APISIXType['ConsumerPut']) => putConsumerReq(req, d), async onSuccess() { notifications.show({ message: t('info.edit.success', { name: t('consumers.singular') }), diff --git a/src/routes/consumers/index.tsx b/src/routes/consumers/index.tsx index 2663e2496..b431ed3b4 100644 --- a/src/routes/consumers/index.tsx +++ b/src/routes/consumers/index.tsx @@ -16,12 +16,11 @@ */ import type { ProColumns } from '@ant-design/pro-components'; import { ProTable } from '@ant-design/pro-components'; -import { useSuspenseQuery } from '@tanstack/react-query'; import { createFileRoute } from '@tanstack/react-router'; -import { useEffect, useMemo } from 'react'; +import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { getConsumerListQueryOptions } from '@/apis/consumers'; +import { getConsumerListQueryOptions, useConsumerList } from '@/apis/hooks'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { ToAddPageBtn, ToDetailPageBtn } from '@/components/page/ToAddPageBtn'; @@ -29,28 +28,11 @@ import { AntdConfigProvider } from '@/config/antdConfigProvider'; import { API_CONSUMERS } from '@/config/constant'; import { queryClient } from '@/config/global'; import type { APISIXType } from '@/types/schema/apisix'; -import { - pageSearchSchema, -} from '@/types/schema/pageSearch'; -import { usePagination } from '@/utils/usePagination'; +import { pageSearchSchema } from '@/types/schema/pageSearch'; function ConsumersList() { const { t } = useTranslation(); - - const { pagination, handlePageChange, updateTotal } = usePagination({ - queryKey: 'consumers', - }); - - const consumersQuery = useSuspenseQuery( - getConsumerListQueryOptions(pagination) - ); - const { data, isLoading, refetch } = consumersQuery; - - useEffect(() => { - if (data?.total) { - updateTotal(data.total); - } - }, [data?.total, updateTotal]); + const { data, isLoading, refetch, pagination } = useConsumerList(); const columns = useMemo<ProColumns<APISIXType['RespConsumerItem']>[]>(() => { return [ @@ -109,13 +91,7 @@ function ConsumersList() { loading={isLoading} search={false} options={false} - pagination={{ - current: pagination.page, - pageSize: pagination.pageSize, - total: pagination.total, - showSizeChanger: true, - onChange: handlePageChange, - }} + pagination={pagination} cardProps={{ bodyStyle: { padding: 0 } }} toolbar={{ menu: { diff --git a/src/routes/global_rules/add.tsx b/src/routes/global_rules/add.tsx index ff59f4abb..3f0641f6f 100644 --- a/src/routes/global_rules/add.tsx +++ b/src/routes/global_rules/add.tsx @@ -25,11 +25,12 @@ import { nanoid } from 'nanoid'; import { FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import { putGlobalRuleReq } from '@/apis/plugins'; +import { putGlobalRuleReq } from '@/apis/global_rules'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartGlobalRules } from '@/components/form-slice/FormPartGlobalRules'; import { FormTOCBox } from '@/components/form-slice/FormSection'; import PageHeader from '@/components/page/PageHeader'; +import { req } from '@/config/req'; import type { APISIXType } from '@/types/schema/apisix'; import { APISIX } from '@/types/schema/apisix'; @@ -38,7 +39,18 @@ const GlobalRuleAddForm = () => { const router = useReactRouter(); const putGlobalRule = useMutation({ - mutationFn: putGlobalRuleReq, + mutationFn: (d: APISIXType['GlobalRulePut']) => putGlobalRuleReq(req, d), + async onSuccess(res) { + notifications.show({ + id: 'add-global_rule', + message: t('info.add.success', { name: t('globalRules.singular') }), + color: 'green', + }); + await router.navigate({ + to: '/global_rules/detail/$id', + params: { id: res.data.value.id }, + }); + }, }); const form = useForm({ @@ -52,22 +64,9 @@ const GlobalRuleAddForm = () => { mode: 'onChange', }); - const submit = async (data: APISIXType['GlobalRulePut']) => { - const res = await putGlobalRule.mutateAsync(data); - notifications.show({ - id: 'add-global_rule', - message: t('info.add.success', { name: t('globalRules.singular') }), - color: 'green', - }); - await router.navigate({ - to: '/global_rules/detail/$id', - params: { id: res.data.value.id }, - }); - }; - return ( <FormProvider {...form}> - <form onSubmit={form.handleSubmit(submit)}> + <form onSubmit={form.handleSubmit((d) => putGlobalRule.mutateAsync(d))}> <FormPartGlobalRules /> <FormSubmitBtn>{t('form.btn.add')}</FormSubmitBtn> </form> diff --git a/src/routes/global_rules/detail.$id.tsx b/src/routes/global_rules/detail.$id.tsx index edc5bc0b5..8ea27f920 100644 --- a/src/routes/global_rules/detail.$id.tsx +++ b/src/routes/global_rules/detail.$id.tsx @@ -17,7 +17,7 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { Button, Group } from '@mantine/core'; import { notifications } from '@mantine/notifications'; -import { useMutation, useQuery } from '@tanstack/react-query'; +import { useMutation, useSuspenseQuery } from '@tanstack/react-query'; import { createFileRoute, useNavigate, @@ -28,15 +28,16 @@ import { FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { useBoolean } from 'react-use'; -import { getGlobalRuleQueryOptions, putGlobalRuleReq } from '@/apis/plugins'; +import { putGlobalRuleReq } from '@/apis/global_rules'; +import { getGlobalRuleQueryOptions } from '@/apis/hooks'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartGlobalRules } from '@/components/form-slice/FormPartGlobalRules'; import { FormTOCBox } from '@/components/form-slice/FormSection'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { API_GLOBAL_RULES } from '@/config/constant'; -import type { APISIXType } from '@/types/schema/apisix'; -import { APISIX } from '@/types/schema/apisix'; +import { req } from '@/config/req'; +import { APISIX, type APISIXType } from '@/types/schema/apisix'; type Props = { readOnly: boolean; @@ -46,7 +47,7 @@ const GlobalRuleDetailForm = (props: Props) => { const { readOnly, setReadOnly } = props; const { t } = useTranslation(); const { id } = useParams({ from: '/global_rules/detail/$id' }); - const detailReq = useQuery(getGlobalRuleQueryOptions(id)); + const detailReq = useSuspenseQuery(getGlobalRuleQueryOptions(id)); const form = useForm({ resolver: zodResolver(APISIX.GlobalRulePut), @@ -63,22 +64,21 @@ const GlobalRuleDetailForm = (props: Props) => { } }, [detailReq.data, form]); - const putglobalRule = useMutation({ - mutationFn: putGlobalRuleReq, + const putGlobalRule = useMutation({ + mutationFn: (d: APISIXType['GlobalRulePut']) => putGlobalRuleReq(req, d), + async onSuccess() { + notifications.show({ + message: t('info.edit.success', { name: t('globalRules.singular') }), + color: 'green', + }); + await detailReq.refetch(); + setReadOnly(true); + }, }); - const submit = async (data: APISIXType['GlobalRulePut']) => { - await putglobalRule.mutateAsync(data); - notifications.show({ - message: t('info.edit.success', { name: t('globalRules.singular') }), - color: 'green', - }); - await detailReq.refetch(); - setReadOnly(true); - }; return ( <FormProvider {...form}> - <form onSubmit={form.handleSubmit(submit)}> + <form onSubmit={form.handleSubmit((d) => putGlobalRule.mutateAsync(d))}> <FormPartGlobalRules /> {!readOnly && ( <Group> diff --git a/src/routes/global_rules/index.tsx b/src/routes/global_rules/index.tsx index ec5a9c647..248455efa 100644 --- a/src/routes/global_rules/index.tsx +++ b/src/routes/global_rules/index.tsx @@ -16,59 +16,36 @@ */ import type { ProColumns } from '@ant-design/pro-components'; import { ProTable } from '@ant-design/pro-components'; -import { queryOptions, useSuspenseQuery } from '@tanstack/react-query'; import { createFileRoute } from '@tanstack/react-router'; -import { useEffect, useMemo } from 'react'; +import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; +import { getGlobalRuleListQueryOptions, useGlobalRuleList } from '@/apis/hooks'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { ToAddPageBtn, ToDetailPageBtn } from '@/components/page/ToAddPageBtn'; import { AntdConfigProvider } from '@/config/antdConfigProvider'; import { API_GLOBAL_RULES } from '@/config/constant'; import { queryClient } from '@/config/global'; -import { req } from '@/config/req'; import type { APISIXType } from '@/types/schema/apisix'; -import { - pageSearchSchema, - type PageSearchType, -} from '@/types/schema/pageSearch'; -import { usePagination } from '@/utils/usePagination'; +import { pageSearchSchema } from '@/types/schema/pageSearch'; + -const genGlobalRulesQueryOptions = (props: PageSearchType) => { - const { page, pageSize } = props; - return queryOptions({ - queryKey: ['global_rules', page, pageSize], - queryFn: () => - req - .get<unknown, APISIXType['RespGlobalRuleList']>(API_GLOBAL_RULES, { - params: { - page, - page_size: pageSize, - }, - }) - .then((v) => v.data), - }); -}; function RouteComponent() { const { t } = useTranslation(); - // Use the pagination hook - const { pagination, handlePageChange, updateTotal } = usePagination({ - queryKey: 'global_rules', - }); - - const globalRulesQuery = useSuspenseQuery( - genGlobalRulesQueryOptions(pagination) + return ( + <> + <PageHeader title={t('sources.globalRules')} /> + <GlobalRulesList /> + </> ); - const { data, isLoading, refetch } = globalRulesQuery; +} - useEffect(() => { - if (data?.total) { - updateTotal(data.total); - } - }, [data?.total, updateTotal]); +function GlobalRulesList() { + const { t } = useTranslation(); + const { data, isLoading, refetch, pagination } = useGlobalRuleList(); const columns = useMemo< ProColumns<APISIXType['RespConsumerGroupItem']>[] @@ -104,46 +81,37 @@ function RouteComponent() { }, [t, refetch]); return ( - <> - <PageHeader title={t('sources.globalRules')} /> - <AntdConfigProvider> - <ProTable - columns={columns} - dataSource={data?.list || []} - rowKey="id" - loading={isLoading} - search={false} - options={false} - pagination={{ - current: pagination.page, - pageSize: pagination.pageSize, - total: pagination.total, - showSizeChanger: true, - onChange: handlePageChange, - }} - cardProps={{ bodyStyle: { padding: 0 } }} - toolbar={{ - menu: { - type: 'inline', - items: [ - { - key: 'add', - label: ( - <ToAddPageBtn - key="add" - to="/global_rules/add" - label={t('info.add.title', { - name: t('globalRules.singular'), - })} - /> - ), - }, - ], - }, - }} - /> - </AntdConfigProvider> - </> + <AntdConfigProvider> + <ProTable + columns={columns} + dataSource={data.list} + rowKey="id" + loading={isLoading} + search={false} + options={false} + pagination={pagination} + cardProps={{ bodyStyle: { padding: 0 } }} + toolbar={{ + menu: { + type: 'inline', + items: [ + { + key: 'add', + label: ( + <ToAddPageBtn + key="add" + to="/global_rules/add" + label={t('info.add.title', { + name: t('globalRules.singular'), + })} + /> + ), + }, + ], + }, + }} + /> + </AntdConfigProvider> ); } @@ -152,5 +120,5 @@ export const Route = createFileRoute('/global_rules/')({ validateSearch: pageSearchSchema, loaderDeps: ({ search }) => search, loader: ({ deps }) => - queryClient.ensureQueryData(genGlobalRulesQueryOptions(deps)), + queryClient.ensureQueryData(getGlobalRuleListQueryOptions(deps)), }); diff --git a/src/routes/plugin_configs/add.tsx b/src/routes/plugin_configs/add.tsx index dca90c2ea..4f4ea71aa 100644 --- a/src/routes/plugin_configs/add.tsx +++ b/src/routes/plugin_configs/add.tsx @@ -27,7 +27,8 @@ import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartPluginConfig } from '@/components/form-slice/FormPartPluginConfig'; import { FormTOCBox } from '@/components/form-slice/FormSection'; import PageHeader from '@/components/page/PageHeader'; -import { APISIX } from '@/types/schema/apisix'; +import { req } from '@/config/req'; +import { APISIX, type APISIXType } from '@/types/schema/apisix'; import { pipeProduce } from '@/utils/producer'; const PluginConfigAddForm = () => { @@ -35,7 +36,8 @@ const PluginConfigAddForm = () => { const router = useRouter(); const putPluginConfig = useMutation({ - mutationFn: putPluginConfigReq, + mutationFn: (d: APISIXType['PluginConfigPut']) => + putPluginConfigReq(req, d), async onSuccess(response) { notifications.show({ message: t('info.add.success', { name: t('pluginConfigs.singular') }), diff --git a/src/routes/plugin_configs/detail.$id.tsx b/src/routes/plugin_configs/detail.$id.tsx index d882b9f13..431dc2c90 100644 --- a/src/routes/plugin_configs/detail.$id.tsx +++ b/src/routes/plugin_configs/detail.$id.tsx @@ -28,17 +28,16 @@ import { FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { useBoolean } from 'react-use'; -import { - getPluginConfigQueryOptions, - putPluginConfigReq, -} from '@/apis/plugin_configs'; +import { getPluginConfigQueryOptions } from '@/apis/hooks'; +import { putPluginConfigReq } from '@/apis/plugin_configs'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartPluginConfig } from '@/components/form-slice/FormPartPluginConfig'; import { FormTOCBox } from '@/components/form-slice/FormSection'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { API_PLUGIN_CONFIGS } from '@/config/constant'; -import { APISIX } from '@/types/schema/apisix'; +import { req } from '@/config/req'; +import { APISIX, type APISIXType } from '@/types/schema/apisix'; import { pipeProduce } from '@/utils/producer'; type Props = { @@ -56,7 +55,8 @@ const PluginConfigDetailForm = (props: Props) => { const initialValue = data.value; const putPluginConfig = useMutation({ - mutationFn: putPluginConfigReq, + mutationFn: (d: APISIXType['PluginConfigPut']) => + putPluginConfigReq(req, pipeProduce()({ ...d, id })), async onSuccess() { notifications.show({ message: t('info.edit.success', { name: t('pluginConfigs.singular') }), @@ -84,11 +84,7 @@ const PluginConfigDetailForm = (props: Props) => { return ( <FormProvider {...form}> - <form - onSubmit={form.handleSubmit((d) => - putPluginConfig.mutateAsync(pipeProduce()({ ...d, id })) - )} - > + <form onSubmit={form.handleSubmit((d) => putPluginConfig.mutateAsync(d))}> <FormPartPluginConfig /> {!readOnly && ( <Group> diff --git a/src/routes/plugin_configs/index.tsx b/src/routes/plugin_configs/index.tsx index f646a1fdc..bccb89848 100644 --- a/src/routes/plugin_configs/index.tsx +++ b/src/routes/plugin_configs/index.tsx @@ -16,12 +16,11 @@ */ import type { ProColumns } from '@ant-design/pro-components'; import { ProTable } from '@ant-design/pro-components'; -import { useSuspenseQuery } from '@tanstack/react-query'; import { createFileRoute } from '@tanstack/react-router'; -import { useEffect, useMemo } from 'react'; +import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { getPluginConfigListQueryOptions } from '@/apis/plugin_configs'; +import { getPluginConfigListQueryOptions, usePluginConfigList } from '@/apis/hooks'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { ToAddPageBtn, ToDetailPageBtn } from '@/components/page/ToAddPageBtn'; @@ -30,25 +29,10 @@ import { API_PLUGIN_CONFIGS } from '@/config/constant'; import { queryClient } from '@/config/global'; import type { APISIXType } from '@/types/schema/apisix'; import { pageSearchSchema } from '@/types/schema/pageSearch'; -import { usePagination } from '@/utils/usePagination'; function PluginConfigsList() { const { t } = useTranslation(); - - const { pagination, handlePageChange, updateTotal } = usePagination({ - queryKey: 'plugin_configs', - }); - - const pluginConfigsQuery = useSuspenseQuery( - getPluginConfigListQueryOptions(pagination) - ); - const { data, isLoading, refetch } = pluginConfigsQuery; - - useEffect(() => { - if (data?.total) { - updateTotal(data.total); - } - }, [data?.total, updateTotal]); + const { data, isLoading, refetch, pagination } = usePluginConfigList(); const columns = useMemo< ProColumns<APISIXType['RespPluginConfigItem']>[] @@ -115,13 +99,7 @@ function PluginConfigsList() { loading={isLoading} search={false} options={false} - pagination={{ - current: pagination.page, - pageSize: pagination.pageSize, - total: pagination.total, - showSizeChanger: true, - onChange: handlePageChange, - }} + pagination={pagination} cardProps={{ bodyStyle: { padding: 0 } }} toolbar={{ menu: { diff --git a/src/routes/protos/add.tsx b/src/routes/protos/add.tsx index b8d981359..798dac75f 100644 --- a/src/routes/protos/add.tsx +++ b/src/routes/protos/add.tsx @@ -28,6 +28,7 @@ import { postProtoReq } from '@/apis/protos'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartProto } from '@/components/form-slice/FormPartProto'; import PageHeader from '@/components/page/PageHeader'; +import { req } from '@/config/req'; import type { APISIXType } from '@/types/schema/apisix'; import { APISIXProtos } from '@/types/schema/apisix/protos'; @@ -40,7 +41,14 @@ const ProtoAddForm = () => { const router = useReactRouter(); const postProto = useMutation({ - mutationFn: postProtoReq, + mutationFn: (d: APISIXType['ProtoPost']) => postProtoReq(req, d), + async onSuccess() { + notifications.show({ + message: t('info.add.success', { name: t('protos.singular') }), + color: 'green', + }); + await router.navigate({ to: '/protos' }); + }, }); const form = useForm({ @@ -51,19 +59,9 @@ const ProtoAddForm = () => { mode: 'onChange', }); - const submit = async (data: APISIXType['ProtoPost']) => { - await postProto.mutateAsync(data); - notifications.show({ - id: 'add-proto', - message: t('info.add.success', { name: t('protos.singular') }), - color: 'green', - }); - await router.navigate({ to: '/protos' }); - }; - return ( <FormProvider {...form}> - <form onSubmit={form.handleSubmit(submit)}> + <form onSubmit={form.handleSubmit((d) => postProto.mutateAsync(d))}> <FormPartProto /> <FormSubmitBtn>{t('form.btn.add')}</FormSubmitBtn> </form> diff --git a/src/routes/protos/detail.$id.tsx b/src/routes/protos/detail.$id.tsx index 883464026..7035a9384 100644 --- a/src/routes/protos/detail.$id.tsx +++ b/src/routes/protos/detail.$id.tsx @@ -28,7 +28,8 @@ import { FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { useBoolean } from 'react-use'; -import { getProtoQueryOptions, putProtoReq } from '@/apis/protos'; +import { getProtoQueryOptions } from '@/apis/hooks'; +import { putProtoReq } from '@/apis/protos'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartProto } from '@/components/form-slice/FormPartProto'; import { FormTOCBox } from '@/components/form-slice/FormSection'; @@ -36,6 +37,7 @@ import { FormSectionGeneral } from '@/components/form-slice/FormSectionGeneral'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { API_PROTOS } from '@/config/constant'; +import { req } from '@/config/req'; import { APISIX, type APISIXType } from '@/types/schema/apisix'; import { pipeProduce } from '@/utils/producer'; @@ -61,7 +63,7 @@ const ProtoDetailForm = ({ id, readOnly, setReadOnly }: ProtoFormProps) => { }); const putProto = useMutation({ - mutationFn: putProtoReq, + mutationFn: (d: APISIXType['Proto']) => putProtoReq(req, pipeProduce()(d)), async onSuccess() { notifications.show({ message: t('info.edit.success', { name: t('protos.singular') }), @@ -85,11 +87,7 @@ const ProtoDetailForm = ({ id, readOnly, setReadOnly }: ProtoFormProps) => { return ( <FormProvider {...form}> - <form - onSubmit={form.handleSubmit((d) => - putProto.mutateAsync(pipeProduce()(d)) - )} - > + <form onSubmit={form.handleSubmit((d) => putProto.mutateAsync(d))}> <FormSectionGeneral /> <FormPartProto allowUpload={!readOnly} /> {!readOnly && ( diff --git a/src/routes/protos/index.tsx b/src/routes/protos/index.tsx index af8436540..275495498 100644 --- a/src/routes/protos/index.tsx +++ b/src/routes/protos/index.tsx @@ -16,12 +16,11 @@ */ import type { ProColumns } from '@ant-design/pro-components'; import { ProTable } from '@ant-design/pro-components'; -import { useSuspenseQuery } from '@tanstack/react-query'; import { createFileRoute } from '@tanstack/react-router'; -import { useEffect, useMemo } from 'react'; +import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { getProtoListQueryOptions } from '@/apis/protos'; +import { getProtoListQueryOptions, useProtoList } from '@/apis/hooks'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { ToAddPageBtn, ToDetailPageBtn } from '@/components/page/ToAddPageBtn'; @@ -30,24 +29,11 @@ import { API_PROTOS } from '@/config/constant'; import { queryClient } from '@/config/global'; import type { APISIXType } from '@/types/schema/apisix'; import { pageSearchSchema } from '@/types/schema/pageSearch'; -import { usePagination } from '@/utils/usePagination'; function RouteComponent() { const { t } = useTranslation(); - // Use the pagination hook - const { pagination, handlePageChange, updateTotal } = usePagination({ - queryKey: 'protos', - }); - - const protosQuery = useSuspenseQuery(getProtoListQueryOptions(pagination)); - const { data, isLoading, refetch } = protosQuery; - - useEffect(() => { - if (data?.total) { - updateTotal(data.total); - } - }, [data?.total, updateTotal]); + const { data, isLoading, refetch, pagination } = useProtoList(); const columns = useMemo< ProColumns<APISIXType['RespProtoList']['data']['list'][number]>[] @@ -93,13 +79,7 @@ function RouteComponent() { loading={isLoading} search={false} options={false} - pagination={{ - current: pagination.page, - pageSize: pagination.pageSize, - total: pagination.total, - showSizeChanger: true, - onChange: handlePageChange, - }} + pagination={pagination} cardProps={{ bodyStyle: { padding: 0 } }} toolbar={{ menu: { diff --git a/src/routes/secrets/add.tsx b/src/routes/secrets/add.tsx index 83295d917..752b42e9a 100644 --- a/src/routes/secrets/add.tsx +++ b/src/routes/secrets/add.tsx @@ -28,7 +28,8 @@ import { FormPartSecret } from '@/components/form-slice/FormPartSecret'; import { FormTOCBox } from '@/components/form-slice/FormSection'; import { FormSectionGeneral } from '@/components/form-slice/FormSectionGeneral'; import PageHeader from '@/components/page/PageHeader'; -import { APISIX } from '@/types/schema/apisix'; +import { req } from '@/config/req'; +import { APISIX, type APISIXType } from '@/types/schema/apisix'; import { pipeProduce } from '@/utils/producer'; const SecretAddForm = () => { @@ -36,7 +37,8 @@ const SecretAddForm = () => { const router = useRouter(); const putSecret = useMutation({ - mutationFn: putSecretReq, + mutationFn: (d: APISIXType['Secret']) => + putSecretReq(req, pipeProduce()(d)), async onSuccess() { notifications.show({ message: t('info.add.success', { name: t('secrets.singular') }), @@ -61,11 +63,7 @@ const SecretAddForm = () => { return ( <FormProvider {...form}> - <form - onSubmit={form.handleSubmit((d) => - putSecret.mutateAsync(pipeProduce()(d)) - )} - > + <form onSubmit={form.handleSubmit((d) => putSecret.mutateAsync(d))}> <FormSectionGeneral showDate={false} /> <FormPartSecret /> <FormSubmitBtn>{t('form.btn.add')}</FormSubmitBtn> diff --git a/src/routes/secrets/detail.$manager.$id.tsx b/src/routes/secrets/detail.$manager.$id.tsx index de6d5db3f..9c2e96599 100644 --- a/src/routes/secrets/detail.$manager.$id.tsx +++ b/src/routes/secrets/detail.$manager.$id.tsx @@ -28,7 +28,8 @@ import { FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { useBoolean } from 'react-use'; -import { getSecretQueryOptions, putSecretReq } from '@/apis/secrets'; +import { getSecretQueryOptions } from '@/apis/hooks'; +import { putSecretReq } from '@/apis/secrets'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartSecret } from '@/components/form-slice/FormPartSecret'; import { FormTOCBox } from '@/components/form-slice/FormSection'; @@ -36,6 +37,7 @@ import { FormSectionGeneral } from '@/components/form-slice/FormSectionGeneral'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { API_SECRETS } from '@/config/constant'; +import { req } from '@/config/req'; import { APISIX, type APISIXType } from '@/types/schema/apisix'; import { pipeProduce } from '@/utils/producer'; @@ -73,7 +75,8 @@ const SecretDetailForm = (props: Props) => { }, [secretData, form, isLoading, readOnly]); const putSecret = useMutation({ - mutationFn: putSecretReq, + mutationFn: (d: APISIXType['Secret']) => + putSecretReq(req, pipeProduce()(d)), async onSuccess() { notifications.show({ message: t('info.edit.success', { name: t('secrets.singular') }), @@ -90,11 +93,7 @@ const SecretDetailForm = (props: Props) => { return ( <FormProvider {...form}> - <form - onSubmit={form.handleSubmit((d) => { - putSecret.mutateAsync(pipeProduce()(d)); - })} - > + <form onSubmit={form.handleSubmit((d) => putSecret.mutateAsync(d))}> <FormSectionGeneral readOnly /> <FormPartSecret readOnlyManager /> {!readOnly && ( diff --git a/src/routes/secrets/index.tsx b/src/routes/secrets/index.tsx index 18a7417e7..fa9810c34 100644 --- a/src/routes/secrets/index.tsx +++ b/src/routes/secrets/index.tsx @@ -16,12 +16,11 @@ */ import type { ProColumns } from '@ant-design/pro-components'; import { ProTable } from '@ant-design/pro-components'; -import { useSuspenseQuery } from '@tanstack/react-query'; import { createFileRoute } from '@tanstack/react-router'; -import { useEffect, useMemo } from 'react'; +import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { getSecretListQueryOptions } from '@/apis/secrets'; +import { getSecretListQueryOptions, useSecretList } from '@/apis/hooks'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { ToAddPageBtn, ToDetailPageBtn } from '@/components/page/ToAddPageBtn'; @@ -30,23 +29,10 @@ import { API_SECRETS } from '@/config/constant'; import { queryClient } from '@/config/global'; import type { APISIXType } from '@/types/schema/apisix'; import { pageSearchSchema } from '@/types/schema/pageSearch'; -import { usePagination } from '@/utils/usePagination'; function SecretList() { const { t } = useTranslation(); - - const { pagination, handlePageChange, updateTotal } = usePagination({ - queryKey: 'secrets', - }); - - const secretsQuery = useSuspenseQuery(getSecretListQueryOptions(pagination)); - const { data, isLoading, refetch } = secretsQuery; - - useEffect(() => { - if (data?.total) { - updateTotal(data.total); - } - }, [data?.total, updateTotal]); + const { data, isLoading, refetch, pagination } = useSecretList(); const columns = useMemo< ProColumns<APISIXType['RespSecretList']['data']['list'][number]>[] @@ -101,13 +87,7 @@ function SecretList() { loading={isLoading} search={false} options={false} - pagination={{ - current: pagination.page, - pageSize: pagination.pageSize, - total: pagination.total, - showSizeChanger: true, - onChange: handlePageChange, - }} + pagination={pagination} cardProps={{ bodyStyle: { padding: 0 } }} toolbar={{ menu: { diff --git a/src/routes/services/add.tsx b/src/routes/services/add.tsx index 37b83ad9b..469e380ab 100644 --- a/src/routes/services/add.tsx +++ b/src/routes/services/add.tsx @@ -21,12 +21,13 @@ import { createFileRoute, useRouter } from '@tanstack/react-router'; import { FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import { postServiceReq } from '@/apis/services'; +import { postServiceReq, type ServicePostType } from '@/apis/services'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartService } from '@/components/form-slice/FormPartService'; import { ServicePostSchema } from '@/components/form-slice/FormPartService/schema'; import { FormTOCBox } from '@/components/form-slice/FormSection'; import PageHeader from '@/components/page/PageHeader'; +import { req } from '@/config/req'; import { pipeProduce } from '@/utils/producer'; const ServiceAddForm = () => { @@ -34,7 +35,7 @@ const ServiceAddForm = () => { const router = useRouter(); const postService = useMutation({ - mutationFn: postServiceReq, + mutationFn: (d: ServicePostType) => postServiceReq(req, pipeProduce()(d)), async onSuccess() { notifications.show({ message: t('info.add.success', { name: t('services.singular') }), @@ -53,11 +54,7 @@ const ServiceAddForm = () => { return ( <FormProvider {...form}> - <form - onSubmit={form.handleSubmit((d) => - postService.mutateAsync(pipeProduce()(d)) - )} - > + <form onSubmit={form.handleSubmit((d) => postService.mutateAsync(d))}> <FormPartService /> <FormSubmitBtn>{t('form.btn.add')}</FormSubmitBtn> </form> diff --git a/src/routes/services/detail.$id.tsx b/src/routes/services/detail.$id.tsx index 9c613f7a1..bf73a60bc 100644 --- a/src/routes/services/detail.$id.tsx +++ b/src/routes/services/detail.$id.tsx @@ -17,7 +17,7 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { Button, Group,Skeleton } from '@mantine/core'; import { notifications } from '@mantine/notifications'; -import { useMutation, useQuery } from '@tanstack/react-query'; +import { useMutation, useSuspenseQuery } from '@tanstack/react-query'; import { createFileRoute, useNavigate, @@ -28,7 +28,8 @@ import { FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { useBoolean } from 'react-use'; -import { getServiceQueryOptions, putServiceReq } from '@/apis/services'; +import { getServiceQueryOptions } from '@/apis/hooks'; +import { putServiceReq } from '@/apis/services'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartService } from '@/components/form-slice/FormPartService'; import { FormTOCBox } from '@/components/form-slice/FormSection'; @@ -36,7 +37,8 @@ import { FormSectionGeneral } from '@/components/form-slice/FormSectionGeneral'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { API_SERVICES } from '@/config/constant'; -import { APISIX } from '@/types/schema/apisix'; +import { req } from '@/config/req'; +import { APISIX, type APISIXType } from '@/types/schema/apisix'; import { pipeProduce } from '@/utils/producer'; type Props = { @@ -49,7 +51,7 @@ const ServiceDetailForm = (props: Props) => { const { t } = useTranslation(); const { id } = useParams({ from: '/services/detail/$id' }); - const serviceQuery = useQuery(getServiceQueryOptions(id)); + const serviceQuery = useSuspenseQuery(getServiceQueryOptions(id)); const { data: serviceData, isLoading, refetch } = serviceQuery; const form = useForm({ @@ -67,7 +69,8 @@ const ServiceDetailForm = (props: Props) => { }, [serviceData, form, isLoading]); const putService = useMutation({ - mutationFn: putServiceReq, + mutationFn: (d: APISIXType['Service']) => + putServiceReq(req, pipeProduce()(d)), async onSuccess() { notifications.show({ message: t('info.edit.success', { name: t('services.singular') }), @@ -84,11 +87,7 @@ const ServiceDetailForm = (props: Props) => { return ( <FormProvider {...form}> - <form - onSubmit={form.handleSubmit((d) => { - putService.mutateAsync(pipeProduce()(d)); - })} - > + <form onSubmit={form.handleSubmit((d) => putService.mutateAsync(d))}> <FormSectionGeneral /> <FormPartService /> {!readOnly && ( diff --git a/src/routes/services/index.tsx b/src/routes/services/index.tsx index b01b776ed..10fa740b2 100644 --- a/src/routes/services/index.tsx +++ b/src/routes/services/index.tsx @@ -16,12 +16,11 @@ */ import type { ProColumns } from '@ant-design/pro-components'; import { ProTable } from '@ant-design/pro-components'; -import { useSuspenseQuery } from '@tanstack/react-query'; import { createFileRoute } from '@tanstack/react-router'; -import { useEffect, useMemo } from 'react'; +import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { getServiceListQueryOptions } from '@/apis/services'; +import { getServiceListQueryOptions, useServiceList } from '@/apis/hooks'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { ToAddPageBtn,ToDetailPageBtn } from '@/components/page/ToAddPageBtn'; @@ -30,23 +29,11 @@ import { API_SERVICES } from '@/config/constant'; import { queryClient } from '@/config/global'; import type { APISIXType } from '@/types/schema/apisix'; import { pageSearchSchema } from '@/types/schema/pageSearch'; -import { usePagination } from '@/utils/usePagination'; const ServiceList = () => { - const { pagination, handlePageChange, updateTotal } = usePagination({ - queryKey: 'services', - }); - - const query = useSuspenseQuery(getServiceListQueryOptions(pagination)); - const { data, isLoading, refetch } = query; + const { data, isLoading, refetch, pagination } = useServiceList(); const { t } = useTranslation(); - useEffect(() => { - if (data?.total) { - updateTotal(data.total); - } - }, [data?.total, updateTotal]); - const columns = useMemo<ProColumns<APISIXType['RespServiceItem']>[]>(() => { return [ { @@ -110,13 +97,7 @@ const ServiceList = () => { loading={isLoading} search={false} options={false} - pagination={{ - current: pagination.page, - pageSize: pagination.pageSize, - total: pagination.total, - showSizeChanger: true, - onChange: handlePageChange, - }} + pagination={pagination} cardProps={{ bodyStyle: { padding: 0 } }} toolbar={{ menu: { diff --git a/src/routes/ssls/add.tsx b/src/routes/ssls/add.tsx index fe84f82fd..356f25010 100644 --- a/src/routes/ssls/add.tsx +++ b/src/routes/ssls/add.tsx @@ -21,6 +21,7 @@ import { createFileRoute, useRouter } from '@tanstack/react-router'; import { FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; +import { postSSLReq } from '@/apis/ssls'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartSSL } from '@/components/form-slice/FormPartSSL'; import { @@ -29,17 +30,14 @@ import { } from '@/components/form-slice/FormPartSSL/schema'; import { FormTOCBox } from '@/components/form-slice/FormSection'; import PageHeader from '@/components/page/PageHeader'; -import { API_SSLS } from '@/config/constant'; import { req } from '@/config/req'; -import { type APISIXType } from '@/types/schema/apisix'; import { pipeProduce } from '@/utils/producer'; const SSLAddForm = () => { const { t } = useTranslation(); const router = useRouter(); const postSSL = useMutation({ - mutationFn: (data: SSLPostType) => - req.post<unknown, APISIXType['RespSSLDetail']>(API_SSLS, data), + mutationFn: (d: SSLPostType) => postSSLReq(req, pipeProduce()(d)), async onSuccess() { notifications.show({ message: t('info.add.success', { name: t('ssls.singular') }), @@ -59,11 +57,7 @@ const SSLAddForm = () => { return ( <FormProvider {...form}> - <form - onSubmit={form.handleSubmit((d) => - postSSL.mutateAsync(pipeProduce()(d)) - )} - > + <form onSubmit={form.handleSubmit((d) => postSSL.mutateAsync(d))}> <FormPartSSL /> <FormSubmitBtn>{t('form.btn.add')}</FormSubmitBtn> </form> diff --git a/src/routes/ssls/detail.$id.tsx b/src/routes/ssls/detail.$id.tsx index 4c323131b..729585e6c 100644 --- a/src/routes/ssls/detail.$id.tsx +++ b/src/routes/ssls/detail.$id.tsx @@ -28,18 +28,21 @@ import { FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { useBoolean } from 'react-use'; -import { getSSLDetailQueryOptions, putSSLReq } from '@/apis/ssls'; +import { getSSLQueryOptions } from '@/apis/hooks'; +import { putSSLReq } from '@/apis/ssls'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartSSL } from '@/components/form-slice/FormPartSSL'; import { produceToSSLForm, SSLPutSchema, + type SSLPutType, } from '@/components/form-slice/FormPartSSL/schema'; import { FormTOCBox } from '@/components/form-slice/FormSection'; import { FormSectionGeneral } from '@/components/form-slice/FormSectionGeneral'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { API_SSLS } from '@/config/constant'; +import { req } from '@/config/req'; import { pipeProduce } from '@/utils/producer'; type Props = { @@ -54,7 +57,7 @@ const SSLDetailForm = (props: Props & { id: string }) => { data: { value: sslData }, isLoading, refetch, - } = useSuspenseQuery(getSSLDetailQueryOptions(id)); + } = useSuspenseQuery(getSSLQueryOptions(id)); const form = useForm({ resolver: zodResolver(SSLPutSchema), @@ -64,7 +67,7 @@ const SSLDetailForm = (props: Props & { id: string }) => { }); const putSSL = useMutation({ - mutationFn: putSSLReq, + mutationFn: (d: SSLPutType) => putSSLReq(req, pipeProduce()(d)), async onSuccess() { notifications.show({ message: t('info.edit.success', { name: t('ssls.singular') }), diff --git a/src/routes/ssls/index.tsx b/src/routes/ssls/index.tsx index 1b485136a..9bc31f207 100644 --- a/src/routes/ssls/index.tsx +++ b/src/routes/ssls/index.tsx @@ -16,12 +16,11 @@ */ import type { ProColumns } from '@ant-design/pro-components'; import { ProTable } from '@ant-design/pro-components'; -import { useSuspenseQuery } from '@tanstack/react-query'; import { createFileRoute } from '@tanstack/react-router'; -import { useEffect, useMemo } from 'react'; +import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { getSSLListQueryOptions } from '@/apis/ssls'; +import { getSSLListQueryOptions, useSSLList } from '@/apis/hooks'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { ToAddPageBtn, ToDetailPageBtn } from '@/components/page/ToAddPageBtn'; @@ -30,23 +29,10 @@ import { API_SSLS } from '@/config/constant'; import { queryClient } from '@/config/global'; import type { APISIXType } from '@/types/schema/apisix'; import { pageSearchSchema } from '@/types/schema/pageSearch'; -import { usePagination } from '@/utils/usePagination'; function RouteComponent() { const { t } = useTranslation(); - - const { pagination, handlePageChange, updateTotal } = usePagination({ - queryKey: 'ssls', - }); - - const sslsQuery = useSuspenseQuery(getSSLListQueryOptions(pagination)); - const { data, isLoading, refetch } = sslsQuery; - - useEffect(() => { - if (data?.total) { - updateTotal(data.total); - } - }, [data?.total, updateTotal]); + const { data, isLoading, refetch, pagination } = useSSLList(); const columns = useMemo<ProColumns<APISIXType['RespSSLItem']>[]>(() => { return [ @@ -113,13 +99,7 @@ function RouteComponent() { loading={isLoading} search={false} options={false} - pagination={{ - current: pagination.page, - pageSize: pagination.pageSize, - total: pagination.total, - showSizeChanger: true, - onChange: handlePageChange, - }} + pagination={pagination} cardProps={{ bodyStyle: { padding: 0 } }} toolbar={{ menu: { diff --git a/src/routes/stream_routes/add.tsx b/src/routes/stream_routes/add.tsx index 0e986a980..405ad9d01 100644 --- a/src/routes/stream_routes/add.tsx +++ b/src/routes/stream_routes/add.tsx @@ -24,9 +24,13 @@ import { useTranslation } from 'react-i18next'; import { postStreamRouteReq } from '@/apis/stream_routes'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartStreamRoute } from '@/components/form-slice/FormPartStreamRoute'; -import { StreamRoutePostSchema } from '@/components/form-slice/FormPartStreamRoute/schema'; +import { + StreamRoutePostSchema, + type StreamRoutePostType, +} from '@/components/form-slice/FormPartStreamRoute/schema'; import { FormTOCBox } from '@/components/form-slice/FormSection'; import PageHeader from '@/components/page/PageHeader'; +import { req } from '@/config/req'; import { pipeProduce } from '@/utils/producer'; const StreamRouteAddForm = () => { @@ -34,7 +38,8 @@ const StreamRouteAddForm = () => { const router = useRouter(); const postStreamRoute = useMutation({ - mutationFn: postStreamRouteReq, + mutationFn: (d: StreamRoutePostType) => + postStreamRouteReq(req, pipeProduce()(d)), async onSuccess() { notifications.show({ message: t('info.add.success', { name: t('streamRoutes.singular') }), @@ -53,11 +58,7 @@ const StreamRouteAddForm = () => { return ( <FormProvider {...form}> - <form - onSubmit={form.handleSubmit((d) => - postStreamRoute.mutateAsync(pipeProduce()(d)) - )} - > + <form onSubmit={form.handleSubmit((d) => postStreamRoute.mutateAsync(d))}> <FormPartStreamRoute /> <FormSubmitBtn>{t('form.btn.add')}</FormSubmitBtn> </form> diff --git a/src/routes/stream_routes/detail.$id.tsx b/src/routes/stream_routes/detail.$id.tsx index 4b634851e..cb1e8d178 100644 --- a/src/routes/stream_routes/detail.$id.tsx +++ b/src/routes/stream_routes/detail.$id.tsx @@ -28,10 +28,8 @@ import { FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { useBoolean } from 'react-use'; -import { - getStreamRouteQueryOptions, - putStreamRouteReq, -} from '@/apis/stream_routes'; +import { getStreamRouteQueryOptions } from '@/apis/hooks'; +import { putStreamRouteReq } from '@/apis/stream_routes'; import { FormSubmitBtn } from '@/components/form/Btn'; import { FormPartStreamRoute } from '@/components/form-slice/FormPartStreamRoute'; import { FormTOCBox } from '@/components/form-slice/FormSection'; @@ -39,7 +37,8 @@ import { FormSectionGeneral } from '@/components/form-slice/FormSectionGeneral'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { API_STREAM_ROUTES } from '@/config/constant'; -import { APISIX } from '@/types/schema/apisix'; +import { req } from '@/config/req'; +import { APISIX, type APISIXType } from '@/types/schema/apisix'; import { pipeProduce } from '@/utils/producer'; type Props = { @@ -70,7 +69,8 @@ const StreamRouteDetailForm = (props: Props) => { }, [streamRouteData, form, isLoading]); const putStreamRoute = useMutation({ - mutationFn: putStreamRouteReq, + mutationFn: (d: APISIXType['StreamRoute']) => + putStreamRouteReq(req, pipeProduce()(d)), async onSuccess() { notifications.show({ message: t('info.edit.success', { name: t('streamRoutes.singular') }), @@ -87,11 +87,7 @@ const StreamRouteDetailForm = (props: Props) => { return ( <FormProvider {...form}> - <form - onSubmit={form.handleSubmit((d) => { - putStreamRoute.mutateAsync(pipeProduce()(d)); - })} - > + <form onSubmit={form.handleSubmit((d) => putStreamRoute.mutateAsync(d))}> <FormSectionGeneral /> <FormPartStreamRoute /> {!readOnly && ( diff --git a/src/routes/stream_routes/index.tsx b/src/routes/stream_routes/index.tsx index b7b5dd5b2..6676af7b3 100644 --- a/src/routes/stream_routes/index.tsx +++ b/src/routes/stream_routes/index.tsx @@ -16,12 +16,11 @@ */ import type { ProColumns } from '@ant-design/pro-components'; import { ProTable } from '@ant-design/pro-components'; -import { useSuspenseQuery } from '@tanstack/react-query'; import { createFileRoute } from '@tanstack/react-router'; -import { useEffect, useMemo } from 'react'; +import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { getStreamRouteListQueryOptions } from '@/apis/stream_routes'; +import { getStreamRouteListQueryOptions, useStreamRouteList } from '@/apis/hooks'; import { DeleteResourceBtn } from '@/components/page/DeleteResourceBtn'; import PageHeader from '@/components/page/PageHeader'; import { ToAddPageBtn,ToDetailPageBtn } from '@/components/page/ToAddPageBtn'; @@ -30,23 +29,11 @@ import { API_STREAM_ROUTES } from '@/config/constant'; import { queryClient } from '@/config/global'; import type { APISIXType } from '@/types/schema/apisix'; import { pageSearchSchema } from '@/types/schema/pageSearch'; -import { usePagination } from '@/utils/usePagination'; const StreamRouteList = () => { - const { pagination, handlePageChange, updateTotal } = usePagination({ - queryKey: 'stream_routes', - }); - - const query = useSuspenseQuery(getStreamRouteListQueryOptions(pagination)); - const { data, isLoading, refetch } = query; + const { data, isLoading, refetch, pagination } = useStreamRouteList(); const { t } = useTranslation(); - useEffect(() => { - if (data?.total) { - updateTotal(data.total); - } - }, [data?.total, updateTotal]); - const columns = useMemo< ProColumns<APISIXType['RespStreamRouteItem']>[] >(() => { @@ -101,13 +88,7 @@ const StreamRouteList = () => { loading={isLoading} search={false} options={false} - pagination={{ - current: pagination.page, - pageSize: pagination.pageSize, - total: pagination.total, - showSizeChanger: true, - onChange: handlePageChange, - }} + pagination={pagination} cardProps={{ bodyStyle: { padding: 0 } }} toolbar={{ menu: { diff --git a/src/routes/upstreams/add.tsx b/src/routes/upstreams/add.tsx index 244504066..a080b815e 100644 --- a/src/routes/upstreams/add.tsx +++ b/src/routes/upstreams/add.tsx @@ -41,7 +41,7 @@ const UpstreamAddForm = () => { const { t } = useTranslation(); const router = useRouter(); const postUpstream = useMutation({ - mutationFn: (data: PostUpstreamType) => postUpstreamReq(req, data), + mutationFn: (d: PostUpstreamType) => postUpstreamReq(req, d), async onSuccess(data) { notifications.show({ message: t('info.add.success', { name: t('upstreams.singular') }), diff --git a/src/routes/upstreams/detail.$id.tsx b/src/routes/upstreams/detail.$id.tsx index 7d8e539f8..441826d21 100644 --- a/src/routes/upstreams/detail.$id.tsx +++ b/src/routes/upstreams/detail.$id.tsx @@ -76,7 +76,7 @@ const UpstreamDetailForm = ( }); const putUpstream = useMutation({ - mutationFn: (data: APISIXType['Upstream']) => putUpstreamReq(req, data), + mutationFn: (d: APISIXType['Upstream']) => putUpstreamReq(req, d), async onSuccess() { notifications.show({ message: t('info.edit.success', { name: t('upstreams.singular') }), diff --git a/src/types/schema/pageSearch.ts b/src/types/schema/pageSearch.ts index dc2f25b70..fb663566b 100644 --- a/src/types/schema/pageSearch.ts +++ b/src/types/schema/pageSearch.ts @@ -16,39 +16,22 @@ */ import { z } from 'zod'; -/** - * To deprecate pageSize without modifying existing code, use preprocessing. - */ -export const pageSearchSchema = z.preprocess( - (data) => { - // If pageSize is provided but page_size isn't, use pageSize value for page_size - const inputData = data as Record<string, unknown>; - if (inputData?.pageSize && inputData?.page_size === undefined) { - return { ...inputData, page_size: inputData.pageSize }; - } - return data; - }, - z - .object({ - page: z - .union([z.string(), z.number()]) - .optional() - .default(1) - .transform((val) => (val ? Number(val) : 1)), - pageSize: z - .union([z.string(), z.number()]) - .optional() - .default(10) - .transform((val) => (val ? Number(val) : 10)), - page_size: z - .union([z.string(), z.number()]) - .optional() - .default(10) - .transform((val) => (val ? Number(val) : 10)), - name: z.string().optional(), - label: z.string().optional(), - }) - .passthrough() -); + +export const pageSearchSchema = z + .object({ + page: z + .union([z.string(), z.number()]) + .optional() + .default(1) + .transform((val) => (val ? Number(val) : 1)), + page_size: z + .union([z.string(), z.number()]) + .optional() + .default(10) + .transform((val) => (val ? Number(val) : 10)), + name: z.string().optional(), + label: z.string().optional(), + }) + .passthrough(); export type PageSearchType = z.infer<typeof pageSearchSchema>; diff --git a/src/utils/usePagination.ts b/src/utils/usePagination.ts deleted file mode 100644 index d30bfd029..000000000 --- a/src/utils/usePagination.ts +++ /dev/null @@ -1,174 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { useRouter } from '@tanstack/react-router'; -import { useCallback, useEffect,useState } from 'react'; - -import { queryClient } from '@/config/global'; -import type { PageSearchType } from '@/types/schema/pageSearch'; - -type PaginationState = PageSearchType & { - total: number; -}; - -interface UsePaginationOptions { - initialPage?: number; - initialPageSize?: number; - initialTotal?: number; - queryKey: string; - /** If true, updates URL with pagination state */ - syncWithUrl?: boolean; -} - -export interface UsePaginationResult { - pagination: PaginationState; - setPagination: React.Dispatch<React.SetStateAction<PaginationState>>; - handlePageChange: (page: number, pageSize: number) => void; - createQueryKey: (page: number, pageSize: number) => (string | number)[]; - refreshData: () => void; - updateTotal: (total: number) => void; -} - -/** - * Custom hook for managing pagination state and related operations - * - * @param options - Configuration options for pagination - * @returns Pagination state and handlers - */ -export function usePagination( - options: UsePaginationOptions -): UsePaginationResult { - const { - initialPage = 1, - initialPageSize = 10, - initialTotal = 0, - queryKey, - syncWithUrl = true, - } = options; - - // Get router for URL integration - const router = useRouter(); - const routeSearch = router.state.location.search; - - // Initialize pagination from URL if available - const urlPage = - syncWithUrl && routeSearch.page - ? Number(routeSearch.page) || initialPage - : initialPage; - const urlPageSize = - syncWithUrl && routeSearch.pageSize - ? Number(routeSearch.pageSize) || initialPageSize - : initialPageSize; - - const [pagination, setPagination] = useState<PaginationState>({ - page: urlPage, - page_size: urlPageSize, - pageSize: urlPageSize, - total: initialTotal, - }); - - // Sync URL with state when URL params change - useEffect(() => { - if (syncWithUrl) { - const urlPage = routeSearch.page ? Number(routeSearch.page) || 1 : null; - const urlPageSize = routeSearch.pageSize - ? Number(routeSearch.pageSize) || 10 - : null; - - if ( - (urlPage !== null && urlPage !== pagination.page) || - (urlPageSize !== null && urlPageSize !== pagination.pageSize) - ) { - setPagination((prev) => ({ - ...prev, - current: urlPage || prev.page, - pageSize: urlPageSize || prev.pageSize, - })); - } - } - }, [routeSearch, syncWithUrl, pagination]); - - /** - * Creates a query key array for React Query based on the given page and pageSize - */ - const createQueryKey = useCallback( - (page: number, pageSize: number): (string | number)[] => [ - queryKey, - page, - pageSize, - ], - [queryKey] - ); - - /** - * Handles page and page size changes - */ - const handlePageChange = useCallback( - (page: number, pageSize: number) => { - setPagination((prev) => ({ - ...prev, - current: page, - pageSize: pageSize, - })); - - // Update URL with new pagination state if enabled - if (syncWithUrl) { - router.navigate({ - search: (prev) => { - // Keep all existing search params - const newSearch = { ...prev }; - newSearch.page = page; - newSearch.pageSize = pageSize; - return newSearch as never; - }, - replace: true, - }); - } - - // Invalidate the query to trigger a refetch with new pagination - queryClient.invalidateQueries({ - queryKey: createQueryKey(page, pageSize), - }); - }, - [createQueryKey, router, syncWithUrl] - ); - - /** - * Updates pagination total when data changes - */ - const updateTotal = useCallback((total: number) => { - setPagination((prev) => ({ ...prev, total })); - }, []); - - /** - * Refreshes current page data - */ - const refreshData = useCallback(() => { - const { page, pageSize } = pagination; - queryClient.invalidateQueries({ - queryKey: createQueryKey(page, pageSize), - }); - }, [createQueryKey, pagination]); - - return { - pagination, - setPagination, - handlePageChange, - createQueryKey, - refreshData, - updateTotal, - }; -} diff --git a/src/utils/useSearchParams.ts b/src/utils/useSearchParams.ts index 35fc8315b..a9c3b3cfa 100644 --- a/src/utils/useSearchParams.ts +++ b/src/utils/useSearchParams.ts @@ -22,21 +22,22 @@ import { } from '@tanstack/react-router'; import { useCallback } from 'react'; -import type { PageSearchType } from '@/types/schema/pageSearch'; -type RouteTreeIds = RouteIds<RegisteredRouter['routeTree']>; -export const useSearchParams = <T extends RouteTreeIds>(routeId: T) => { +export type RouteTreeIds = RouteIds<RegisteredRouter['routeTree']>; + +export const useSearchParams = <T extends RouteTreeIds, P extends object>( + routeId: T +) => { const { useSearch } = getRouteApi<T>(routeId); const navigate = useNavigate(); - const params = useSearch(); - type Params = typeof params; + const params = useSearch() as P; const setParams = useCallback( - (props: Partial<Params>) => { + (props: Partial<P>) => { return navigate({ to: '.', - search: (prev: object) => ({ ...prev, ...props }), + search: (prev) => ({ ...prev, ...props }), }); }, [navigate] @@ -46,9 +47,10 @@ export const useSearchParams = <T extends RouteTreeIds>(routeId: T) => { [navigate] ); - return { params: params as PageSearchType, setParams, resetParams } as const; + return { params, setParams, resetParams } as const; }; -export type UseSearchParams<T extends RouteTreeIds> = ReturnType< - typeof useSearchParams<T> ->; +export type UseSearchParams< + T extends RouteTreeIds, + P extends object +> = ReturnType<typeof useSearchParams<T, P>>; diff --git a/src/utils/useTablePagination.ts b/src/utils/useTablePagination.ts index 602a510be..a1e376a7c 100644 --- a/src/utils/useTablePagination.ts +++ b/src/utils/useTablePagination.ts @@ -20,18 +20,23 @@ import { useCallback, useMemo } from 'react'; import type { FileRoutesByTo } from '@/routeTree.gen'; import type { APISIXListResponse } from '@/types/schema/apisix/type'; -import { pageSearchSchema } from '@/types/schema/pageSearch'; +import { + pageSearchSchema, + type PageSearchType, +} from '@/types/schema/pageSearch'; import type { UseSearchParams } from './useSearchParams'; -type ListPageKeys = `${keyof FilterKeys<FileRoutesByTo, 's'>}/`; -type Props<T> = { +export type ListPageKeys = `${keyof FilterKeys<FileRoutesByTo, 's'>}/`; +type Props<T, P extends PageSearchType> = { data: APISIXListResponse<T>; /** if params is from useSearchParams, refetch is not needed */ refetch?: () => void; -} & Pick<UseSearchParams<ListPageKeys>, 'params' | 'setParams'>; +} & Pick<UseSearchParams<ListPageKeys, P>, 'params' | 'setParams'>; -export const useTablePagination = <T>(props: Props<T>) => { +export const useTablePagination = <T, P extends PageSearchType>( + props: Props<T, P> +) => { const { data, refetch, setParams } = props; const params = useMemo( () => pageSearchSchema.parse(props.params), @@ -40,8 +45,8 @@ export const useTablePagination = <T>(props: Props<T>) => { const { page, page_size } = params; const onChange: TablePaginationConfig['onChange'] = useCallback( - (page: number, pageSize: number) => { - setParams({ page, page_size: pageSize }); + (page: number, page_size: number) => { + setParams({ page, page_size } as P); refetch?.(); }, [refetch, setParams]