feat: add tracking code on project settings
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { formatDateTime, formatTime } from '@/utils/date';
|
import { DropdownMenuSeparator } from '@radix-ui/react-dropdown-menu';
|
||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
import type { ColumnDef } from '@tanstack/react-table';
|
import type { ColumnDef } from '@tanstack/react-table';
|
||||||
import { isToday } from 'date-fns';
|
import { toast } from 'sonner';
|
||||||
|
|
||||||
import { ColumnCreatedAt } from '@/components/column-created-at';
|
import { ColumnCreatedAt } from '@/components/column-created-at';
|
||||||
import CopyInput from '@/components/forms/copy-input';
|
import CopyInput from '@/components/forms/copy-input';
|
||||||
import { createActionColumn } from '@/components/ui/data-table/data-table-helpers';
|
import { createActionColumn } from '@/components/ui/data-table/data-table-helpers';
|
||||||
@@ -10,9 +10,6 @@ import { handleError, useTRPC } from '@/integrations/trpc/react';
|
|||||||
import { pushModal, showConfirm } from '@/modals';
|
import { pushModal, showConfirm } from '@/modals';
|
||||||
import type { RouterOutputs } from '@/trpc/client';
|
import type { RouterOutputs } from '@/trpc/client';
|
||||||
import { clipboard } from '@/utils/clipboard';
|
import { clipboard } from '@/utils/clipboard';
|
||||||
import { DropdownMenuSeparator } from '@radix-ui/react-dropdown-menu';
|
|
||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
||||||
import { toast } from 'sonner';
|
|
||||||
|
|
||||||
export function useColumns() {
|
export function useColumns() {
|
||||||
const columns: ColumnDef<RouterOutputs['client']['list'][number]>[] = [
|
const columns: ColumnDef<RouterOutputs['client']['list'][number]>[] = [
|
||||||
@@ -51,7 +48,7 @@ export function useColumns() {
|
|||||||
queryClient.invalidateQueries(trpc.client.list.pathFilter());
|
queryClient.invalidateQueries(trpc.client.list.pathFilter());
|
||||||
},
|
},
|
||||||
onError: handleError,
|
onError: handleError,
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -67,7 +64,6 @@ export function useColumns() {
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
variant="destructive"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
showConfirm({
|
showConfirm({
|
||||||
title: 'Revoke client',
|
title: 'Revoke client',
|
||||||
@@ -79,6 +75,7 @@ export function useColumns() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
variant="destructive"
|
||||||
>
|
>
|
||||||
Revoke
|
Revoke
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
import type { UseQueryResult } from '@tanstack/react-query';
|
import type { UseQueryResult } from '@tanstack/react-query';
|
||||||
|
import { PlusIcon } from 'lucide-react';
|
||||||
|
import { useColumns } from './columns';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { DataTable } from '@/components/ui/data-table/data-table';
|
import { DataTable } from '@/components/ui/data-table/data-table';
|
||||||
import { DataTableToolbar } from '@/components/ui/data-table/data-table-toolbar';
|
import { DataTableToolbar } from '@/components/ui/data-table/data-table-toolbar';
|
||||||
import { useTable } from '@/components/ui/data-table/use-table';
|
import { useTable } from '@/components/ui/data-table/use-table';
|
||||||
import { pushModal } from '@/modals';
|
import { pushModal } from '@/modals';
|
||||||
import type { RouterOutputs } from '@/trpc/client';
|
import type { RouterOutputs } from '@/trpc/client';
|
||||||
import { PlusIcon } from 'lucide-react';
|
|
||||||
import { useColumns } from './columns';
|
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
query: UseQueryResult<RouterOutputs['client']['list'], unknown>;
|
query: UseQueryResult<RouterOutputs['client']['list'], unknown>;
|
||||||
};
|
}
|
||||||
|
|
||||||
export const ClientsTable = ({ query }: Props) => {
|
export const ClientsTable = ({ query }: Props) => {
|
||||||
const columns = useColumns();
|
const columns = useColumns();
|
||||||
@@ -30,13 +29,13 @@ export const ClientsTable = ({ query }: Props) => {
|
|||||||
<DataTableToolbar table={table}>
|
<DataTableToolbar table={table}>
|
||||||
<Button
|
<Button
|
||||||
icon={PlusIcon}
|
icon={PlusIcon}
|
||||||
responsive
|
|
||||||
onClick={() => pushModal('AddClient')}
|
onClick={() => pushModal('AddClient')}
|
||||||
|
responsive
|
||||||
>
|
>
|
||||||
Create client
|
Create client
|
||||||
</Button>
|
</Button>
|
||||||
</DataTableToolbar>
|
</DataTableToolbar>
|
||||||
<DataTable table={table} loading={isLoading} />
|
<DataTable loading={isLoading} table={table} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const ConnectWeb = ({ client }: Props) => {
|
|||||||
</script>
|
</script>
|
||||||
<script src="https://openpanel.dev/op1.js" defer async></script>`;
|
<script src="https://openpanel.dev/op1.js" defer async></script>`;
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="col gap-4">
|
||||||
<div className="col gap-2">
|
<div className="col gap-2">
|
||||||
<div className="row items-center justify-between gap-4">
|
<div className="row items-center justify-between gap-4">
|
||||||
<div className="flex items-center gap-2 font-bold text-xl capitalize">
|
<div className="flex items-center gap-2 font-bold text-xl capitalize">
|
||||||
@@ -44,7 +44,7 @@ const ConnectWeb = ({ client }: Props) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Syntax className="border" code={code} />
|
<Syntax className="border" code={code} copyable={false} />
|
||||||
</div>
|
</div>
|
||||||
<div className="col gap-4">
|
<div className="col gap-4">
|
||||||
<p className="text-center text-muted-foreground text-sm">
|
<p className="text-center text-muted-foreground text-sm">
|
||||||
@@ -80,7 +80,7 @@ const ConnectWeb = ({ client }: Props) => {
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ import { Route as AppOrganizationIdProjectIdProfilesTabsIndexRouteImport } from
|
|||||||
import { Route as AppOrganizationIdProjectIdNotificationsTabsIndexRouteImport } from './routes/_app.$organizationId.$projectId.notifications._tabs.index'
|
import { Route as AppOrganizationIdProjectIdNotificationsTabsIndexRouteImport } from './routes/_app.$organizationId.$projectId.notifications._tabs.index'
|
||||||
import { Route as AppOrganizationIdProjectIdEventsTabsIndexRouteImport } from './routes/_app.$organizationId.$projectId.events._tabs.index'
|
import { Route as AppOrganizationIdProjectIdEventsTabsIndexRouteImport } from './routes/_app.$organizationId.$projectId.events._tabs.index'
|
||||||
import { Route as AppOrganizationIdProjectIdSettingsTabsWidgetsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.widgets'
|
import { Route as AppOrganizationIdProjectIdSettingsTabsWidgetsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.widgets'
|
||||||
|
import { Route as AppOrganizationIdProjectIdSettingsTabsTrackingRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.tracking'
|
||||||
import { Route as AppOrganizationIdProjectIdSettingsTabsImportsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.imports'
|
import { Route as AppOrganizationIdProjectIdSettingsTabsImportsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.imports'
|
||||||
import { Route as AppOrganizationIdProjectIdSettingsTabsEventsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.events'
|
import { Route as AppOrganizationIdProjectIdSettingsTabsEventsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.events'
|
||||||
import { Route as AppOrganizationIdProjectIdSettingsTabsDetailsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.details'
|
import { Route as AppOrganizationIdProjectIdSettingsTabsDetailsRouteImport } from './routes/_app.$organizationId.$projectId.settings._tabs.details'
|
||||||
@@ -475,6 +476,12 @@ const AppOrganizationIdProjectIdSettingsTabsWidgetsRoute =
|
|||||||
path: '/widgets',
|
path: '/widgets',
|
||||||
getParentRoute: () => AppOrganizationIdProjectIdSettingsTabsRoute,
|
getParentRoute: () => AppOrganizationIdProjectIdSettingsTabsRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
const AppOrganizationIdProjectIdSettingsTabsTrackingRoute =
|
||||||
|
AppOrganizationIdProjectIdSettingsTabsTrackingRouteImport.update({
|
||||||
|
id: '/tracking',
|
||||||
|
path: '/tracking',
|
||||||
|
getParentRoute: () => AppOrganizationIdProjectIdSettingsTabsRoute,
|
||||||
|
} as any)
|
||||||
const AppOrganizationIdProjectIdSettingsTabsImportsRoute =
|
const AppOrganizationIdProjectIdSettingsTabsImportsRoute =
|
||||||
AppOrganizationIdProjectIdSettingsTabsImportsRouteImport.update({
|
AppOrganizationIdProjectIdSettingsTabsImportsRouteImport.update({
|
||||||
id: '/imports',
|
id: '/imports',
|
||||||
@@ -634,6 +641,7 @@ export interface FileRoutesByFullPath {
|
|||||||
'/$organizationId/$projectId/settings/details': typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
'/$organizationId/$projectId/settings/details': typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
||||||
'/$organizationId/$projectId/settings/events': typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
'/$organizationId/$projectId/settings/events': typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
||||||
'/$organizationId/$projectId/settings/imports': typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
'/$organizationId/$projectId/settings/imports': typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
||||||
|
'/$organizationId/$projectId/settings/tracking': typeof AppOrganizationIdProjectIdSettingsTabsTrackingRoute
|
||||||
'/$organizationId/$projectId/settings/widgets': typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRoute
|
'/$organizationId/$projectId/settings/widgets': typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRoute
|
||||||
'/$organizationId/$projectId/events/': typeof AppOrganizationIdProjectIdEventsTabsIndexRoute
|
'/$organizationId/$projectId/events/': typeof AppOrganizationIdProjectIdEventsTabsIndexRoute
|
||||||
'/$organizationId/$projectId/notifications/': typeof AppOrganizationIdProjectIdNotificationsTabsIndexRoute
|
'/$organizationId/$projectId/notifications/': typeof AppOrganizationIdProjectIdNotificationsTabsIndexRoute
|
||||||
@@ -701,6 +709,7 @@ export interface FileRoutesByTo {
|
|||||||
'/$organizationId/$projectId/settings/details': typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
'/$organizationId/$projectId/settings/details': typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
||||||
'/$organizationId/$projectId/settings/events': typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
'/$organizationId/$projectId/settings/events': typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
||||||
'/$organizationId/$projectId/settings/imports': typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
'/$organizationId/$projectId/settings/imports': typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
||||||
|
'/$organizationId/$projectId/settings/tracking': typeof AppOrganizationIdProjectIdSettingsTabsTrackingRoute
|
||||||
'/$organizationId/$projectId/settings/widgets': typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRoute
|
'/$organizationId/$projectId/settings/widgets': typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRoute
|
||||||
'/$organizationId/$projectId/profiles/$profileId/events': typeof AppOrganizationIdProjectIdProfilesProfileIdTabsEventsRoute
|
'/$organizationId/$projectId/profiles/$profileId/events': typeof AppOrganizationIdProjectIdProfilesProfileIdTabsEventsRoute
|
||||||
'/$organizationId/$projectId/profiles/$profileId/sessions': typeof AppOrganizationIdProjectIdProfilesProfileIdTabsSessionsRoute
|
'/$organizationId/$projectId/profiles/$profileId/sessions': typeof AppOrganizationIdProjectIdProfilesProfileIdTabsSessionsRoute
|
||||||
@@ -781,6 +790,7 @@ export interface FileRoutesById {
|
|||||||
'/_app/$organizationId/$projectId/settings/_tabs/details': typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
'/_app/$organizationId/$projectId/settings/_tabs/details': typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
||||||
'/_app/$organizationId/$projectId/settings/_tabs/events': typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
'/_app/$organizationId/$projectId/settings/_tabs/events': typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
||||||
'/_app/$organizationId/$projectId/settings/_tabs/imports': typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
'/_app/$organizationId/$projectId/settings/_tabs/imports': typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
||||||
|
'/_app/$organizationId/$projectId/settings/_tabs/tracking': typeof AppOrganizationIdProjectIdSettingsTabsTrackingRoute
|
||||||
'/_app/$organizationId/$projectId/settings/_tabs/widgets': typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRoute
|
'/_app/$organizationId/$projectId/settings/_tabs/widgets': typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRoute
|
||||||
'/_app/$organizationId/$projectId/events/_tabs/': typeof AppOrganizationIdProjectIdEventsTabsIndexRoute
|
'/_app/$organizationId/$projectId/events/_tabs/': typeof AppOrganizationIdProjectIdEventsTabsIndexRoute
|
||||||
'/_app/$organizationId/$projectId/notifications/_tabs/': typeof AppOrganizationIdProjectIdNotificationsTabsIndexRoute
|
'/_app/$organizationId/$projectId/notifications/_tabs/': typeof AppOrganizationIdProjectIdNotificationsTabsIndexRoute
|
||||||
@@ -855,6 +865,7 @@ export interface FileRouteTypes {
|
|||||||
| '/$organizationId/$projectId/settings/details'
|
| '/$organizationId/$projectId/settings/details'
|
||||||
| '/$organizationId/$projectId/settings/events'
|
| '/$organizationId/$projectId/settings/events'
|
||||||
| '/$organizationId/$projectId/settings/imports'
|
| '/$organizationId/$projectId/settings/imports'
|
||||||
|
| '/$organizationId/$projectId/settings/tracking'
|
||||||
| '/$organizationId/$projectId/settings/widgets'
|
| '/$organizationId/$projectId/settings/widgets'
|
||||||
| '/$organizationId/$projectId/events/'
|
| '/$organizationId/$projectId/events/'
|
||||||
| '/$organizationId/$projectId/notifications/'
|
| '/$organizationId/$projectId/notifications/'
|
||||||
@@ -922,6 +933,7 @@ export interface FileRouteTypes {
|
|||||||
| '/$organizationId/$projectId/settings/details'
|
| '/$organizationId/$projectId/settings/details'
|
||||||
| '/$organizationId/$projectId/settings/events'
|
| '/$organizationId/$projectId/settings/events'
|
||||||
| '/$organizationId/$projectId/settings/imports'
|
| '/$organizationId/$projectId/settings/imports'
|
||||||
|
| '/$organizationId/$projectId/settings/tracking'
|
||||||
| '/$organizationId/$projectId/settings/widgets'
|
| '/$organizationId/$projectId/settings/widgets'
|
||||||
| '/$organizationId/$projectId/profiles/$profileId/events'
|
| '/$organizationId/$projectId/profiles/$profileId/events'
|
||||||
| '/$organizationId/$projectId/profiles/$profileId/sessions'
|
| '/$organizationId/$projectId/profiles/$profileId/sessions'
|
||||||
@@ -1001,6 +1013,7 @@ export interface FileRouteTypes {
|
|||||||
| '/_app/$organizationId/$projectId/settings/_tabs/details'
|
| '/_app/$organizationId/$projectId/settings/_tabs/details'
|
||||||
| '/_app/$organizationId/$projectId/settings/_tabs/events'
|
| '/_app/$organizationId/$projectId/settings/_tabs/events'
|
||||||
| '/_app/$organizationId/$projectId/settings/_tabs/imports'
|
| '/_app/$organizationId/$projectId/settings/_tabs/imports'
|
||||||
|
| '/_app/$organizationId/$projectId/settings/_tabs/tracking'
|
||||||
| '/_app/$organizationId/$projectId/settings/_tabs/widgets'
|
| '/_app/$organizationId/$projectId/settings/_tabs/widgets'
|
||||||
| '/_app/$organizationId/$projectId/events/_tabs/'
|
| '/_app/$organizationId/$projectId/events/_tabs/'
|
||||||
| '/_app/$organizationId/$projectId/notifications/_tabs/'
|
| '/_app/$organizationId/$projectId/notifications/_tabs/'
|
||||||
@@ -1493,6 +1506,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRouteImport
|
preLoaderRoute: typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRouteImport
|
||||||
parentRoute: typeof AppOrganizationIdProjectIdSettingsTabsRoute
|
parentRoute: typeof AppOrganizationIdProjectIdSettingsTabsRoute
|
||||||
}
|
}
|
||||||
|
'/_app/$organizationId/$projectId/settings/_tabs/tracking': {
|
||||||
|
id: '/_app/$organizationId/$projectId/settings/_tabs/tracking'
|
||||||
|
path: '/tracking'
|
||||||
|
fullPath: '/$organizationId/$projectId/settings/tracking'
|
||||||
|
preLoaderRoute: typeof AppOrganizationIdProjectIdSettingsTabsTrackingRouteImport
|
||||||
|
parentRoute: typeof AppOrganizationIdProjectIdSettingsTabsRoute
|
||||||
|
}
|
||||||
'/_app/$organizationId/$projectId/settings/_tabs/imports': {
|
'/_app/$organizationId/$projectId/settings/_tabs/imports': {
|
||||||
id: '/_app/$organizationId/$projectId/settings/_tabs/imports'
|
id: '/_app/$organizationId/$projectId/settings/_tabs/imports'
|
||||||
path: '/imports'
|
path: '/imports'
|
||||||
@@ -1766,6 +1786,7 @@ interface AppOrganizationIdProjectIdSettingsTabsRouteChildren {
|
|||||||
AppOrganizationIdProjectIdSettingsTabsDetailsRoute: typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
AppOrganizationIdProjectIdSettingsTabsDetailsRoute: typeof AppOrganizationIdProjectIdSettingsTabsDetailsRoute
|
||||||
AppOrganizationIdProjectIdSettingsTabsEventsRoute: typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
AppOrganizationIdProjectIdSettingsTabsEventsRoute: typeof AppOrganizationIdProjectIdSettingsTabsEventsRoute
|
||||||
AppOrganizationIdProjectIdSettingsTabsImportsRoute: typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
AppOrganizationIdProjectIdSettingsTabsImportsRoute: typeof AppOrganizationIdProjectIdSettingsTabsImportsRoute
|
||||||
|
AppOrganizationIdProjectIdSettingsTabsTrackingRoute: typeof AppOrganizationIdProjectIdSettingsTabsTrackingRoute
|
||||||
AppOrganizationIdProjectIdSettingsTabsWidgetsRoute: typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRoute
|
AppOrganizationIdProjectIdSettingsTabsWidgetsRoute: typeof AppOrganizationIdProjectIdSettingsTabsWidgetsRoute
|
||||||
AppOrganizationIdProjectIdSettingsTabsIndexRoute: typeof AppOrganizationIdProjectIdSettingsTabsIndexRoute
|
AppOrganizationIdProjectIdSettingsTabsIndexRoute: typeof AppOrganizationIdProjectIdSettingsTabsIndexRoute
|
||||||
}
|
}
|
||||||
@@ -1780,6 +1801,8 @@ const AppOrganizationIdProjectIdSettingsTabsRouteChildren: AppOrganizationIdProj
|
|||||||
AppOrganizationIdProjectIdSettingsTabsEventsRoute,
|
AppOrganizationIdProjectIdSettingsTabsEventsRoute,
|
||||||
AppOrganizationIdProjectIdSettingsTabsImportsRoute:
|
AppOrganizationIdProjectIdSettingsTabsImportsRoute:
|
||||||
AppOrganizationIdProjectIdSettingsTabsImportsRoute,
|
AppOrganizationIdProjectIdSettingsTabsImportsRoute,
|
||||||
|
AppOrganizationIdProjectIdSettingsTabsTrackingRoute:
|
||||||
|
AppOrganizationIdProjectIdSettingsTabsTrackingRoute,
|
||||||
AppOrganizationIdProjectIdSettingsTabsWidgetsRoute:
|
AppOrganizationIdProjectIdSettingsTabsWidgetsRoute:
|
||||||
AppOrganizationIdProjectIdSettingsTabsWidgetsRoute,
|
AppOrganizationIdProjectIdSettingsTabsWidgetsRoute,
|
||||||
AppOrganizationIdProjectIdSettingsTabsIndexRoute:
|
AppOrganizationIdProjectIdSettingsTabsIndexRoute:
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
import type { IServiceClient } from '@openpanel/db';
|
||||||
|
import { frameworks } from '@openpanel/sdk-info';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
import { CopyIcon } from 'lucide-react';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import Syntax from '@/components/syntax';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Combobox } from '@/components/ui/combobox';
|
||||||
|
import { useAppContext } from '@/hooks/use-app-context';
|
||||||
|
import { useAppParams } from '@/hooks/use-app-params';
|
||||||
|
import { useTRPC } from '@/integrations/trpc/react';
|
||||||
|
import { pushModal } from '@/modals';
|
||||||
|
import { clipboard } from '@/utils/clipboard';
|
||||||
|
|
||||||
|
export const Route = createFileRoute(
|
||||||
|
'/_app/$organizationId/$projectId/settings/_tabs/tracking'
|
||||||
|
)({
|
||||||
|
component: Component,
|
||||||
|
});
|
||||||
|
|
||||||
|
function Component() {
|
||||||
|
const { projectId } = useAppParams();
|
||||||
|
const trpc = useTRPC();
|
||||||
|
const query = useQuery(trpc.client.list.queryOptions({ projectId }));
|
||||||
|
return <ConnectWeb clients={query.data ?? []} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
clients: IServiceClient[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const ConnectWeb = ({ clients }: Props) => {
|
||||||
|
const [client, setClient] = useState<IServiceClient | null>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!client && clients && clients.length > 0) {
|
||||||
|
setClient(clients[0]);
|
||||||
|
}
|
||||||
|
}, [clients]);
|
||||||
|
const context = useAppContext();
|
||||||
|
const code = `<script>
|
||||||
|
window.op=window.op||function(){var n=[];return new Proxy(function(){arguments.length&&n.push([].slice.call(arguments))},{get:function(t,r){return"q"===r?n:function(){n.push([r].concat([].slice.call(arguments)))}} ,has:function(t,r){return"q"===r}}) }();
|
||||||
|
window.op('init', {${context.isSelfHosted ? `\n\tapiUrl: '${context.apiUrl}',` : ''}
|
||||||
|
clientId: '${client?.id ?? 'YOUR_CLIENT_ID'}',
|
||||||
|
trackScreenViews: true,
|
||||||
|
trackOutgoingLinks: true,
|
||||||
|
trackAttributes: true,
|
||||||
|
// sessionReplay: {
|
||||||
|
// enabled: true,
|
||||||
|
// },
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<script src="https://openpanel.dev/op1.js" defer async></script>`;
|
||||||
|
return (
|
||||||
|
<div className="col gap-4">
|
||||||
|
<div className="col gap-2">
|
||||||
|
<div className="row items-center justify-between gap-4">
|
||||||
|
<Combobox
|
||||||
|
items={clients.map((c) => ({
|
||||||
|
value: c.id,
|
||||||
|
label: c.name,
|
||||||
|
}))}
|
||||||
|
onChange={(id) =>
|
||||||
|
setClient(clients.find((c) => c.id === id) ?? null)
|
||||||
|
}
|
||||||
|
placeholder="Select client"
|
||||||
|
searchable
|
||||||
|
value={client?.id ?? null}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
icon={CopyIcon}
|
||||||
|
onClick={() => clipboard(code, null)}
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
Copy
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Syntax className="border" code={code} copyable={false} />
|
||||||
|
</div>
|
||||||
|
<div className="col gap-4">
|
||||||
|
<p className="text-center text-muted-foreground text-sm">
|
||||||
|
Or pick a framework below to get started.
|
||||||
|
</p>
|
||||||
|
<div className="grid gap-4 md:grid-cols-2">
|
||||||
|
{frameworks.map((framework) => (
|
||||||
|
<button
|
||||||
|
className="flex items-center gap-4 rounded-md border p-2 text-left"
|
||||||
|
key={framework.name}
|
||||||
|
onClick={() =>
|
||||||
|
pushModal('Instructions', {
|
||||||
|
framework,
|
||||||
|
client,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<div className="h-10 w-10 rounded-md bg-def-200 p-2">
|
||||||
|
<framework.IconComponent className="h-full w-full" />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 font-semibold">{framework.name}</div>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<p className="text-center text-muted-foreground text-sm">
|
||||||
|
Missing a framework?{' '}
|
||||||
|
<a
|
||||||
|
className="text-foreground underline"
|
||||||
|
href="mailto:hello@openpanel.dev"
|
||||||
|
>
|
||||||
|
Let us know!
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
import FullPageLoadingState from '@/components/full-page-loading-state';
|
|
||||||
import { PageHeader } from '@/components/page-header';
|
|
||||||
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
||||||
import { PAGE_TITLES, createProjectTitle } from '@/utils/title';
|
|
||||||
import {
|
import {
|
||||||
Outlet,
|
|
||||||
createFileRoute,
|
createFileRoute,
|
||||||
|
Outlet,
|
||||||
useLocation,
|
useLocation,
|
||||||
useRouter,
|
useRouter,
|
||||||
} from '@tanstack/react-router';
|
} from '@tanstack/react-router';
|
||||||
|
import FullPageLoadingState from '@/components/full-page-loading-state';
|
||||||
|
import { PageHeader } from '@/components/page-header';
|
||||||
|
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
|
import { createProjectTitle, PAGE_TITLES } from '@/utils/title';
|
||||||
|
|
||||||
export const Route = createFileRoute(
|
export const Route = createFileRoute(
|
||||||
'/_app/$organizationId/$projectId/settings/_tabs',
|
'/_app/$organizationId/$projectId/settings/_tabs'
|
||||||
)({
|
)({
|
||||||
component: ProjectDashboard,
|
component: ProjectDashboard,
|
||||||
head: () => {
|
head: () => {
|
||||||
@@ -27,7 +27,7 @@ export const Route = createFileRoute(
|
|||||||
await queryClient.prefetchQuery(
|
await queryClient.prefetchQuery(
|
||||||
trpc.project.getProjectWithClients.queryOptions({
|
trpc.project.getProjectWithClients.queryOptions({
|
||||||
projectId: params.projectId,
|
projectId: params.projectId,
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
pendingComponent: FullPageLoadingState,
|
pendingComponent: FullPageLoadingState,
|
||||||
@@ -42,6 +42,7 @@ function ProjectDashboard() {
|
|||||||
{ id: 'details', label: 'Details' },
|
{ id: 'details', label: 'Details' },
|
||||||
{ id: 'events', label: 'Events' },
|
{ id: 'events', label: 'Events' },
|
||||||
{ id: 'clients', label: 'Clients' },
|
{ id: 'clients', label: 'Clients' },
|
||||||
|
{ id: 'tracking', label: 'Tracking script' },
|
||||||
{ id: 'widgets', label: 'Widgets' },
|
{ id: 'widgets', label: 'Widgets' },
|
||||||
{ id: 'imports', label: 'Imports' },
|
{ id: 'imports', label: 'Imports' },
|
||||||
];
|
];
|
||||||
@@ -56,11 +57,11 @@ function ProjectDashboard() {
|
|||||||
return (
|
return (
|
||||||
<div className="container p-8">
|
<div className="container p-8">
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="Project settings"
|
|
||||||
description="Manage your project settings here"
|
description="Manage your project settings here"
|
||||||
|
title="Project settings"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Tabs value={tab} onValueChange={handleTabChange} className="mt-2 mb-8">
|
<Tabs className="mt-2 mb-8" onValueChange={handleTabChange} value={tab}>
|
||||||
<TabsList>
|
<TabsList>
|
||||||
{settingsTabs.map((tab) => (
|
{settingsTabs.map((tab) => (
|
||||||
<TabsTrigger key={tab.id} value={tab.id}>
|
<TabsTrigger key={tab.id} value={tab.id}>
|
||||||
|
|||||||
Reference in New Issue
Block a user