feat: Bring back API key sales channel management (#6976)

- Add API key sales channel management
- Add HTTP responses for API keys and sales channels
- Use HTTP responses in `dashboard` and remove now redundant types
This commit is contained in:
Oli Juhl authored and GitHub committed 2024-04-06 16:30:27 +00:00
1 parent 58c68f6715
commit 5724d80286
22 files changed
+535 -609

No files matched your search

@@ -10,11 +10,9 @@ import { client } from "../../lib/client"
import { queryClient } from "../../lib/medusa" import { queryClient } from "../../lib/medusa"
import { queryKeysFactory } from "../../lib/query-key-factory" import { queryKeysFactory } from "../../lib/query-key-factory"
import { CreateApiKeyReq, UpdateApiKeyReq } from "../../types/api-payloads" import { CreateApiKeyReq, UpdateApiKeyReq } from "../../types/api-payloads"
import { import { ApiKeyDeleteRes } from "../../types/api-responses"
ApiKeyDeleteRes, import { AdminApiKeyResponse, AdminApiKeyListResponse } from "@medusajs/types"
ApiKeyListRes, import { salesChannelsQueryKeys } from "./sales-channels"
ApiKeyRes,
} from "../../types/api-responses"
const API_KEYS_QUERY_KEY = "api_keys" as const const API_KEYS_QUERY_KEY = "api_keys" as const
export const apiKeysQueryKeys = queryKeysFactory(API_KEYS_QUERY_KEY) export const apiKeysQueryKeys = queryKeysFactory(API_KEYS_QUERY_KEY)
@@ -23,7 +21,7 @@ export const useApiKey = (
id: string, id: string,
query?: Record<string, any>, query?: Record<string, any>,
options?: Omit< options?: Omit<
UseQueryOptions<ApiKeyRes, Error, ApiKeyRes, QueryKey>, UseQueryOptions<AdminApiKeyResponse, Error, AdminApiKeyResponse, QueryKey>,
"queryKey" | "queryFn" "queryKey" | "queryFn"
> >
) => { ) => {
@@ -39,7 +37,12 @@ export const useApiKey = (
export const useApiKeys = ( export const useApiKeys = (
query?: Record<string, any>, query?: Record<string, any>,
options?: Omit< options?: Omit<
UseQueryOptions<ApiKeyListRes, Error, ApiKeyListRes, QueryKey>, UseQueryOptions<
AdminApiKeyListResponse,
Error,
AdminApiKeyListResponse,
QueryKey
>,
"queryKey" | "queryFn" "queryKey" | "queryFn"
> >
) => { ) => {
@@ -53,7 +56,7 @@ export const useApiKeys = (
} }
export const useCreateApiKey = ( export const useCreateApiKey = (
options?: UseMutationOptions<ApiKeyRes, Error, CreateApiKeyReq> options?: UseMutationOptions<AdminApiKeyResponse, Error, CreateApiKeyReq>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: (payload) => client.apiKeys.create(payload), mutationFn: (payload) => client.apiKeys.create(payload),
@@ -68,7 +71,7 @@ export const useCreateApiKey = (
export const useUpdateApiKey = ( export const useUpdateApiKey = (
id: string, id: string,
options?: UseMutationOptions<ApiKeyRes, Error, UpdateApiKeyReq> options?: UseMutationOptions<AdminApiKeyResponse, Error, UpdateApiKeyReq>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: (payload) => client.apiKeys.update(id, payload), mutationFn: (payload) => client.apiKeys.update(id, payload),
@@ -84,7 +87,7 @@ export const useUpdateApiKey = (
export const useRevokeApiKey = ( export const useRevokeApiKey = (
id: string, id: string,
options?: UseMutationOptions<ApiKeyRes, Error, void> options?: UseMutationOptions<AdminApiKeyResponse, Error, void>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: () => client.apiKeys.revoke(id), mutationFn: () => client.apiKeys.revoke(id),
@@ -111,3 +114,50 @@ export const useDeleteApiKey = (
}, },
}) })
} }
export const useBatchRemoveSalesChannelsFromApiKey = (
id: string,
options?: UseMutationOptions<
AdminApiKeyResponse,
Error,
{ sales_channel_ids: string[] }
>
) => {
return useMutation({
mutationFn: (payload) =>
client.apiKeys.batchRemoveSalesChannels(id, payload),
onSuccess: (data, variables, context) => {
queryClient.invalidateQueries({ queryKey: apiKeysQueryKeys.lists() })
queryClient.invalidateQueries({ queryKey: apiKeysQueryKeys.detail(id) })
queryClient.invalidateQueries({
queryKey: salesChannelsQueryKeys.lists(),
})
options?.onSuccess?.(data, variables, context)
},
...options,
})
}
export const useBatchAddSalesChannelsToApiKey = (
id: string,
options?: UseMutationOptions<
AdminApiKeyResponse,
Error,
{ sales_channel_ids: string[] }
>
) => {
return useMutation({
mutationFn: (payload) => client.apiKeys.batchAddSalesChannels(id, payload),
onSuccess: (data, variables, context) => {
queryClient.invalidateQueries({ queryKey: apiKeysQueryKeys.lists() })
queryClient.invalidateQueries({ queryKey: apiKeysQueryKeys.detail(id) })
queryClient.invalidateQueries({
queryKey: salesChannelsQueryKeys.lists(),
})
options?.onSuccess?.(data, variables, context)
},
...options,
})
}
@@ -15,20 +15,25 @@ import {
RemoveProductsSalesChannelReq, RemoveProductsSalesChannelReq,
UpdateSalesChannelReq, UpdateSalesChannelReq,
} from "../../types/api-payloads" } from "../../types/api-payloads"
import { import { SalesChannelDeleteRes } from "../../types/api-responses"
SalesChannelDeleteRes,
SalesChannelListRes,
SalesChannelRes,
} from "../../types/api-responses"
import { productsQueryKeys } from "./products" import { productsQueryKeys } from "./products"
import {
AdminSalesChannelListResponse,
AdminSalesChannelResponse,
} from "@medusajs/types"
const SALES_CHANNELS_QUERY_KEY = "sales-channels" as const const SALES_CHANNELS_QUERY_KEY = "sales-channels" as const
const salesChannelsQueryKeys = queryKeysFactory(SALES_CHANNELS_QUERY_KEY) export const salesChannelsQueryKeys = queryKeysFactory(SALES_CHANNELS_QUERY_KEY)
export const useSalesChannel = ( export const useSalesChannel = (
id: string, id: string,
options?: Omit< options?: Omit<
UseQueryOptions<SalesChannelRes, Error, SalesChannelRes, QueryKey>, UseQueryOptions<
AdminSalesChannelResponse,
Error,
AdminSalesChannelResponse,
QueryKey
>,
"queryFn" | "queryKey" "queryFn" | "queryKey"
> >
) => { ) => {
@@ -44,7 +49,12 @@ export const useSalesChannel = (
export const useSalesChannels = ( export const useSalesChannels = (
query?: Record<string, any>, query?: Record<string, any>,
options?: Omit< options?: Omit<
UseQueryOptions<SalesChannelListRes, Error, SalesChannelListRes, QueryKey>, UseQueryOptions<
AdminSalesChannelListResponse,
Error,
AdminSalesChannelListResponse,
QueryKey
>,
"queryFn" | "queryKey" "queryFn" | "queryKey"
> >
) => { ) => {
@@ -58,7 +68,11 @@ export const useSalesChannels = (
} }
export const useCreateSalesChannel = ( export const useCreateSalesChannel = (
options?: UseMutationOptions<SalesChannelRes, Error, CreateSalesChannelReq> options?: UseMutationOptions<
AdminSalesChannelResponse,
Error,
CreateSalesChannelReq
>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: (payload) => client.salesChannels.create(payload), mutationFn: (payload) => client.salesChannels.create(payload),
@@ -74,7 +88,11 @@ export const useCreateSalesChannel = (
export const useUpdateSalesChannel = ( export const useUpdateSalesChannel = (
id: string, id: string,
options?: UseMutationOptions<SalesChannelRes, Error, UpdateSalesChannelReq> options?: UseMutationOptions<
AdminSalesChannelResponse,
Error,
UpdateSalesChannelReq
>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: (payload) => client.salesChannels.update(id, payload), mutationFn: (payload) => client.salesChannels.update(id, payload),
@@ -120,7 +138,7 @@ export const useDeleteSalesChannel = (
export const useSalesChannelRemoveProducts = ( export const useSalesChannelRemoveProducts = (
id: string, id: string,
options?: UseMutationOptions< options?: UseMutationOptions<
SalesChannelRes, AdminSalesChannelResponse,
Error, Error,
RemoveProductsSalesChannelReq RemoveProductsSalesChannelReq
> >
@@ -156,7 +174,7 @@ export const useSalesChannelRemoveProducts = (
export const useSalesChannelAddProducts = ( export const useSalesChannelAddProducts = (
id: string, id: string,
options?: UseMutationOptions< options?: UseMutationOptions<
SalesChannelRes, AdminSalesChannelResponse,
Error, Error,
AddProductsSalesChannelReq AddProductsSalesChannelReq
> >
@@ -1,17 +1,14 @@
import { AdminApiKeyListResponse, AdminApiKeyResponse } from "@medusajs/types"
import { CreateApiKeyReq, UpdateApiKeyReq } from "../../types/api-payloads" import { CreateApiKeyReq, UpdateApiKeyReq } from "../../types/api-payloads"
import { import { ApiKeyDeleteRes } from "../../types/api-responses"
ApiKeyDeleteRes,
ApiKeyListRes,
ApiKeyRes,
} from "../../types/api-responses"
import { deleteRequest, getRequest, postRequest } from "./common" import { deleteRequest, getRequest, postRequest } from "./common"
const retrieveApiKey = async (id: string, query?: Record<string, any>) => { const retrieveApiKey = async (id: string, query?: Record<string, any>) => {
return getRequest<ApiKeyRes>(`/admin/api-keys/${id}`, query) return getRequest<AdminApiKeyResponse>(`/admin/api-keys/${id}`, query)
} }
const listApiKeys = async (query?: Record<string, any>) => { const listApiKeys = async (query?: Record<string, any>) => {
return getRequest<ApiKeyListRes>(`/admin/api-keys`, query) return getRequest<AdminApiKeyListResponse>(`/admin/api-keys`, query)
} }
const deleteApiKey = async (id: string) => { const deleteApiKey = async (id: string) => {
@@ -19,15 +16,35 @@ const deleteApiKey = async (id: string) => {
} }
const revokeApiKey = async (id: string) => { const revokeApiKey = async (id: string) => {
return postRequest<ApiKeyRes>(`/admin/api-keys/${id}/revoke`) return postRequest<AdminApiKeyResponse>(`/admin/api-keys/${id}/revoke`)
} }
const createApiKey = async (payload: CreateApiKeyReq) => { const createApiKey = async (payload: CreateApiKeyReq) => {
return postRequest<ApiKeyRes>(`/admin/api-keys`, payload) return postRequest<AdminApiKeyResponse>(`/admin/api-keys`, payload)
} }
const updateApiKey = async (id: string, payload: UpdateApiKeyReq) => { const updateApiKey = async (id: string, payload: UpdateApiKeyReq) => {
return postRequest<ApiKeyRes>(`/admin/api-keys/${id}`, payload) return postRequest<AdminApiKeyResponse>(`/admin/api-keys/${id}`, payload)
}
const batchRemoveSalesChannelsFromApiKey = async (
id: string,
payload: { sales_channel_ids: string[] }
) => {
return postRequest<AdminApiKeyResponse>(
`/admin/api-keys/${id}/sales-channels/batch/remove`,
payload
)
}
const batchAddSalesChannelsFromApiKey = async (
id: string,
payload: { sales_channel_ids: string[] }
) => {
return postRequest<AdminApiKeyResponse>(
`/admin/api-keys/${id}/sales-channels/batch/add`,
payload
)
} }
export const apiKeys = { export const apiKeys = {
@@ -37,4 +54,6 @@ export const apiKeys = {
create: createApiKey, create: createApiKey,
update: updateApiKey, update: updateApiKey,
revoke: revokeApiKey, revoke: revokeApiKey,
batchRemoveSalesChannels: batchRemoveSalesChannelsFromApiKey,
batchAddSalesChannels: batchAddSalesChannelsFromApiKey,
} }
@@ -1,36 +1,42 @@
import {
AdminSalesChannelListResponse,
AdminSalesChannelResponse,
} from "@medusajs/types"
import { import {
AddProductsSalesChannelReq, AddProductsSalesChannelReq,
CreateSalesChannelReq, CreateSalesChannelReq,
RemoveProductsSalesChannelReq, RemoveProductsSalesChannelReq,
UpdateSalesChannelReq, UpdateSalesChannelReq,
} from "../../types/api-payloads" } from "../../types/api-payloads"
import { import { SalesChannelDeleteRes } from "../../types/api-responses"
SalesChannelDeleteRes,
SalesChannelListRes,
SalesChannelRes,
} from "../../types/api-responses"
import { deleteRequest, getRequest, postRequest } from "./common" import { deleteRequest, getRequest, postRequest } from "./common"
async function retrieveSalesChannel(id: string, query?: Record<string, any>) { async function retrieveSalesChannel(id: string, query?: Record<string, any>) {
return getRequest<SalesChannelRes, Record<string, any>>( return getRequest<AdminSalesChannelResponse, Record<string, any>>(
`/admin/sales-channels/${id}`, `/admin/sales-channels/${id}`,
query query
) )
} }
async function listSalesChannels(query?: Record<string, any>) { async function listSalesChannels(query?: Record<string, any>) {
return getRequest<SalesChannelListRes, Record<string, any>>( return getRequest<AdminSalesChannelListResponse, Record<string, any>>(
`/admin/sales-channels`, `/admin/sales-channels`,
query query
) )
} }
async function createSalesChannel(payload: CreateSalesChannelReq) { async function createSalesChannel(payload: CreateSalesChannelReq) {
return postRequest<SalesChannelRes>(`/admin/sales-channels`, payload) return postRequest<AdminSalesChannelResponse>(
`/admin/sales-channels`,
payload
)
} }
async function updateSalesChannel(id: string, payload: UpdateSalesChannelReq) { async function updateSalesChannel(id: string, payload: UpdateSalesChannelReq) {
return postRequest<SalesChannelRes>(`/admin/sales-channels/${id}`, payload) return postRequest<AdminSalesChannelResponse>(
`/admin/sales-channels/${id}`,
payload
)
} }
async function deleteSalesChannel(id: string) { async function deleteSalesChannel(id: string) {
@@ -41,7 +47,7 @@ async function batchRemoveProducts(
id: string, id: string,
payload: RemoveProductsSalesChannelReq payload: RemoveProductsSalesChannelReq
) { ) {
return postRequest<SalesChannelRes>( return postRequest<AdminSalesChannelResponse>(
`/admin/sales-channels/${id}/products/batch/remove`, `/admin/sales-channels/${id}/products/batch/remove`,
payload payload
) )
@@ -51,7 +57,7 @@ async function batchAddProducts(
id: string, id: string,
payload: AddProductsSalesChannelReq payload: AddProductsSalesChannelReq
) { ) {
return postRequest<SalesChannelRes>( return postRequest<AdminSalesChannelResponse>(
`/admin/sales-channels/${id}/products/batch/add`, `/admin/sales-channels/${id}/products/batch/add`,
payload payload
) )
@@ -7,7 +7,7 @@ import { ErrorBoundary } from "../../components/error/error-boundary"
import { MainLayout } from "../../components/layout-v2/main-layout" import { MainLayout } from "../../components/layout-v2/main-layout"
import { SettingsLayout } from "../../components/layout/settings-layout" import { SettingsLayout } from "../../components/layout/settings-layout"
import { useMe } from "../../hooks/api/users" import { useMe } from "../../hooks/api/users"
import { ApiKeyRes } from "../../types/api-responses" import { AdminApiKeyResponse } from "@medusajs/types"
import { SearchProvider } from "../search-provider" import { SearchProvider } from "../search-provider"
import { SidebarProvider } from "../sidebar-provider" import { SidebarProvider } from "../sidebar-provider"
@@ -489,8 +489,7 @@ export const v2Routes: RouteObject[] = [
"../../v2-routes/api-key-management/api-key-management-detail" "../../v2-routes/api-key-management/api-key-management-detail"
), ),
handle: { handle: {
crumb: (data: ApiKeyRes) => { crumb: (data: AdminApiKeyResponse) => {
console.log("data", data)
return data.api_key.title return data.api_key.title
}, },
}, },
@@ -3,7 +3,6 @@
*/ */
import { import {
ApiKeyDTO,
CampaignDTO, CampaignDTO,
CurrencyDTO, CurrencyDTO,
CustomerDTO, CustomerDTO,
@@ -22,8 +21,8 @@ import {
StoreDTO, StoreDTO,
UserDTO, UserDTO,
} from "@medusajs/types" } from "@medusajs/types"
import { WorkflowExecutionDTO } from "../v2-routes/workflow-executions/types"
import { ProductTagDTO } from "@medusajs/types/dist/product" import { ProductTagDTO } from "@medusajs/types/dist/product"
import { WorkflowExecutionDTO } from "../v2-routes/workflow-executions/types"
type ListRes = { type ListRes = {
count: number count: number
@@ -77,18 +76,9 @@ export type CampaignListRes = { campaigns: CampaignDTO[] } & ListRes
export type CampaignDeleteRes = DeleteRes export type CampaignDeleteRes = DeleteRes
// API Keys // API Keys
export type ExtendedApiKeyDTO = ApiKeyDTO & {
sales_channels: SalesChannelDTO[] | null
}
export type ApiKeyRes = { api_key: ExtendedApiKeyDTO }
export type ApiKeyListRes = { api_keys: ExtendedApiKeyDTO[] } & ListRes
export type ApiKeyDeleteRes = DeleteRes export type ApiKeyDeleteRes = DeleteRes
// Sales Channels // Sales Channels
export type SalesChannelRes = { sales_channel: SalesChannelDTO }
export type SalesChannelListRes = {
sales_channels: SalesChannelDTO[]
} & ListRes
export type SalesChannelDeleteRes = DeleteRes export type SalesChannelDeleteRes = DeleteRes
// Currencies // Currencies
@@ -1,37 +1,27 @@
// Missing Sales Channel endpoint for API Key domain
import { useParams } from "react-router-dom" import { useParams } from "react-router-dom"
import { RouteFocusModal } from "../../../components/route-modal" import { RouteFocusModal } from "../../../components/route-modal"
import { useSalesChannels } from "../../../hooks/api/sales-channels"
import { AddSalesChannelsToApiKeyForm } from "./components"
export const ApiKeyManagementAddSalesChannels = () => { export const ApiKeyManagementAddSalesChannels = () => {
const { id } = useParams() const { id } = useParams()
// const { data, isLoading, isError, error } = useAdminCustomQuery( const { sales_channels, isLoading, isError, error } = useSalesChannels({
// `/api-keys/${id}`, publishable_key_id: id,
// [adminPublishableApiKeysKeys.detailSalesChannels(id!)], })
// {
// fields: "id,*sales_channels",
// },
// {
// keepPreviousData: true,
// }
// )
// if (isError) { if (isError) {
// throw error throw error
// } }
// const salesChannels = data?.api_key?.sales_channels
return ( return (
<RouteFocusModal> <RouteFocusModal>
{/* {!isLoading && salesChannels && ( {!isLoading && !!sales_channels && (
<AddSalesChannelsToApiKeyForm <AddSalesChannelsToApiKeyForm
apiKey={id!} apiKey={id!}
preSelected={salesChannels.map((sc) => sc.id)} preSelected={sales_channels.map((sc) => sc.id)}
/> />
)} */} )}
TODO
</RouteFocusModal> </RouteFocusModal>
) )
} }
@@ -1,40 +1,25 @@
import { zodResolver } from "@hookform/resolvers/zod" import { zodResolver } from "@hookform/resolvers/zod"
import { SalesChannel } from "@medusajs/medusa" import { Button, Checkbox, Hint, StatusBadge, Tooltip } from "@medusajs/ui"
import { import {
Button, OnChangeFn,
Checkbox,
Hint,
StatusBadge,
Table,
Tooltip,
clx,
} from "@medusajs/ui"
import {
PaginationState,
RowSelectionState, RowSelectionState,
createColumnHelper, createColumnHelper,
flexRender,
getCoreRowModel,
useReactTable,
} from "@tanstack/react-table" } from "@tanstack/react-table"
import { import { useMemo, useState } from "react"
adminPublishableApiKeysKeys,
useAdminAddPublishableKeySalesChannelsBatch,
useAdminCustomPost,
useAdminSalesChannels,
} from "medusa-react"
import { useEffect, useMemo, useState } from "react"
import { useForm } from "react-hook-form" import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import * as zod from "zod" import * as zod from "zod"
import { OrderBy } from "../../../../components/filtering/order-by"
import { Query } from "../../../../components/filtering/query"
import { LocalizedTablePagination } from "../../../../components/localization/localized-table-pagination"
import { import {
RouteFocusModal, RouteFocusModal,
useRouteModal, useRouteModal,
} from "../../../../components/route-modal" } from "../../../../components/route-modal"
import { useQueryParams } from "../../../../hooks/use-query-params" import { useBatchAddSalesChannelsToApiKey } from "../../../../hooks/api/api-keys"
import { useSalesChannelTableQuery } from "../../../../hooks/table/query/use-sales-channel-table-query"
import { useDataTable } from "../../../../hooks/use-data-table"
import { useSalesChannels } from "../../../../hooks/api/sales-channels"
import { keepPreviousData } from "@tanstack/react-query"
import { DataTable } from "../../../../components/table/data-table"
import { AdminSalesChannelResponse } from "@medusajs/types"
type AddSalesChannelsToApiKeyFormProps = { type AddSalesChannelsToApiKeyFormProps = {
apiKey: string apiKey: string
@@ -63,69 +48,51 @@ export const AddSalesChannelsToApiKeyForm = ({
const { setValue } = form const { setValue } = form
const { mutateAsync, isLoading: isMutating } = useAdminCustomPost( const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
`/api-keys/${apiKey}/sales-channels/batch/add`,
[adminPublishableApiKeysKeys.detailSalesChannels(apiKey)]
)
const [{ pageIndex, pageSize }, setPagination] = useState<PaginationState>({ // @ts-ignore
pageIndex: 0, const { mutateAsync, isLoading: isMutating } =
useBatchAddSalesChannelsToApiKey(apiKey)
const { raw, searchParams } = useSalesChannelTableQuery({
pageSize: PAGE_SIZE, pageSize: PAGE_SIZE,
}) })
const pagination = useMemo(
() => ({
pageIndex,
pageSize,
}),
[pageIndex, pageSize]
)
const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
useEffect(() => {
setValue(
"sales_channel_ids",
Object.keys(rowSelection).filter((k) => rowSelection[k]),
{
shouldDirty: true,
shouldTouch: true,
}
)
}, [rowSelection, setValue])
const params = useQueryParams(["q", "order"])
const { sales_channels, count } = useAdminSalesChannels(
{
limit: PAGE_SIZE,
offset: PAGE_SIZE * pageIndex,
...params,
},
{
keepPreviousData: true,
}
)
const columns = useColumns() const columns = useColumns()
const table = useReactTable({ const { sales_channels, count, isLoading } = useSalesChannels(
{ ...searchParams },
{
placeholderData: keepPreviousData,
}
)
const updater: OnChangeFn<RowSelectionState> = (fn) => {
const state = typeof fn === "function" ? fn(rowSelection) : fn
const ids = Object.keys(state)
setValue("sales_channel_ids", ids, {
shouldDirty: true,
shouldTouch: true,
})
setRowSelection(state)
}
const { table } = useDataTable({
data: sales_channels ?? [], data: sales_channels ?? [],
columns, columns,
pageCount: Math.ceil((count ?? 0) / PAGE_SIZE), count,
state: { enablePagination: true,
pagination,
rowSelection,
},
onPaginationChange: setPagination,
onRowSelectionChange: setRowSelection,
getCoreRowModel: getCoreRowModel(),
manualPagination: true,
getRowId: (row) => row.id,
enableRowSelection: (row) => { enableRowSelection: (row) => {
return !preSelected.includes(row.id) return !preSelected.includes(row.original.id!)
}, },
meta: { getRowId: (row) => row.id,
preSelected, pageSize: PAGE_SIZE,
rowSelection: {
state: rowSelection,
updater,
}, },
}) })
@@ -165,85 +132,26 @@ export const AddSalesChannelsToApiKeyForm = ({
</Button> </Button>
</div> </div>
</RouteFocusModal.Header> </RouteFocusModal.Header>
<RouteFocusModal.Body className="flex h-full w-full flex-col items-center divide-y overflow-y-auto"> <RouteFocusModal.Body>
<div className="flex w-full items-center justify-between px-6 py-4"> <DataTable
<div></div> table={table}
<div className="flex items-center gap-x-2"> columns={columns}
<Query /> count={count}
<OrderBy keys={["title"]} />
</div>
</div>
<div className="w-full flex-1 overflow-y-auto">
<Table>
<Table.Header className="border-t-0">
{table.getHeaderGroups().map((headerGroup) => {
return (
<Table.Row
key={headerGroup.id}
className="[&_th:first-of-type]:w-[1%] [&_th:first-of-type]:whitespace-nowrap"
>
{headerGroup.headers.map((header) => {
return (
<Table.HeaderCell key={header.id}>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
</Table.HeaderCell>
)
})}
</Table.Row>
)
})}
</Table.Header>
<Table.Body className="border-b-0">
{table.getRowModel().rows.map((row) => (
<Table.Row
key={row.id}
className={clx(
"transition-fg",
{
"bg-ui-bg-highlight hover:bg-ui-bg-highlight-hover":
row.getIsSelected(),
},
{
"bg-ui-bg-disabled hover:bg-ui-bg-disabled":
preSelected.includes(row.original.id),
}
)}
>
{row.getVisibleCells().map((cell) => (
<Table.Cell key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</Table.Cell>
))}
</Table.Row>
))}
</Table.Body>
</Table>
</div>
<div className="w-full border-t">
<LocalizedTablePagination
canNextPage={table.getCanNextPage()}
canPreviousPage={table.getCanPreviousPage()}
nextPage={table.nextPage}
previousPage={table.previousPage}
count={count ?? 0}
pageIndex={pageIndex}
pageCount={table.getPageCount()}
pageSize={PAGE_SIZE} pageSize={PAGE_SIZE}
pagination
search
isLoading={isLoading}
queryObject={raw}
orderBy={["name", "created_at", "updated_at"]}
/> />
</div>
</RouteFocusModal.Body> </RouteFocusModal.Body>
</form> </form>
</RouteFocusModal.Form> </RouteFocusModal.Form>
) )
} }
const columnHelper = createColumnHelper<SalesChannel>() const columnHelper =
createColumnHelper<AdminSalesChannelResponse["sales_channel"]>()
const useColumns = () => { const useColumns = () => {
const { t } = useTranslation() const { t } = useTranslation()
@@ -266,28 +174,24 @@ const useColumns = () => {
/> />
) )
}, },
cell: ({ row, table }) => { cell: ({ row }) => {
const { preSelected } = table.options.meta as { const isPreSelected = !row.getCanSelect()
preSelected: string[] const isSelected = row.getIsSelected() || isPreSelected
}
const isAdded = preSelected.includes(row.original.id)
const isSelected = row.getIsSelected() || isAdded
const Component = ( const Component = (
<Checkbox <Checkbox
checked={isSelected} checked={isSelected}
disabled={isAdded} disabled={isPreSelected}
onCheckedChange={(value) => row.toggleSelected(!!value)} onCheckedChange={(value) => row.toggleSelected(!!value)}
onClick={(e) => {
e.stopPropagation()
}}
/> />
) )
if (isAdded) { if (isPreSelected) {
return ( return (
<Tooltip <Tooltip content={t("store.currencyAlreadyAdded")} side="right">
content={t("salesChannels.productAlreadyAdded")}
side="right"
>
{Component} {Component}
</Tooltip> </Tooltip>
) )
@@ -3,6 +3,7 @@ import { JsonViewSection } from "../../../components/common/json-view-section"
import { useApiKey } from "../../../hooks/api/api-keys" import { useApiKey } from "../../../hooks/api/api-keys"
import { ApiKeyGeneralSection } from "./components/api-key-general-section" import { ApiKeyGeneralSection } from "./components/api-key-general-section"
import { apiKeyLoader } from "./loader" import { apiKeyLoader } from "./loader"
import { ApiKeySalesChannelSection } from "./components/api-key-sales-channel-section"
export const ApiKeyManagementDetail = () => { export const ApiKeyManagementDetail = () => {
const initialData = useLoaderData() as Awaited< const initialData = useLoaderData() as Awaited<
@@ -25,7 +26,7 @@ export const ApiKeyManagementDetail = () => {
return ( return (
<div className="flex flex-col gap-y-2"> <div className="flex flex-col gap-y-2">
<ApiKeyGeneralSection apiKey={api_key} /> <ApiKeyGeneralSection apiKey={api_key} />
{/* <ApiKeySalesChannelSection apiKey={apiKey} /> */} <ApiKeySalesChannelSection apiKey={api_key} />
<JsonViewSection data={api_key} /> <JsonViewSection data={api_key} />
<Outlet /> <Outlet />
</div> </div>
@@ -1,366 +1,254 @@
// Api Key Sales Channel Endpoint is not part of v2 import { PencilSquare, Trash } from "@medusajs/icons"
import {
Button,
Checkbox,
Container,
Heading,
StatusBadge,
usePrompt,
} from "@medusajs/ui"
import { RowSelectionState, createColumnHelper } from "@tanstack/react-table"
import {
adminPublishableApiKeysKeys,
useAdminCustomPost,
useAdminRemovePublishableKeySalesChannelsBatch,
} from "medusa-react"
import { useMemo, useState } from "react"
import { useTranslation } from "react-i18next"
import { Link, useNavigate } from "react-router-dom"
import { ActionMenu } from "../../../../../components/common/action-menu"
import { useSalesChannels } from "../../../../../hooks/api/sales-channels"
import { useSalesChannelTableQuery } from "../../../../../hooks/table/query/use-sales-channel-table-query"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { DataTable } from "../../../../../components/table/data-table"
import { keepPreviousData } from "@tanstack/react-query"
import { AdminApiKeyResponse, AdminSalesChannelResponse } from "@medusajs/types"
import { useBatchRemoveSalesChannelsFromApiKey } from "../../../../../hooks/api/api-keys"
// import { PencilSquare, Trash } from "@medusajs/icons" type ApiKeySalesChannelSectionProps = {
// import { SalesChannel } from "@medusajs/medusa" apiKey: AdminApiKeyResponse["api_key"]
// import { }
// Button,
// Checkbox,
// CommandBar,
// Container,
// Heading,
// StatusBadge,
// Table,
// clx,
// usePrompt,
// } from "@medusajs/ui"
// import {
// PaginationState,
// RowSelectionState,
// createColumnHelper,
// flexRender,
// getCoreRowModel,
// useReactTable,
// } from "@tanstack/react-table"
// import {
// adminPublishableApiKeysKeys,
// useAdminCustomPost,
// useAdminRemovePublishableKeySalesChannelsBatch,
// } from "medusa-react"
// import { useMemo, useState } from "react"
// import { useTranslation } from "react-i18next"
// import { Link, useNavigate } from "react-router-dom"
// import { ActionMenu } from "../../../../../components/common/action-menu"
// import {
// NoRecords,
// NoResults,
// } from "../../../../../components/common/empty-table-content"
// import { Query } from "../../../../../components/filtering/query"
// import { LocalizedTablePagination } from "../../../../../components/localization/localized-table-pagination"
// import { useQueryParams } from "../../../../../hooks/use-query-params"
// import { ExtendedApiKeyDTO } from "../../../../../types/api-responses"
// import { SalesChannelDTO } from "@medusajs/types"
// type ApiKeySalesChannelSectionProps = { const PAGE_SIZE = 10
// apiKey: ExtendedApiKeyDTO
// }
// const PAGE_SIZE = 10 export const ApiKeySalesChannelSection = ({
apiKey,
}: ApiKeySalesChannelSectionProps) => {
const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
const { t } = useTranslation()
const prompt = usePrompt()
// export const ApiKeySalesChannelSection = ({ const { raw, searchParams } = useSalesChannelTableQuery({
// apiKey, pageSize: PAGE_SIZE,
// }: ApiKeySalesChannelSectionProps) => { })
// const { t } = useTranslation()
// const navigate = useNavigate()
// const prompt = usePrompt()
// const [{ pageIndex, pageSize }, setPagination] = useState<PaginationState>({ const { sales_channels, count, isLoading } = useSalesChannels(
// pageIndex: 0, { ...searchParams, publishable_key_id: apiKey.id },
// pageSize: PAGE_SIZE, {
// }) placeholderData: keepPreviousData,
}
)
// const pagination = useMemo( const columns = useColumns({ apiKey: apiKey.id })
// () => ({ // const filters = useProductTableFilters(["sales_channel_id"])
// pageIndex,
// pageSize,
// }),
// [pageIndex, pageSize]
// )
// const [rowSelection, setRowSelection] = useState<RowSelectionState>({}) const { table } = useDataTable({
data: sales_channels ?? [],
columns,
count,
enablePagination: true,
enableRowSelection: true,
getRowId: (row) => row.id,
pageSize: PAGE_SIZE,
rowSelection: {
state: rowSelection,
updater: setRowSelection,
},
})
// const params = useQueryParams(["q"]) const { mutateAsync } = useBatchRemoveSalesChannelsFromApiKey(apiKey.id)
// const query = { const handleRemove = async () => {
// ...params, const keys = Object.keys(rowSelection)
// fields: "id,*sales_channels",
// }
// const salesChannels = apiKey?.sales_channels const res = await prompt({
// const count = salesChannels?.length || 0 title: t("general.areYouSure"),
description: t("apiKeyManagement.removeSalesChannelsWarning", {
count: keys.length,
}),
confirmText: t("actions.continue"),
cancelText: t("actions.cancel"),
})
// const columns = useColumns() if (!res) {
return
}
// const table = useReactTable({ await mutateAsync(
// data: salesChannels ?? [], {
// columns, sales_channel_ids: keys,
// pageCount: Math.ceil(count / PAGE_SIZE), },
// state: { {
// pagination, onSuccess: () => {
// rowSelection, setRowSelection({})
// }, },
// getRowId: (row) => row.id, }
// onPaginationChange: setPagination, )
// onRowSelectionChange: setRowSelection, }
// getCoreRowModel: getCoreRowModel(),
// manualPagination: true,
// meta: {
// apiKey: apiKey.id,
// },
// })
// const { mutateAsync } = useAdminCustomPost( return (
// `/api-keys/${apiKey.id}/sales-channels/batch/remove`, <Container className="divide-y p-0">
// [adminPublishableApiKeysKeys.detailSalesChannels(apiKey.id)] <div className="flex items-center justify-between px-6 py-4">
// ) <Heading level="h2">{t("salesChannels.domain")}</Heading>
<Button variant="secondary" size="small" asChild>
<Link to="add-sales-channels">{t("general.add")}</Link>
</Button>
</div>
<DataTable
table={table}
columns={columns}
count={count}
pageSize={PAGE_SIZE}
pagination
search
isLoading={isLoading}
queryObject={raw}
orderBy={["name", "created_at", "updated_at"]}
commands={[
{
action: handleRemove,
label: t("actions.remove"),
shortcut: "r",
},
]}
/>
</Container>
)
}
// const handleRemove = async () => { const SalesChannelActions = ({
// const keys = Object.keys(rowSelection).filter((k) => rowSelection[k]) salesChannel,
apiKey,
}: {
salesChannel: AdminSalesChannelResponse["sales_channel"]
apiKey: string
}) => {
const { t } = useTranslation()
const prompt = usePrompt()
// const res = await prompt({ const { mutateAsync } = useBatchRemoveSalesChannelsFromApiKey(apiKey)
// title: t("general.areYouSure"),
// description: t("apiKeyManagement.removeSalesChannelsWarning", {
// count: keys.length,
// }),
// confirmText: t("actions.continue"),
// cancelText: t("actions.cancel"),
// })
// if (!res) { const handleDelete = async () => {
// return const res = await prompt({
// } title: t("general.areYouSure"),
description: t("apiKeyManagement.removeSalesChannelWarning", {
name: salesChannel.name,
}),
confirmText: t("actions.delete"),
cancelText: t("actions.cancel"),
})
// await mutateAsync( if (!res) {
// { return
// sales_channel_ids: keys, }
// },
// {
// onSuccess: () => {
// setRowSelection({})
// },
// }
// )
// }
// const noRecords = !salesChannels?.length && !params.q await mutateAsync({
sales_channel_ids: [salesChannel.id],
})
}
// return ( return (
// <Container className="divide-y p-0"> <ActionMenu
// <div className="flex items-center justify-between px-6 py-4"> groups={[
// <Heading level="h2">{t("salesChannels.domain")}</Heading> {
// <Button variant="secondary" size="small" asChild> actions: [
// <Link to="add-sales-channels">{t("general.add")}</Link> {
// </Button> icon: <PencilSquare />,
// </div> label: t("actions.edit"),
// {!noRecords && ( to: `/settings/sales-channels/${salesChannel.id}/edit`,
// <div className="flex items-center justify-between px-6 py-4"> },
// <div></div> ],
// <div className="flex items-center gap-x-2"> },
// <Query /> {
// </div> actions: [
// </div> {
// )} icon: <Trash />,
// {noRecords ? ( label: t("actions.delete"),
// <NoRecords /> onClick: handleDelete,
// ) : ( },
// <div> ],
// {salesChannels?.length !== 0 ? ( },
// <Table> ]}
// <Table.Header className="border-t-0"> />
// {table.getHeaderGroups().map((headerGroup) => { )
// return ( }
// <Table.Row
// key={headerGroup.id}
// className="[&_th:first-of-type]:w-[1%] [&_th:first-of-type]:whitespace-nowrap [&_th:last-of-type]:w-[1%] [&_th:last-of-type]:whitespace-nowrap [&_th]:w-1/3"
// >
// {headerGroup.headers.map((header) => {
// return (
// <Table.HeaderCell key={header.id}>
// {flexRender(
// header.column.columnDef.header,
// header.getContext()
// )}
// </Table.HeaderCell>
// )
// })}
// </Table.Row>
// )
// })}
// </Table.Header>
// <Table.Body className="border-b-0">
// {table.getRowModel().rows.map((row) => (
// <Table.Row
// key={row.id}
// className={clx(
// "transition-fg cursor-pointer [&_td:last-of-type]:w-[1%] [&_td:last-of-type]:whitespace-nowrap",
// {
// "bg-ui-bg-highlight hover:bg-ui-bg-highlight-hover":
// row.getIsSelected(),
// }
// )}
// onClick={() =>
// navigate(`/settings/sales-channels/${row.original.id}`)
// }
// >
// {row.getVisibleCells().map((cell) => (
// <Table.Cell key={cell.id}>
// {flexRender(
// cell.column.columnDef.cell,
// cell.getContext()
// )}
// </Table.Cell>
// ))}
// </Table.Row>
// ))}
// </Table.Body>
// </Table>
// ) : (
// <NoResults />
// )}
// <LocalizedTablePagination
// canNextPage={table.getCanNextPage()}
// canPreviousPage={table.getCanPreviousPage()}
// nextPage={table.nextPage}
// previousPage={table.previousPage}
// count={count ?? 0}
// pageIndex={pageIndex}
// pageCount={table.getPageCount()}
// pageSize={PAGE_SIZE}
// />
// <CommandBar open={!!Object.keys(rowSelection).length}>
// <CommandBar.Bar>
// <CommandBar.Value>
// {t("general.countSelected", {
// count: Object.keys(rowSelection).length,
// })}
// </CommandBar.Value>
// <CommandBar.Seperator />
// <CommandBar.Command
// action={handleRemove}
// shortcut="r"
// label={t("actions.remove")}
// />
// </CommandBar.Bar>
// </CommandBar>
// </div>
// )}
// </Container>
// )
// }
// const SalesChannelActions = ({ const columnHelper =
// salesChannel, createColumnHelper<AdminSalesChannelResponse["sales_channel"]>()
// apiKey,
// }: {
// salesChannel: SalesChannelDTO
// apiKey: string
// }) => {
// const { t } = useTranslation()
// const prompt = usePrompt()
// const { mutateAsync } = useAdminRemovePublishableKeySalesChannelsBatch(apiKey) const useColumns = ({ apiKey }: { apiKey: string }) => {
const { t } = useTranslation()
// const handleDelete = async () => { return useMemo(
// const res = await prompt({ () => [
// title: t("general.areYouSure"), columnHelper.display({
// description: t("apiKeyManagement.removeSalesChannelWarning"), id: "select",
// confirmText: t("actions.delete"), header: ({ table }) => {
// cancelText: t("actions.cancel"), return (
// }) <Checkbox
checked={
// if (!res) { table.getIsSomePageRowsSelected()
// return ? "indeterminate"
// } : table.getIsAllPageRowsSelected()
}
// await mutateAsync({ onCheckedChange={(value) =>
// sales_channel_ids: [{ id: salesChannel.id }], table.toggleAllPageRowsSelected(!!value)
// }) }
// } />
)
// return ( },
// <ActionMenu cell: ({ row }) => {
// groups={[ return (
// { <Checkbox
// actions: [ checked={row.getIsSelected()}
// { onCheckedChange={(value) => row.toggleSelected(!!value)}
// icon: <PencilSquare />, onClick={(e) => {
// label: t("actions.edit"), e.stopPropagation()
// to: `/settings/sales-channels/${salesChannel.id}/edit`, }}
// }, />
// ], )
// }, },
// { }),
// actions: [ columnHelper.accessor("name", {
// { header: t("fields.name"),
// icon: <Trash />, cell: ({ getValue }) => getValue(),
// label: t("actions.delete"), }),
// onClick: handleDelete, columnHelper.accessor("description", {
// }, header: t("fields.description"),
// ], cell: ({ getValue }) => getValue(),
// }, }),
// ]} columnHelper.accessor("is_disabled", {
// /> header: t("fields.status"),
// ) cell: ({ getValue }) => {
// } const value = getValue()
return (
// const columnHelper = createColumnHelper<SalesChannel>() <div>
<StatusBadge color={value ? "grey" : "green"}>
// const useColumns = () => { {value ? t("general.disabled") : t("general.enabled")}
// const { t } = useTranslation() </StatusBadge>
</div>
// return useMemo( )
// () => [ },
// columnHelper.display({ }),
// id: "select", columnHelper.display({
// header: ({ table }) => { id: "actions",
// return ( cell: ({ row, table }) => {
// <Checkbox return (
// checked={ <SalesChannelActions salesChannel={row.original} apiKey={apiKey} />
// table.getIsSomePageRowsSelected() )
// ? "indeterminate" },
// : table.getIsAllPageRowsSelected() }),
// } ],
// onCheckedChange={(value) => [t]
// table.toggleAllPageRowsSelected(!!value) )
// } }
// />
// )
// },
// cell: ({ row }) => {
// return (
// <Checkbox
// checked={row.getIsSelected()}
// onCheckedChange={(value) => row.toggleSelected(!!value)}
// onClick={(e) => {
// e.stopPropagation()
// }}
// />
// )
// },
// }),
// columnHelper.accessor("name", {
// header: t("fields.name"),
// cell: ({ getValue }) => getValue(),
// }),
// columnHelper.accessor("description", {
// header: t("fields.description"),
// cell: ({ getValue }) => getValue(),
// }),
// columnHelper.accessor("is_disabled", {
// header: t("fields.status"),
// cell: ({ getValue }) => {
// const value = getValue()
// return (
// <div>
// <StatusBadge color={value ? "grey" : "green"}>
// {value ? t("general.disabled") : t("general.enabled")}
// </StatusBadge>
// </div>
// )
// },
// }),
// columnHelper.display({
// id: "actions",
// cell: ({ row, table }) => {
// const { apiKey } = table.options.meta as {
// apiKey: string
// }
// return (
// <SalesChannelActions salesChannel={row.original} apiKey={apiKey} />
// )
// },
// }),
// ],
// [t]
// )
// }
@@ -1,9 +1,9 @@
import { LoaderFunctionArgs } from "react-router-dom" import { LoaderFunctionArgs } from "react-router-dom"
import { AdminApiKeyResponse } from "@medusajs/types"
import { apiKeysQueryKeys } from "../../../hooks/api/api-keys" import { apiKeysQueryKeys } from "../../../hooks/api/api-keys"
import { client } from "../../../lib/client" import { client } from "../../../lib/client"
import { queryClient } from "../../../lib/medusa" import { queryClient } from "../../../lib/medusa"
import { ApiKeyRes } from "../../../types/api-responses"
const apiKeyDetailQuery = (id: string) => ({ const apiKeyDetailQuery = (id: string) => ({
queryKey: apiKeysQueryKeys.detail(id), queryKey: apiKeysQueryKeys.detail(id),
@@ -15,7 +15,7 @@ export const apiKeyLoader = async ({ params }: LoaderFunctionArgs) => {
const query = apiKeyDetailQuery(id!) const query = apiKeyDetailQuery(id!)
return ( return (
queryClient.getQueryData<ApiKeyRes>(query.queryKey) ?? queryClient.getQueryData<AdminApiKeyResponse>(query.queryKey) ??
(await queryClient.fetchQuery(query)) (await queryClient.fetchQuery(query))
) )
} }
@@ -9,13 +9,16 @@ import {
} from "medusa-react" } from "medusa-react"
import { useMemo } from "react" import { useMemo } from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { AdminApiKeyResponse } from "@medusajs/types"
import { ApiKeyDTO } from "@medusajs/types"
import { ActionMenu } from "../../../../../components/common/action-menu" import { ActionMenu } from "../../../../../components/common/action-menu"
import { DateCell } from "../../../../../components/table/table-cells/common/date-cell" import { DateCell } from "../../../../../components/table/table-cells/common/date-cell"
import { StatusCell } from "../../../../../components/table/table-cells/common/status-cell" import { StatusCell } from "../../../../../components/table/table-cells/common/status-cell"
import {
useDeleteApiKey,
useRevokeApiKey,
} from "../../../../../hooks/api/api-keys"
const columnHelper = createColumnHelper<ApiKeyDTO>() const columnHelper = createColumnHelper<AdminApiKeyResponse["api_key"]>()
export const useApiKeyManagementTableColumns = () => { export const useApiKeyManagementTableColumns = () => {
const { t } = useTranslation() const { t } = useTranslation()
@@ -83,21 +86,9 @@ export const useApiKeyManagementTableColumns = () => {
) )
} }
const ApiKeyActions = ({ apiKey }: { apiKey: PublishableApiKey }) => { export const ApiKeyActions = ({ apiKey }: { apiKey: PublishableApiKey }) => {
const { mutateAsync: revokeAsync } = useAdminCustomPost( const { mutateAsync: revokeAsync } = useRevokeApiKey(apiKey.id)
`/api-keys/${apiKey.id}/revoke`, const { mutateAsync: deleteAsync } = useDeleteApiKey(apiKey.id)
[
adminPublishableApiKeysKeys.lists(),
adminPublishableApiKeysKeys.detail(apiKey.id),
]
)
const { mutateAsync: deleteAsync } = useAdminCustomDelete(
`/api-keys/${apiKey.id}`,
[
adminPublishableApiKeysKeys.lists(),
adminPublishableApiKeysKeys.detail(apiKey.id),
]
)
const { t } = useTranslation() const { t } = useTranslation()
const prompt = usePrompt() const prompt = usePrompt()
@@ -133,7 +124,7 @@ const ApiKeyActions = ({ apiKey }: { apiKey: PublishableApiKey }) => {
return return
} }
await revokeAsync({}) await revokeAsync(undefined)
} }
return ( return (
@@ -1,9 +1,9 @@
import { adminProductKeys } from "medusa-react" import { adminProductKeys } from "medusa-react"
import { LoaderFunctionArgs } from "react-router-dom" import { LoaderFunctionArgs } from "react-router-dom"
import { AdminSalesChannelResponse } from "@medusajs/types"
import { client } from "../../../lib/client" import { client } from "../../../lib/client"
import { queryClient } from "../../../lib/medusa" import { queryClient } from "../../../lib/medusa"
import { SalesChannelRes } from "../../../types/api-responses"
const salesChannelDetailQuery = (id: string) => ({ const salesChannelDetailQuery = (id: string) => ({
queryKey: adminProductKeys.detail(id), queryKey: adminProductKeys.detail(id),
@@ -15,7 +15,7 @@ export const salesChannelLoader = async ({ params }: LoaderFunctionArgs) => {
const query = salesChannelDetailQuery(id!) const query = salesChannelDetailQuery(id!)
return ( return (
queryClient.getQueryData<SalesChannelRes>(query.queryKey) ?? queryClient.getQueryData<AdminSalesChannelResponse>(query.queryKey) ??
(await queryClient.fetchQuery(query)) (await queryClient.fetchQuery(query))
) )
} }
@@ -0,0 +1,32 @@
import { ApiKeyType } from "../../../api-key"
import { PaginatedResponse } from "../../../common"
/**
* @experimental
*/
interface ApiKeyResponse {
id: string
token: string
redacted: string
title: string
type: ApiKeyType
last_used_at: Date | null
created_by: string
created_at: Date
revoked_by: string | null
revoked_at: Date | null
}
/**
* @experimental
*/
export interface AdminApiKeyResponse {
api_key: ApiKeyResponse
}
/**
* @experimental
*/
export interface AdminApiKeyListResponse extends PaginatedResponse {
api_keys: ApiKeyResponse[]
}
@@ -0,0 +1 @@
export * from "./api-key"
+1
View File
@@ -0,0 +1 @@
export * from "./admin"
+1
View File
@@ -0,0 +1 @@
export * from "./paginated-response"
@@ -0,0 +1,5 @@
export interface PaginatedResponse {
limit: number
offset: number
count: number
}
+3 -1
View File
@@ -1,2 +1,4 @@
export * from "./stock-locations" export * from "./api-key"
export * from "./fulfillment" export * from "./fulfillment"
export * from "./sales-channel"
export * from "./stock-locations"
@@ -0,0 +1 @@
export * from "./sales-channel"
@@ -0,0 +1,26 @@
import { PaginatedResponse } from "../../common"
/**
* @experimental
*/
interface SalesChannelResponse {
id: string
name: string
description: string | null
is_disabled: boolean
metadata: Record<string, unknown> | null
}
/**
* @experimental
*/
export interface AdminSalesChannelListResponse extends PaginatedResponse {
sales_channels: SalesChannelResponse[]
}
/**
* @experimental
*/
export interface AdminSalesChannelResponse {
sales_channel: SalesChannelResponse
}
@@ -0,0 +1 @@
export * from "./admin"