Skip to content

Commit 337dda1

Browse files
authored
feat(webapp): name of the page in tab titles (#4517)
Adds a shared `pageMeta()` helper and 74 route declarations, so a title reads `run_abc | Runs | Trigger.dev` — the specific thing first, then the page. Org pages also carry the organization: `Team | Acme | Trigger.dev`. Inside a project no scope is added, because the dashboard switches projects in every tab at once. Page names are unchanged; what's new is that a page says which one it is at all. Three wording changes on purpose: the queue page now names the queue, the model page names the model, and entity pages carry their section.
1 parent 66940c0 commit 337dda1

78 files changed

Lines changed: 501 additions & 310 deletions

File tree

  • .server-changes
  • apps/webapp/app
    • routes
      • _app.orgs.$organizationSlug.invite
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam._index
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.agents.$agentParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.alerts.new
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.alerts
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.apikeys
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.batches.$batchParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.batches
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.branches
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.bulk-actions.$bulkActionParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.bulk-actions
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.dashboards.$dashboardKey
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.dashboards._index
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.dashboards.custom.$dashboardId
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.dev-branches
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables.new
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.errors.$fingerprint
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.errors._index
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.limits
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.logs
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.models.$modelId
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.models._index
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.models.compare
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.playground.$agentParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.playground
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.queues_.$queueParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.queues
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.regions
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs._index
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.schedules.$scheduleParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.schedules.edit.$scheduleParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.schedules.new
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.sessions.$sessionParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.sessions._index
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings.integrations
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.tasks.dashboard
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.tasks.scheduled.$taskParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.tasks.standard.$taskParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens.$waitpointParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens
      • _app.orgs.$organizationSlug.settings._index
      • _app.orgs.$organizationSlug.settings.billing-limits
      • _app.orgs.$organizationSlug.settings.billing
      • _app.orgs.$organizationSlug.settings.private-connections._index
      • _app.orgs.$organizationSlug.settings.private-connections.new
      • _app.orgs.$organizationSlug.settings.roles
      • _app.orgs.$organizationSlug.settings.sso
      • _app.orgs.$organizationSlug.settings.team
      • _app.orgs.$organizationSlug.settings.usage
      • _app.orgs.$organizationSlug_.projects.new
      • _app.orgs.$organizationSlug_.select-plan
      • _app.orgs.new
      • _app.timezones
      • account._index
      • account.authorization-code.$authorizationCode
      • account.security
      • account.tokens
    • utils

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.server-changes/page-tab-titles.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
area: webapp
3+
type: improvement
4+
---
5+
6+
Browser tabs now name the page you're on, and the run, task or queue when you're looking at one, instead of all reading "Trigger.dev".

apps/webapp/app/root.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import {
3030
} from "~/utils/themePreference";
3131
import { cachedFlag } from "~/v3/featureFlags.server";
3232
import { getTimezonePreference } from "./services/preferences/uiPreferences.server";
33-
import { appEnvTitleTag } from "./utils";
33+
import { appTitle } from "./utils/pageTitle";
3434

3535
// Derived here (not inside StaleAssetRecovery) so the shared component takes
3636
// the flag as a prop. NODE_ENV is statically replaced in browser bundles, and
@@ -51,7 +51,8 @@ export const headers = () => ({
5151
export const meta: MetaFunction = ({ data }) => {
5252
const typedData = data as UseDataFunctionReturn<typeof loader>;
5353
return [
54-
{ title: typedData?.appEnv ? `Trigger.dev${appEnvTitleTag(typedData.appEnv)}` : "Trigger.dev" },
54+
// Pages declare their own title with `pageMeta`; this is the fallback.
55+
{ title: appTitle(typedData?.appEnv) },
5556
{
5657
name: "viewport",
5758
content: "width=1024, initial-scale=1",

apps/webapp/app/routes/_app.orgs.$organizationSlug.invite/route.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ import { dashboardAction, dashboardLoader } from "~/services/routeBuilders/dashb
3838
import { acceptInvitePath, organizationTeamPath, v3BillingPath } from "~/utils/pathBuilder";
3939
import { isAtOrBelow } from "~/utils/inviteRoleLadder";
4040
import { PurchaseSeatsModal } from "../_app.orgs.$organizationSlug.settings.team/route";
41+
import { pageMeta } from "~/utils/pageTitle";
42+
43+
export const meta = pageMeta("Invite team members");
4144

4245
const Params = z.object({
4346
organizationSlug: z.string(),

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam._index/route.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { BookOpenIcon, ExclamationTriangleIcon } from "@heroicons/react/20/solid";
2-
import { json, type MetaFunction } from "@remix-run/node";
2+
import { json } from "@remix-run/node";
33
import { useFetcher, useRevalidator } from "@remix-run/react";
44
import { type ActionFunctionArgs, type LoaderFunctionArgs } from "@remix-run/server-runtime";
55
import type { TaskRunStatus } from "@trigger.dev/database";
@@ -100,10 +100,9 @@ import {
100100
v3TasksStreamingPath,
101101
v3TestTaskPath,
102102
} from "~/utils/pathBuilder";
103+
import { pageMeta } from "~/utils/pageTitle";
103104

104-
export const meta: MetaFunction = () => {
105-
return [{ title: `Tasks | Trigger.dev` }];
106-
};
105+
export const meta = pageMeta("Tasks");
107106

108107
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
109108
const userId = await requireUserId(request);

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.agents.$agentParam/route.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { BookOpenIcon } from "@heroicons/react/24/solid";
2-
import { type MetaFunction } from "@remix-run/react";
32
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
43
import { Suspense, useMemo, useState } from "react";
54
import { TypedAwait, typeddefer, useTypedLoaderData } from "remix-typedjson";
@@ -50,11 +49,12 @@ import {
5049
v3PlaygroundAgentPath,
5150
} from "~/utils/pathBuilder";
5251
import { parseFiniteInt } from "~/utils/searchParams";
52+
import { pageMeta } from "~/utils/pageTitle";
5353

54-
export const meta: MetaFunction<typeof loader> = ({ data }) => {
55-
const slug = (data as { agent?: AgentDetail | null } | undefined)?.agent?.slug;
56-
return [{ title: slug ? `${slug} | Agents | Trigger.dev` : "Agent | Trigger.dev" }];
57-
};
54+
export const meta = pageMeta<typeof loader>(({ data, params }) => [
55+
data?.agent?.slug ?? params.agentParam ?? "Agent",
56+
"Agents",
57+
]);
5858

5959
const AgentParamSchema = EnvironmentParamSchema.extend({
6060
agentParam: z.string(),

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.alerts.new/route.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ import {
4646
assertSafeWebhookUrl,
4747
UnsafeWebhookUrlError,
4848
} from "~/v3/services/alerts/safeWebhookUrl.server";
49+
import { pageMeta } from "~/utils/pageTitle";
50+
51+
export const meta = pageMeta("New alert");
4952

5053
const FormSchema = z
5154
.object({

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.alerts/route.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
PlusIcon,
1111
TrashIcon,
1212
} from "@heroicons/react/20/solid";
13-
import { Form, type MetaFunction, Outlet, useActionData, useNavigation } from "@remix-run/react";
13+
import { Form, Outlet, useActionData, useNavigation } from "@remix-run/react";
1414
import { type ActionFunctionArgs, type LoaderFunctionArgs, json } from "@remix-run/server-runtime";
1515
import { SlackIcon } from "@trigger.dev/companyicons";
1616
import type { ProjectAlertChannelType, ProjectAlertType } from "@trigger.dev/database";
@@ -66,14 +66,9 @@ import {
6666
v3ProjectAlertsPath,
6767
} from "~/utils/pathBuilder";
6868
import { alertsWorker } from "~/v3/alertsWorker.server";
69+
import { pageMeta } from "~/utils/pageTitle";
6970

70-
export const meta: MetaFunction = () => {
71-
return [
72-
{
73-
title: `Alerts | Trigger.dev`,
74-
},
75-
];
76-
};
71+
export const meta = pageMeta("Alerts");
7772

7873
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
7974
const userId = await requireUserId(request);

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.apikeys/route.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { BookOpenIcon } from "@heroicons/react/20/solid";
2-
import { type MetaFunction } from "@remix-run/react";
32
import { typedjson, useTypedLoaderData } from "remix-typedjson";
43
import { AdminDebugTooltip } from "~/components/admin/debugTooltip";
54
import { CopyableText } from "~/components/primitives/CopyableText";
@@ -38,14 +37,9 @@ import { ApiKeysPresenter } from "~/presenters/v3/ApiKeysPresenter.server";
3837
import { dashboardLoader } from "~/services/routeBuilders/dashboardBuilder";
3938
import { cn } from "~/utils/cn";
4039
import { docsPath, EnvironmentParamSchema } from "~/utils/pathBuilder";
40+
import { pageMeta } from "~/utils/pageTitle";
4141

42-
export const meta: MetaFunction = () => {
43-
return [
44-
{
45-
title: `API keys | Trigger.dev`,
46-
},
47-
];
48-
};
42+
export const meta = pageMeta("API keys");
4943

5044
export const loader = dashboardLoader(
5145
{

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.batches.$batchParam/route.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import { requireUserId } from "~/services/session.server";
2424
import { cn } from "~/utils/cn";
2525
import { formatNumber } from "~/utils/numberFormatter";
2626
import { EnvironmentParamSchema, v3BatchesPath, v3BatchRunsPath } from "~/utils/pathBuilder";
27+
import { pageMeta } from "~/utils/pageTitle";
28+
29+
export const meta = pageMeta(({ params }) => [params.batchParam ?? "Batch", "Batches"]);
2730

2831
const BatchParamSchema = EnvironmentParamSchema.extend({
2932
batchParam: z.string(),

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.batches/route.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ExclamationCircleIcon } from "@heroicons/react/20/solid";
22
import { BookOpenIcon } from "@heroicons/react/24/solid";
3-
import { type MetaFunction, Outlet, useLocation, useNavigation, useParams } from "@remix-run/react";
3+
import { Outlet, useLocation, useNavigation, useParams } from "@remix-run/react";
44
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
55
import { formatDuration } from "@trigger.dev/core/v3/utils/durations";
66
import { typedjson, useTypedLoaderData } from "remix-typedjson";
@@ -62,14 +62,9 @@ import {
6262
v3BatchRunsPath,
6363
} from "~/utils/pathBuilder";
6464
import { throwNotFound } from "~/utils/httpErrors";
65+
import { pageMeta } from "~/utils/pageTitle";
6566

66-
export const meta: MetaFunction = () => {
67-
return [
68-
{
69-
title: `Batches | Trigger.dev`,
70-
},
71-
];
72-
};
67+
export const meta = pageMeta("Batches");
7368

7469
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
7570
const userId = await requireUserId(request);

0 commit comments

Comments
 (0)