From 1c9a95f22ab8c3f1d1e48c7c889227ce1d9160cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Emir=20=C5=9Een?= Date: Wed, 24 Apr 2024 14:33:37 +0300 Subject: [PATCH] feat(devtools): devtools improvements (#5875) --- .changeset/clean-dryers-grow.md | 7 + .changeset/clean-elephants-matter.md | 7 + .changeset/cyan-wolves-cry.md | 10 ++ .changeset/flat-suns-push.md | 10 ++ .changeset/forty-pianos-beam.md | 7 + .changeset/shiny-colts-nail.md | 7 + .../src/hooks/accessControl/useCan/index.ts | 5 +- .../src/hooks/auditLog/useLogList/index.ts | 2 +- .../core/src/hooks/data/useInfiniteList.ts | 2 +- packages/core/src/hooks/data/useList.ts | 2 +- packages/core/src/hooks/data/useMany.ts | 2 +- packages/core/src/hooks/data/useOne.ts | 2 +- packages/devtools-internal/src/get-trace.ts | 5 +- packages/devtools-internal/src/get-xray.ts | 11 +- packages/devtools-internal/src/listeners.ts | 18 -- .../src/use-query-subscription.tsx | 22 ++- packages/devtools-server/package.json | 4 +- packages/devtools-server/src/index.ts | 12 ++ .../tsconfig.declarations.json | 3 +- packages/devtools-server/tsconfig.json | 3 + packages/devtools-shared/src/event-types.ts | 6 + packages/devtools-ui/package.json | 2 +- .../src/components/invalidate-button.tsx | 63 +++++++ .../src/components/json-viewer.tsx | 125 +++++++++++--- .../src/components/monitor-details.tsx | 19 ++- packages/devtools-ui/src/style.css | 154 ++++++++++++++++++ .../src/utils/get-resource-value.ts | 12 +- 27 files changed, 456 insertions(+), 66 deletions(-) create mode 100644 .changeset/clean-dryers-grow.md create mode 100644 .changeset/clean-elephants-matter.md create mode 100644 .changeset/cyan-wolves-cry.md create mode 100644 .changeset/flat-suns-push.md create mode 100644 .changeset/forty-pianos-beam.md create mode 100644 .changeset/shiny-colts-nail.md create mode 100644 packages/devtools-ui/src/components/invalidate-button.tsx diff --git a/.changeset/clean-dryers-grow.md b/.changeset/clean-dryers-grow.md new file mode 100644 index 000000000000..0d4d79b28313 --- /dev/null +++ b/.changeset/clean-dryers-grow.md @@ -0,0 +1,7 @@ +--- +"@refinedev/core": patch +--- + +refactor: add resource name to devtools xray calls + +Added the resource name to the devtools xray calls to allow resource names to be displayed in the devtools even with custom query keys. diff --git a/.changeset/clean-elephants-matter.md b/.changeset/clean-elephants-matter.md new file mode 100644 index 000000000000..12623d212d40 --- /dev/null +++ b/.changeset/clean-elephants-matter.md @@ -0,0 +1,7 @@ +--- +"@refinedev/devtools-server": patch +--- + +chore: move `@refinedev/devtools-ui` dependency + +Moved `@refinedev/devtools-ui` dependency to `devDependencies` since only the `vite` output is used in the server. diff --git a/.changeset/cyan-wolves-cry.md b/.changeset/cyan-wolves-cry.md new file mode 100644 index 000000000000..cdf4944af8cb --- /dev/null +++ b/.changeset/cyan-wolves-cry.md @@ -0,0 +1,10 @@ +--- +"@refinedev/devtools-internal": patch +"@refinedev/devtools-server": patch +"@refinedev/devtools-shared": patch +"@refinedev/devtools-ui": patch +--- + +feat: update resource name accessing logic + +Updated resource name displaying logic to use `resourceName` from activity records to make sure `resource` is correctly displayed with custom query keys. diff --git a/.changeset/flat-suns-push.md b/.changeset/flat-suns-push.md new file mode 100644 index 000000000000..96e9356b4d1f --- /dev/null +++ b/.changeset/flat-suns-push.md @@ -0,0 +1,10 @@ +--- +"@refinedev/devtools-internal": patch +"@refinedev/devtools-server": patch +"@refinedev/devtools-shared": patch +"@refinedev/devtools-ui": patch +--- + +feat: add invalidate query button + +Added `Invalidate Query` button to settled queries in the devtools panel to allow users to manually invalidate queries for debugging purposes. diff --git a/.changeset/forty-pianos-beam.md b/.changeset/forty-pianos-beam.md new file mode 100644 index 000000000000..ba749e3d46bf --- /dev/null +++ b/.changeset/forty-pianos-beam.md @@ -0,0 +1,7 @@ +--- +"@refinedev/devtools-ui": patch +--- + +refactor: replace `react-json-view` with `react-json-view-lite` + +Replaced outdated `react-json-view` package with `react-json-view-lite` for both performance and dependency resolution reasons. diff --git a/.changeset/shiny-colts-nail.md b/.changeset/shiny-colts-nail.md new file mode 100644 index 000000000000..fd1aeb85a415 --- /dev/null +++ b/.changeset/shiny-colts-nail.md @@ -0,0 +1,7 @@ +--- +"@refinedev/core": patch +--- + +fix: exclude internal button hook calls from devtools trace + +Removed internal button hook calls from devtools trace to avoid crowding the trace with unnecessary information. diff --git a/packages/core/src/hooks/accessControl/useCan/index.ts b/packages/core/src/hooks/accessControl/useCan/index.ts index e5e2273e198f..65301b0079af 100644 --- a/packages/core/src/hooks/accessControl/useCan/index.ts +++ b/packages/core/src/hooks/accessControl/useCan/index.ts @@ -75,7 +75,10 @@ export const useCan = ({ ...mergedQueryOptions, meta: { ...mergedQueryOptions?.meta, - ...getXRay("useCan", preferLegacyKeys), + ...getXRay("useCan", preferLegacyKeys, resource, [ + "useButtonCanAccess", + "useNavigationButton", + ]), }, retry: false, }); diff --git a/packages/core/src/hooks/auditLog/useLogList/index.ts b/packages/core/src/hooks/auditLog/useLogList/index.ts index d4492ae7adae..aa70d1b59a37 100644 --- a/packages/core/src/hooks/auditLog/useLogList/index.ts +++ b/packages/core/src/hooks/auditLog/useLogList/index.ts @@ -66,7 +66,7 @@ export const useLogList = < retry: false, meta: { ...queryOptions?.meta, - ...getXRay("useLogList", preferLegacyKeys), + ...getXRay("useLogList", preferLegacyKeys, resource), }, }); diff --git a/packages/core/src/hooks/data/useInfiniteList.ts b/packages/core/src/hooks/data/useInfiniteList.ts index 6ee3eaca5a42..e08832893493 100644 --- a/packages/core/src/hooks/data/useInfiniteList.ts +++ b/packages/core/src/hooks/data/useInfiniteList.ts @@ -315,7 +315,7 @@ export const useInfiniteList = < }, meta: { ...queryOptions?.meta, - ...getXRay("useInfiniteList", preferLegacyKeys), + ...getXRay("useInfiniteList", preferLegacyKeys, resource?.name), }, }); diff --git a/packages/core/src/hooks/data/useList.ts b/packages/core/src/hooks/data/useList.ts index 64543105a4ed..2e9c569e71cd 100644 --- a/packages/core/src/hooks/data/useList.ts +++ b/packages/core/src/hooks/data/useList.ts @@ -321,7 +321,7 @@ export const useList = < }, meta: { ...queryOptions?.meta, - ...getXRay("useList", preferLegacyKeys), + ...getXRay("useList", preferLegacyKeys, resource?.name), }, }); diff --git a/packages/core/src/hooks/data/useMany.ts b/packages/core/src/hooks/data/useMany.ts index 8f61f7ce010c..8014ddfd7a61 100644 --- a/packages/core/src/hooks/data/useMany.ts +++ b/packages/core/src/hooks/data/useMany.ts @@ -226,7 +226,7 @@ export const useMany = < }, meta: { ...queryOptions?.meta, - ...getXRay("useMany", preferLegacyKeys), + ...getXRay("useMany", preferLegacyKeys, resource?.name), }, }); diff --git a/packages/core/src/hooks/data/useOne.ts b/packages/core/src/hooks/data/useOne.ts index 39cd3c1d2766..bc62f061526c 100644 --- a/packages/core/src/hooks/data/useOne.ts +++ b/packages/core/src/hooks/data/useOne.ts @@ -239,7 +239,7 @@ export const useOne = < }, meta: { ...queryOptions?.meta, - ...getXRay("useOne", preferLegacyKeys), + ...getXRay("useOne", preferLegacyKeys, resource?.name), }, }); diff --git a/packages/devtools-internal/src/get-trace.ts b/packages/devtools-internal/src/get-trace.ts index 90dff6833575..69c237c7d476 100644 --- a/packages/devtools-internal/src/get-trace.ts +++ b/packages/devtools-internal/src/get-trace.ts @@ -4,7 +4,7 @@ import { isRefineStack } from "./is-refine-stack"; import { getPackageNameFromFilename } from "./get-package-name-from-filename"; import { TraceType } from "@refinedev/devtools-shared"; -export function getTrace() { +export function getTrace(excludeFromTrace?: string[]) { if (__DEV_CONDITION__ !== "development") { return []; } @@ -24,7 +24,8 @@ export function getTrace() { packageName: getPackageNameFromFilename(frame.fileName), }) as TraceType, ) - .filter((trace) => trace.function); + .filter((trace) => trace.function) + .filter((trace) => !excludeFromTrace?.includes(trace.function ?? "")); return traces.slice(1); } catch (error) { return []; diff --git a/packages/devtools-internal/src/get-xray.ts b/packages/devtools-internal/src/get-xray.ts index 7b659526e575..0794d31c1acf 100644 --- a/packages/devtools-internal/src/get-xray.ts +++ b/packages/devtools-internal/src/get-xray.ts @@ -7,9 +7,15 @@ export type XRayResponse = { trace: TraceType[]; resourcePath: string | null; legacyKey: boolean; + resourceName?: string; }; -export function getXRay(hookName: string, legacyKey: boolean): XRayResponse { +export function getXRay( + hookName: string, + legacyKey: boolean, + resourceName?: string, + excludeFromTrace?: string[], +): XRayResponse { if (__DEV_CONDITION__ !== "development") { return { hookName: "", @@ -18,7 +24,7 @@ export function getXRay(hookName: string, legacyKey: boolean): XRayResponse { legacyKey: false, }; } - const trace = getTrace().slice(1); + const trace = getTrace(excludeFromTrace).slice(1); const resourcePath = getResourcePath(hookName as RefineHook, legacyKey); @@ -27,5 +33,6 @@ export function getXRay(hookName: string, legacyKey: boolean): XRayResponse { trace, resourcePath, legacyKey, + resourceName, }; } diff --git a/packages/devtools-internal/src/listeners.ts b/packages/devtools-internal/src/listeners.ts index 8a2583e3bace..4a928aaea3f2 100644 --- a/packages/devtools-internal/src/listeners.ts +++ b/packages/devtools-internal/src/listeners.ts @@ -25,16 +25,6 @@ export const createMutationListener = }); resolve(); }); - - // console.table({ - // type: "mutation", - // key: mutation?.options.mutationKey, - // id: mutation?.mutationId, - // status: mutation?.state.status, - // trace: mutation?.meta?.trace, - // state: mutation?.state, - // variables: mutation?.state?.variables, - // }); }; export const createQueryListener = (ws: WebSocket) => (query: Query) => { @@ -53,12 +43,4 @@ export const createQueryListener = (ws: WebSocket) => (query: Query) => { }); resolve(); }); - - // console.table({ - // type: "query", - // key: query.queryKey, - // status: query.state.status, - // trace: query.meta?.trace, - // state: query.state, - // }); }; diff --git a/packages/devtools-internal/src/use-query-subscription.tsx b/packages/devtools-internal/src/use-query-subscription.tsx index 365e1fa4200d..f0634ff948b5 100644 --- a/packages/devtools-internal/src/use-query-subscription.tsx +++ b/packages/devtools-internal/src/use-query-subscription.tsx @@ -1,4 +1,8 @@ -import { DevToolsContext } from "@refinedev/devtools-shared"; +import { + DevToolsContext, + DevtoolsEvent, + receive, +} from "@refinedev/devtools-shared"; import { QueryClient } from "@tanstack/react-query"; import React, { useContext } from "react"; import { createQueryListener, createMutationListener } from "./listeners"; @@ -50,5 +54,21 @@ export const useQuerySubscription = }; }, [ws, queryClient]); + React.useEffect(() => { + if (!ws) return () => 0; + + const cb = receive( + ws, + DevtoolsEvent.DEVTOOLS_INVALIDATE_QUERY_ACTION, + ({ queryKey }) => { + if (queryKey) { + queryClient.invalidateQueries(queryKey); + } + }, + ); + + return cb; + }, [ws, queryClient]); + return {}; }; diff --git a/packages/devtools-server/package.json b/packages/devtools-server/package.json index 45273d6eac45..29160996a68b 100644 --- a/packages/devtools-server/package.json +++ b/packages/devtools-server/package.json @@ -38,7 +38,7 @@ "build": "npm run build:client && tsup", "build:client": "NODE_ENV=production tsc && vite build --config src/client/vite.config.ts", "dev": "npm run dev:client & tsup --watch", - "dev:client": "vite build --watch --force --config src/client/vite.config.ts", + "dev:client": "vite build --watch --config src/client/vite.config.ts", "prepare": "npm run build", "publint": "publint --strict=true --level=suggestion", "start:server": "node dist/cli.cjs", @@ -48,7 +48,6 @@ "dependencies": { "@ory/client": "^1.5.2", "@refinedev/devtools-shared": "1.1.5", - "@refinedev/devtools-ui": "1.1.20", "body-parser": "^1.20.2", "boxen": "^5.1.2", "chalk": "^4.1.2", @@ -73,6 +72,7 @@ }, "devDependencies": { "@esbuild-plugins/node-resolve": "^0.1.4", + "@refinedev/devtools-ui": "1.1.20", "@testing-library/jest-dom": "^5.16.4", "@types/dedent": "^0.7.0", "@types/fs-extra": "^9.0.13", diff --git a/packages/devtools-server/src/index.ts b/packages/devtools-server/src/index.ts index 7c5a3deb60d3..e769fba97a18 100644 --- a/packages/devtools-server/src/index.ts +++ b/packages/devtools-server/src/index.ts @@ -83,6 +83,18 @@ export const server = async ({ projectPath = process.cwd() }: Options = {}) => { }, ); + receive( + client as any, + DevtoolsEvent.DEVTOOLS_INVALIDATE_QUERY, + ({ queryKey }) => { + ws.clients.forEach((c) => { + send(c as any, DevtoolsEvent.DEVTOOLS_INVALIDATE_QUERY_ACTION, { + queryKey, + }); + }); + }, + ); + receive(client as any, DevtoolsEvent.DEVTOOLS_LOGIN_SUCCESS, () => { ws.clients.forEach((c) => { send(c as any, DevtoolsEvent.DEVTOOLS_RELOAD_AFTER_LOGIN, {}); diff --git a/packages/devtools-server/tsconfig.declarations.json b/packages/devtools-server/tsconfig.declarations.json index d0f135c6ba6d..929f158768bd 100644 --- a/packages/devtools-server/tsconfig.declarations.json +++ b/packages/devtools-server/tsconfig.declarations.json @@ -8,7 +8,8 @@ "**/*.spec.ts", "**/*.test.ts", "**/*.spec.tsx", - "**/*.test.tsx" + "**/*.test.tsx", + "src/client/**/*" ], "compilerOptions": { "outDir": "dist", diff --git a/packages/devtools-server/tsconfig.json b/packages/devtools-server/tsconfig.json index a9152a516fad..82100d3cc2a7 100644 --- a/packages/devtools-server/tsconfig.json +++ b/packages/devtools-server/tsconfig.json @@ -1,5 +1,8 @@ { "include": ["src", "types"], + "exclude": [ + "src/client/**/*", + ], "extends": "../../tsconfig.build.json", "compilerOptions": { "types": ["node", "jest", "@testing-library/jest-dom"], diff --git a/packages/devtools-shared/src/event-types.ts b/packages/devtools-shared/src/event-types.ts index 2d99df3a0014..e9b74cab5b9c 100644 --- a/packages/devtools-shared/src/event-types.ts +++ b/packages/devtools-shared/src/event-types.ts @@ -21,6 +21,8 @@ export enum DevtoolsEvent { DEVTOOLS_HIGHLIGHT_IN_MONITOR_ACTION = "devtools:highlight-in-monitor-action", DEVTOOLS_LOGIN_SUCCESS = "devtools:login-success", DEVTOOLS_RELOAD_AFTER_LOGIN = "devtools:reload-after-login", + DEVTOOLS_INVALIDATE_QUERY = "devtools:invalidate-query", + DEVTOOLS_INVALIDATE_QUERY_ACTION = "devtools:invalidate-query-action", } type Timestamps = { @@ -39,6 +41,7 @@ type ActivityPayload = variables?: Mutation["state"]["variables"]; hookName: string; resourcePath: string | null; + resourceName?: string; legacyKey: boolean; } | { @@ -50,6 +53,7 @@ type ActivityPayload = state: QueryState; hookName: string; resourcePath: string | null; + resourceName?: string; legacyKey: boolean; }; @@ -68,4 +72,6 @@ export type DevtoolsEventPayloads = { [DevtoolsEvent.DEVTOOLS_HIGHLIGHT_IN_MONITOR_ACTION]: { name: string }; [DevtoolsEvent.DEVTOOLS_LOGIN_SUCCESS]: {}; [DevtoolsEvent.DEVTOOLS_RELOAD_AFTER_LOGIN]: {}; + [DevtoolsEvent.DEVTOOLS_INVALIDATE_QUERY]: { queryKey: QueryKey }; + [DevtoolsEvent.DEVTOOLS_INVALIDATE_QUERY_ACTION]: { queryKey: QueryKey }; }; diff --git a/packages/devtools-ui/package.json b/packages/devtools-ui/package.json index dbe2718d71fc..33322d677fe9 100644 --- a/packages/devtools-ui/package.json +++ b/packages/devtools-ui/package.json @@ -55,7 +55,7 @@ "lodash-es": "^4.17.21", "prism-react-renderer": "^1.3.5", "react-gravatar": "^2.6.3", - "react-json-view": "^1.21.3", + "react-json-view-lite": "^1.3.0", "react-router-dom": "^6.8.1", "semver-diff": "^3.1.1" }, diff --git a/packages/devtools-ui/src/components/invalidate-button.tsx b/packages/devtools-ui/src/components/invalidate-button.tsx new file mode 100644 index 000000000000..d906a18b1377 --- /dev/null +++ b/packages/devtools-ui/src/components/invalidate-button.tsx @@ -0,0 +1,63 @@ +import React from "react"; +import type { Activity } from "../interfaces/activity"; +import { UpdateIcon } from "./icons/update"; +import clsx from "clsx"; +import { + DevToolsContext, + DevtoolsEvent, + send, +} from "@refinedev/devtools-shared"; + +export const InvalidateButton = ({ activity }: { activity: Activity }) => { + const { ws } = React.useContext(DevToolsContext); + + if (activity.type !== "query") return null; + + if (activity.status === "success" || activity.status === "error") { + const isFetching = activity.state.fetchStatus === "fetching"; + + return ( + <> + + + ); + } + + return null; +}; diff --git a/packages/devtools-ui/src/components/json-viewer.tsx b/packages/devtools-ui/src/components/json-viewer.tsx index 7ceb4d2f0630..66cb84786dd3 100644 --- a/packages/devtools-ui/src/components/json-viewer.tsx +++ b/packages/devtools-ui/src/components/json-viewer.tsx @@ -1,6 +1,6 @@ import clsx from "clsx"; import React from "react"; -import ReactJson from "react-json-view"; +import { JsonView, darkStyles } from "react-json-view-lite"; import { MaximizeIcon } from "./icons/maximize"; import { Modal } from "./modal"; @@ -9,24 +9,61 @@ export const JsonViewer = ({ data, label }: { data: any; label: string }) => { return (
- l < 2} style={{ - backgroundColor: "#303450", - padding: "8px", - borderRadius: "8px", - overflow: "auto", - maxHeight: "160px", + ...darkStyles, + container: clsx( + "re-bg-[#303450]", + "re-font-mono re-text-xs", + "[&>*:first-child]:!re-px-[12px]", + "re-py-1", + "re-overflow-auto", + "re-max-h-[160px]", + "re-rounded-lg", + ), + basicChildStyle: clsx( + "re-py-[3px]", + "re-pr-[5px]", + "re-pl-[20px]", + "re-leading-5", + ), + collapsedContent: clsx( + "re-text-amber-500", + "after:re-content-['...']", + "after:re-pr-[5px]", + ), + label: clsx("re-mr-[8px]", "re-text-neutral-200"), + stringValue: clsx("re-text-amber-500"), + numberValue: clsx("re-text-amber-500"), + undefinedValue: clsx("re-text-neutral-500"), + nullValue: clsx("re-text-neutral-500"), + expandIcon: clsx( + "after:re-transition-transform", + "after:re-duration-200", + "after:re-ease-in-out", + "after:re-content-['⏵']", + "after:re-mr-[8px]", + "after:re-inline-block", + ), + collapseIcon: clsx( + "after:re-transition-transform", + "after:re-duration-200", + "after:re-ease-in-out", + "after:re-content-['⏵']", + "after:re-mr-[8px]", + "after:re-inline-block", + "after:re-rotate-90", + ), }} - collapsed={2} - name={false} />
diff --git a/packages/devtools-ui/src/style.css b/packages/devtools-ui/src/style.css index 94ef557d4bfe..628647ab1085 100644 --- a/packages/devtools-ui/src/style.css +++ b/packages/devtools-ui/src/style.css @@ -79,3 +79,157 @@ body, *::-webkit-scrollbar { display: none; } + +/* json view */ + +/* base styles */ + +._GzYRV { + line-height: 1.2; + white-space: pre-wrap; + white-space: -moz-pre-wrap; + white-space: -pre-wrap; + white-space: -o-pre-wrap; + word-wrap: break-word; + } + + ._3eOF8 { + margin-right: 5px; + font-weight: bold; + } + + ._1MFti { + cursor: pointer; + } + + ._f10Tu { + font-size: 1.2em; + margin-right: 5px; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + } + + ._1UmXx::after { + content: '\25B8'; + } + + ._1LId0::after { + content: '\25BE'; + } + + ._1pNG9 { + margin-right: 5px; + } + + ._1pNG9::after { + content: '...'; + font-size: 0.8em; + } + + ._2IvMF { + background: #eee; + } + + ._2bkNM { + margin: 0 10px; + padding: 0; + } + + /* default light style */ + ._1MGIk { + font-weight: 600; + margin-right: 5px; + color: #000000; + } + + ._3uHL6 { + color: #000000; + } + + ._2T6PJ { + color: #df113a; + } + + ._1Gho6 { + color: #df113a; + } + + ._vGjyY { + color: rgb(42, 63, 60); + } + + ._1bQdo { + color: #0b75f5; + } + + ._3zQKs { + color: rgb(70, 144, 56); + } + + ._1xvuR { + color: #43413d; + } + + ._oLqym { + color: #000000; + } + + ._2AXVT { + color: #000000; + } + + ._2KJWg { + color: #000000; + } + + /* default dark style */ + ._11RoI { + background: rgb(0, 43, 54); + } + + ._17H2C { + color: rgb(253, 246, 227); + } + + ._3QHg2 { + color: rgb(253, 246, 227); + } + + ._3fDAz { + color: rgb(253, 246, 227); + } + + ._2bSDX { + /* font-weight: bolder; */ + margin-right: 5px; + color: rgb(253, 246, 227); + } + + ._gsbQL { + color: rgb(253, 246, 227); + } + + ._LaAZe { + color: rgb(129, 181, 172); + } + + ._GTKgm { + color: rgb(129, 181, 172); + } + + ._Chy1W { + color: rgb(203, 75, 22); + } + + ._2bveF { + color: rgb(211, 54, 130); + } + + ._2vRm- { + color: rgb(174, 129, 255); + } + + ._1prJR { + color: rgb(38, 139, 210); + } \ No newline at end of file diff --git a/packages/devtools-ui/src/utils/get-resource-value.ts b/packages/devtools-ui/src/utils/get-resource-value.ts index abbe207bd022..d3f1c51813b9 100644 --- a/packages/devtools-ui/src/utils/get-resource-value.ts +++ b/packages/devtools-ui/src/utils/get-resource-value.ts @@ -5,13 +5,17 @@ export const getResourceValue = (activity: Activity): string => { const { resourcePath } = activity; let resource: string | null = null; - if (resourcePath) { - resource = get(activity, resourcePath) ?? "-"; + if (activity?.resourceName) { + resource = activity.resourceName; } else { - resource = "-"; + if (resourcePath) { + resource = get(activity, resourcePath) ?? "-"; + } else { + resource = "-"; + } } - if (resource) { + if (resource && typeof resource === "string") { resource = resource.charAt(0).toUpperCase() + resource.slice(1); }