Skip to content

Commit

Projects no longer depend on each other: the dependsOn relation, its settings page (old links redirect), the overview card, a pull request's Affects panel and preview stacks, reference variables and agents' notes on what a project uses are gone; the table is dropped in a later deploy

syntaqxcommitted Parentc9f5de9Browse files
40 files+41−2680/40 viewed
+2−2
101101 and Message, and memory at two levels (project and workspace) that
102102 agents write and read.
103103 - Projects with deployments on g1t.page: a preview for every pull request,
104− production on merge, dependencies between projects, custom domains.
104+ production on merge, custom domains.
105105 - GitHub Actions workflows from `.g1t/workflows`, secrets and variables,
106106 webhooks and integrations (Sentry, Datadog, Jira, Linear).
107107 - Profiles, workspaces with display names, icons and renameable slugs.
148148 | `services/integrations` | Model providers, alerts, trackers and the GitHub App. | Rust |
149149 | `services/webhooks` | Webhook deliveries. | Rust |
150150 | `services/runner` | Starts sandboxes: for g1t agents, workflow jobs and the merge queue. | TypeScript |
151−| `services/projects` | Projects and the dependencies between them. | TypeScript |
151+| `services/projects` | Projects: what a workspace builds and runs, and where its code lives. | TypeScript |
152152 | `services/deployments` | Builds, previews and production on `g1t.page`. | TypeScript |
153153 | `services/pages` | Serves every app deployed on `g1t.page`, and custom domains. | TypeScript |
154154 | `services/models` | The model proxy at `models.g1t.sh`. | TypeScript |
+10−10
44784478 "kind": "project",
44794479 "id": "ent_9b1d6f0a2c3e4b5d6e7f8a9b",
44804480 "title": "web",
4481− "snippet": "The storefront. Written in TypeScript. Packages: @acme/web. Uses api. Owned by ana.",
4481+ "snippet": "The storefront. Written in TypeScript. Packages: @acme/web. Owned by ana.",
44824482 "project": "web",
44834483 "url": "/acme/web",
44844484 "score": 0.71,
45034503 "kind": "project",
45044504 "key": "web",
45054505 "name": "web",
4506− "summary": "The storefront. Written in TypeScript. Packages: @acme/web. Uses api. Owned by ana.",
4506+ "summary": "The storefront. Written in TypeScript. Packages: @acme/web. Owned by ana.",
45074507 "project": "web",
45084508 "private": true,
45094509 "data": {
45284528 },
45294529 "relations": [
45304530 {
4531− "kind": "depends_on",
4531+ "kind": "exposes",
45324532 "direction": "out",
45334533 "entity": {
45344534 "id": "ent_0a7c3e5b9d1f2a4c6e8b0d2f",
45354535 "workspace": "acme",
4536− "kind": "project",
4537− "key": "api",
4538− "name": "api",
4539− "summary": "The public API. Written in Rust.",
4540− "project": "api",
4536+ "kind": "package",
4537+ "key": "npm:@acme/web",
4538+ "name": "@acme/web",
4539+ "summary": null,
4540+ "project": "web",
45414541 "private": true,
45424542 "data": {},
45434543 "source": "scan",
4544− "ref": "/acme/api",
4545− "updated_at": "2026-10-04T20:57:12.000Z"
4544+ "ref": "/acme/web/blob/main/package.json",
4545+ "updated_at": "2026-10-04T20:58:41.000Z"
45464546 }
45474547 },
45484548 {
+1−2
162162
163163 Every run is also given a **Context** section from the
164164 [context hub](/guides/context-hub/#agents-start-with-context): the
165−project's stack, owners, environments and the projects it uses with their
166−live addresses, the kept memories closest to its task, and recent
165+project's stack, owners and environments, the kept memories closest to its task, and recent
167166 decisions.
168167
169168 Your own agents can use memory too, through the [`memory` tool](/reference/mcp/#memory)
+1−3
5252
5353 | Relation | Example |
5454 | --- | --- |
55−| `depends_on` | `web` depends on `api`; `@acme/web` depends on `@acme/ui` |
55+| `depends_on` | `@acme/web` depends on `@acme/ui` |
5656 | `owned_by` | `web` is owned by `ana` |
5757 | `deploys_to` | the `web` app deploys to `web/production` |
5858 | `documented_by` | `web` is documented by its `README.md` |
227227
228228 - the project's stack, test commands, owners, docs, and its environments
229229 with their addresses;
230−- the projects it uses, with their live addresses and the variables that
231− carry them, and the projects that use it;
232230 - the kept memories closest to the task, beyond the pinned ones every run
233231 already has;
234232 - the latest decisions from merged pull requests.
+1−23
142142 What Deployments cannot run yet, such as long-running servers, is on
143143 [What g1t can't do yet](/about/limitations/#deployments).
144144
145−## Addresses of other projects
146−
147−A project that [depends on another](/guides/projects/#dependencies) with
148−`as: API_URL` gets that project's address as `API_URL`, in its build and in
149−its running app:
150−
151−| Building | `API_URL` is |
152−| --- | --- |
153−| Production | The other project's production. |
154−| A preview of branch `x` | The other project's preview of `x` if it is up, else its production. |
155−
156−A secret or variable of the same name wins over it.
157−
158−### Preview stacks
159−
160−A change to an API is best seen in the apps that call it. On a pull
161−request whose preview is up, **Preview them against this change** (under
162−**Affects**) builds a preview of every project that uses this one, from its
163−own default branch, under the same branch name. Each gets this preview's
164−address through its variable. They come down with their idle days, like
165−any preview.
166−
167145 ## Previews of branches
168146
169147 A preview is built when a pull request is opened, when it is marked ready,
311289 | | Needs |
312290 | --- | --- |
313291 | See its deployments, their build logs, previews and domains | Read |
314−| **Redeploy**, preview a stack, take an app down | Write |
292+| **Redeploy**, take an app down | Write |
315293 | Turn deployments on or off, change their settings | Admin |
316294 | Add, verify and remove custom domains | Admin |
317295
+1−32
6363 | **Active branches** | Branches other than the default, newest first. See [active branches](#active-branches). |
6464 | **Recent changes**, **Latest on main**, **Activity**, **Previews** | What landed, the default branch's latest commits, what happened (pull requests opened, readied and merged, issues opened and closed, checks, reviews, comments, pushes to the default branch and production deploys), and the previews that are up. |
6565 | **About** | Its description, its [links](#links), what it is, and its latest release (its newest tag). People who can change its settings edit the description and links from here. |
66−| **Health**, **Dependencies**, **Clone** | How often checks pass, recent builds and open issues by age; what it uses and what uses it; the clone address. |
66+| **Health**, **Clone** | How often checks pass, recent builds and open issues by age; the clone address. |
6767
6868 ### The checklist
6969
219219 | **General** | The project's name and description, its source, its **root directory**, [what it is](#what-a-project-is), and its [links](#links). A project shows its repository's description, and follows it as it changes, until you give the project one of its own; **Use the repository's description** goes back. |
220220 | **Deployments** | Production, previews, build command, output directory and idle days. See [Deployments](/guides/deployments/#settings). |
221221 | **Domains** | Custom domains for production. See [custom domains](/guides/deployments/#custom-domains). |
222−| **Dependencies** | The projects this one uses, and the ones that use it. See [Dependencies](#dependencies). |
223222 | **Agents** | How g1t's agents pick up work here, and what they read first. |
224223 | **Guardrails** | What agents may reach, run and spend while they work here. See [guardrails](/guides/guardrails/). |
225224 | **Repository** | The repository's name, description, website, [topics](/guides/search/#what-is-indexed) and default branch, and its danger zone: visibility, archive, transfer and delete. See [Managing a repository](/guides/managing-repositories/). |
281280 requests.
282281 - **Several projects on one repository**, each from its own root
283282 directory, with a push building only the projects it touched.
284−
285−
286−## Dependencies
287−
288−A project can depend on others in its workspace: `web` calls `api`'s HTTP
289−API, or consumes `ui-kit`'s package. Declare it under **Settings →
290−Dependencies**, or in a `.g1t/project.yml` in the project's root
291−directory:
292−
293−```yaml
294−dependsOn:
295− - project: api
296− as: API_URL
297− - project: ui-kit
298−```
299−
300−The file is read on every push to the default branch, and its dependencies
301−replace the ones it declared before; those are marked **project.yml** and
302−changed only in the file. A dependency that would make a cycle, or names a
303−project that does not exist, is left out.
304−
305−What g1t does with them:
306−
307−| | |
308−| --- | --- |
309−| **Addresses in builds and apps** | With `as: API_URL`, `web`'s builds and its running app get `API_URL` set to `api`'s address for the same environment: production gets `api`'s production; a preview gets the preview of `api` on the same branch if one is up, else `api`'s production. A secret or variable of the same name on `web` wins. |
310−| **Preview stacks** | On a pull request of `api` whose preview is up, **Preview them against this change** builds a preview of every project that uses `api`, from its default branch, under the same branch name, so each reaches the change through its variable. A reviewer clicks through the whole change. |
311−| **Affects** | A pull request lists the projects that use its project, so reviewers see what else a change can break. |
312−| **Agents** | An agent working on a project is told what it uses and what uses it. If its change alters what those rely on, it keeps it working for them or opens an issue on each saying what to change, and says so in its summary. |
313−| **The overview** | Each project's overview shows what it depends on and what uses it. |
314283
315284 ## From the API
316285
+0−0

Binary or large file; its contents are not shown.

+0−1
55 "": { title: "General", about: "The project's name, where its code lives, and what it is for." },
66 deployments: { title: "Deployments", about: "How the project builds, where it runs, and its previews." },
77 domains: { title: "Domains", about: "Addresses of your own for the production deployment." },
8− dependencies: { title: "Dependencies", about: "What the project relies on and what relies on it." },
98 agents: { title: "Agents", about: "How g1t picks up work here, and what it reads first." },
109 guardrails: { title: "Guardrails", about: "What agents may reach, run and spend while they work here." },
1110 repository: { title: "Repository", about: "Its name, details and default branch, who can see it, and archiving, moving or deleting it." },
+0−4
11171117 <SidebarLink to={`${base}/settings/domains`} icon={<Globe size={15} />}>
11181118 Domains
11191119 </SidebarLink>
1120− <SidebarLink to={`${base}/settings/dependencies`} icon={<Network size={15} />}>
1121− Dependencies
1122− </SidebarLink>
11231120 </div>
11241121 </>
11251122 )}
17041701 branches: "Branches",
17051702 tags: "Tags",
17061703 compare: "Compare",
1707− dependencies: "Dependencies",
17081704 code: "Files",
17091705 secrets: "Secrets and variables",
17101706 settings: "Settings",
+0−1
3737 runners: "manage_integrations",
3838 deployments: "manage_integrations",
3939 domains: "manage_integrations",
40− dependencies: "manage_settings",
4140 // Write and up can see who has access; Admins change it.
4241 access: "push",
4342 // Deploy keys decide who reaches a repository too: Admins only.
+1−1
110110 (
111111 "account active_agents all_ids get list queue pulls_for_repos blame blob branches by_author by_repo contributions catalog check_invite check_limit " +
112112 "check_workspace_deletion check_workspace_rename collaborator_permission compare counts deleted deliveries " +
113− "dependencies domains entitlements entity explore features git_access graph has_feature invoices ledger limit " +
113+ "domains entitlements entity explore features git_access has_feature invoices ledger limit " +
114114 "limit_requests links log logs managed_pulls memories_by_id memory_context my_repo_invitations " +
115115 "outside_collaborators overview path_by_id prices profile profile_workspaces public_namespaces read_session " +
116116 "readable ready_issues references registration repo_access resolve resolve_branch resolve_path resolve_slug " +
+2−3
4747 key: "roadmap",
4848 title: "Roadmap",
4949 section: "Workspace",
50− summary: "Outcomes on a timeline, with their dependencies across projects.",
51− why: "An outcome is what should be true when the work is done. On a roadmap you see when each is expected, what it waits on in other projects, and how much has landed.",
50+ summary: "Outcomes on a timeline, with how much of each has landed.",
51+ why: "An outcome is what should be true when the work is done. On a roadmap you see when each is expected and how much has landed.",
5252 plans: [
5353 "Outcomes as bars on a timeline, from start to target",
5454 "Progress from merged work, not from guesses",
55− "Dependencies across projects, drawn from the project graph",
5655 "Slip warnings when the work left outgrows the time left",
5756 ],
5857 today: { label: "Outcomes", path: "plans" },
+1−1
305305 route("settings/runners", "routes/repo/settings-runners.tsx"),
306306 route("settings/deployments", "routes/repo/settings-deployments.tsx"),
307307 route("settings/domains", "routes/repo/settings-domains.tsx"),
308− route("settings/dependencies", "routes/repo/settings-dependencies.tsx"),
308+ route("settings/dependencies", "routes/repo/settings-dependencies.ts"),
309309 route("settings/guardrails", "routes/repo/settings-guardrails.tsx"),
310310 route("settings/agents", "routes/repo/settings-agents.tsx"),
311311 // What the project will have: one page for each Soon in its menu.
+2−64
11 import {
22 Activity as ActivityIcon,
3− ArrowDownLeft,
43 ArrowRight,
54 ArrowUpRight,
65 BookOpen,
1615 HeartPulse,
1716 Loader2,
1817 Lock,
19− Network,
2018 Package as PackageGlyph,
2119 Pin,
2220 Rocket,
209207 branchesP.catch(() => null),
210208 new Promise<"slow">((resolve) => setTimeout(() => resolve("slow"), crawler ? BRANCHES_WAIT_CRAWLER_MS : BRANCHES_WAIT_MS)),
211209 ]);
212− const [{ insider: member, can }, project, settings, list, open, closed, log, counts, deps, runs, queue, issues, memories, recent, mine, domains, root, packageList, workflows, tagList] = await Promise.all([
210+ const [{ insider: member, can }, project, settings, list, open, closed, log, counts, runs, queue, issues, memories, recent, mine, domains, root, packageList, workflows, tagList] = await Promise.all([
213211 accessP,
214212 projectP,
215213 forMembers(() => deployments.settings(ref, viewer)),
219217 // With their people, in one identity call.
220218 soft(repos.log(path, viewer, null, COMMITS_SHOWN).then(async (found) => (found.ok ? { ok: true as const, value: await showCommits(found.value) } : found))),
221219 soft(countsFor(context, params)),
222− soft(projects.dependencies(params.owner, params.repo, viewer)),
223220 soft(agents.listRuns(viewer, { repo: path, limit: 60 })),
224221 soft(work.queue(path, viewer)),
225222 soft(work.listIssues(path, viewer, { state: "open" })),
452449 languages: null as { name: string; share: number }[] | null,
453450 contributors: null as { username: string }[] | null,
454451 open: ok(counts) ?? { issues: openIssues?.length ?? 0, pulls: openPulls.length },
455− dependencies: ok(deps),
456452 agentsLive: live.slice(0, 6),
457453 runsLoaded: runs?.ok ?? false,
458454 pullsLoaded: open?.ok ?? false,
788784 actionData: Route.ComponentProps["actionData"];
789785 params: Route.ComponentProps["params"];
790786 }) {
791− const { member, project, settings, builds, live, commit, open, dependencies, agentsLive, columns, needs, landed, groups, health, knows, checklist, branches, library, checks } =
787+ const { member, project, settings, builds, live, commit, open, agentsLive, columns, needs, landed, groups, health, knows, checklist, branches, library, checks } =
792788 loaderData;
793789 const base = `/${params.owner}/${params.repo}`;
794790 const production = live.find((app) => app.kind === "production") ?? null;
14611457 )}
14621458 </div>
14631459 </div>
1464− </section>
1465−
1466− <section className="rounded-xl border border-line bg-surface p-5">
1467− <div className="flex items-center justify-between">
1468− <h2 className="flex items-center gap-1.5 text-sm font-semibold">
1469− <Network size={14} className="text-faint" />
1470− Dependencies
1471− </h2>
1472− {member && (
1473− <Link to={`${base}/settings/dependencies`} className="text-xs text-muted hover:text-fg">
1474− Manage
1475− </Link>
1476− )}
1477− </div>
1478− {!dependencies ? (
1479− <p className="mt-3 text-xs text-muted">Dependencies could not be loaded just now.</p>
1480− ) : dependencies.dependsOn.length === 0 && dependencies.usedBy.length === 0 ? (
1481− <p className="mt-3 text-xs leading-5 text-muted">
1482− Uses no other project, and none uses it. Declare one, and builds get its address and agents know what depends on
1483− what.
1484− </p>
1485− ) : (
1486− <div className="mt-3 space-y-3 text-xs">
1487− {dependencies.dependsOn.length > 0 && (
1488− <div>
1489− <p className="flex items-center gap-1 text-muted">
1490− <ArrowUpRight size={12} /> Uses
1491− </p>
1492− <ul className="mt-1.5 space-y-1">
1493− {dependencies.dependsOn.map((d) => (
1494− <li key={d.slug} className="flex items-center justify-between gap-2">
1495− <Link to={`/${params.owner}/${d.slug}`} className="font-medium hover:underline">
1496− {d.name}
1497− </Link>
1498− {d.as && <code className="font-mono text-faint">{d.as}</code>}
1499− </li>
1500− ))}
1501− </ul>
1502− </div>
1503− )}
1504− {dependencies.usedBy.length > 0 && (
1505− <div>
1506− <p className="flex items-center gap-1 text-muted">
1507− <ArrowDownLeft size={12} /> Used by
1508− </p>
1509− <ul className="mt-1.5 space-y-1">
1510− {dependencies.usedBy.map((d) => (
1511− <li key={d.slug}>
1512− <Link to={`/${params.owner}/${d.slug}`} className="font-medium hover:underline">
1513− {d.name}
1514− </Link>
1515− </li>
1516− ))}
1517− </ul>
1518− </div>
1519− )}
1520− </div>
1521− )}
15221460 </section>
15231461
15241462 {source && (
+8−121
1919 ArrowUpRight,
2020 MessagesSquare,
2121 Rocket,
22− Network,
2322 StickyNote,
2423 User,
2524 Users,
6968 } from "../../components/ui";
7069 import { CheckboxOption } from "../../components/ui/checkbox";
7170 import { Hint } from "../../components/ui/hint";
72−import { Loading, SkeletonLine } from "../../components/ui/skeleton";
7371 import { TabStrip } from "../../components/ui/tab-strip";
7472 import { WorkflowStatuses } from "../../components/actions";
7573 import { AddCiPrompt } from "../../components/add-ci";
9391 import { CATCH_UP_TIMEOUT_MS } from "../../lib/catch-up";
9492 import { notFound } from "../../lib/not-found.server";
9593 import { computeNoteFor } from "../../lib/compute.server";
96−import { actions, agents, deployments, identity, inbox, projects, repos, work } from "../../lib/services.server";
94+import { actions, agents, deployments, identity, inbox, repos, work } from "../../lib/services.server";
9795 import { commitChecksFor } from "../../lib/commit-checks.server";
9896 import { CommitChecksBadge } from "../../components/commit-checks";
9997 import { assertSameOrigin, getViewer, requireUser } from "../../lib/session.server";
141139 const ref = { workspace: params.owner, slug: params.repo };
142140 const access = accessTo(context, params);
143141 const pullFound = work.getPull(path, number, viewer);
144− const deps = projects.dependencies(params.owner, params.repo, viewer);
145− // Awaited below, unless the pull request is missing first.
146− deps.catch(() => null);
147142 // Its labels and milestone, with the repository's to choose from.
148143 const labelsFound = work.listLabels(path, viewer);
149144 const milestonesFound = work.listMilestones(path, viewer);
202197 pull.status === "open" &&
203198 (found.value.statuses ?? []).length === 0 &&
204199 (found.value.requiredChecks ?? []).length === 0;
205− const [comparison, used, noChecks] = await Promise.all([
200+ const [comparison, noChecks] = await Promise.all([
206201 // The first screens of it highlighted here, so their colours do not pop in.
207202 tab === "changes"
208203 ? repos
209204 .compare(range.repoId, viewer, range.base, range.head, range.baseBranch)
210205 .then(async (found) => (found.ok ? { ok: true as const, value: await highlightFirstFiles(found.value) } : found))
211206 : null,
212− deps,
213207 unchecked
214208 ? actions
215209 .workflows(path, viewer)
217211 .catch(() => false)
218212 : false,
219213 ]);
220− const affects = used.ok ? used.value.usedBy : [];
221214 // Every pull request for its issue, to compare: streamed, and read only
222215 // when there is more than this one.
223216 const attempts =
284277 // Who may choose the required checks.
285278 canProtect: can.manage_protection,
286279 defaultBranch: repo.ok ? repo.value.defaultBranch : "main",
287− affects,
288− // Streamed: the conversation shows first, the preview card after.
289− ...deploymentOf(deployed?.ok ? deployed.value : null, number, params.owner, affects, viewer),
280+ ...deploymentOf(deployed?.ok ? deployed.value : null, number),
290281 };
291282 }
292283
329320
330321 /**
331322 * Where this pull request is live: its preview (or its latest build, while
332− * one is going or after one failed), and the previews of the projects
333− * that use this one, built against it.
323+ * one is going or after one failed).
334324 */
335325 function deploymentOf(
336326 list: { deployments: Deployment[]; live: LiveApp[] } | null,
337327 number: number,
338− owner: string,
339− affects: { slug: string; name: string }[],
340− viewer: Viewer,
341−): { preview: LiveApp | null; build: Deployment | null; stacked: Promise<Stacked[]> } {
328+): { preview: LiveApp | null; build: Deployment | null } {
342329 const preview = list?.live.find((app) => app.kind === "preview" && app.number === number) ?? null;
343330 const build = list?.deployments.find((d) => d.kind === "preview" && d.number === number) ?? null;
344− const branch = preview?.branch ?? build?.branch ?? null;
345− // Streamed: another lookup per project, shown in the card once known.
346− const stacked: Promise<Stacked[]> = branch
347− ? Promise.all(
348− affects.slice(0, 5).map(async (project) => {
349− const theirs = await deployments.list({ workspace: owner, slug: project.slug }, viewer).catch(() => null);
350− const app = theirs?.ok ? theirs.value.live.find((a) => a.kind === "preview" && a.branch === branch) : undefined;
351− return app ? { name: project.name, slug: project.slug, url: app.url } : null;
352− }),
353− ).then((found) => found.filter((entry) => entry != null))
354− : Promise.resolve([]);
355− return { preview, build, stacked };
331+ return { preview, build };
356332 }
357−
358−/** A project that uses this one, with its preview built against this change. */
359−type Stacked = { name: string; slug: string; url: string };
360−
361333 const PULL_NEEDS: Record<string, Capability> = {
362− stack: "run",
363334 "agent-review": "run",
364335 "rerun-workflow": "run",
365336 "rerun-failed": "run",
389360 // `@acme/backend` is asked as `acme/backend`.
390361 ...String(form.get("others") ?? "").split(/[\s,]+/).map((name) => name.replace(/^@/, "")),
391362 ];
392− // The projects that use this one, built against this pull request's preview.
393− if (action === "stack") {
394− const built = await deployments.stack(user, { workspace: params.owner, slug: params.repo }, String(form.get("branch") ?? ""));
395− return built.ok
396− ? { action, notice: `Building ${built.value.join(", ")} against this preview. They appear on their Deployments pages.` }
397− : { action, error: built.error.message };
398− }
399363 // Asking g1t for its review records the request, then starts it.
400364 if (action === "agent-review") {
401365 const asked = await work.updatePull(user, path, number, {
666630 earlierChecks = [],
667631 workflowJobs,
668632 attempts,
669− affects,
670633 preview,
671634 build,
672− stacked,
673635 landing,
674636 stalled,
675637 requireUpToDate,
11491111 failed={actionData && "comment" in actionData ? { comment: String(actionData.comment), error: actionData.error } : null}
11501112 />
11511113
1152− {(preview || build) && <DeploymentCard preview={preview} build={build} stacked={stacked} stacking={affects.length > 0} base={base} />}
1114+ {(preview || build) && <DeploymentCard preview={preview} build={build} base={base} />}
11531115
11541116 {pull.status === "draft" && (
11551117 <StatusBox>
14521414 </Form>
14531415 )}
14541416 {actionData &&
1455− !["merge", "comment", "stack", "rerun-failed", "rerun-workflow", "update", "agent-review", "reviewers", "assign", "edit-comment", "delete-comment"].includes(
1417+ !["merge", "comment", "rerun-failed", "rerun-workflow", "update", "agent-review", "reviewers", "assign", "edit-comment", "delete-comment"].includes(
14561418 String(actionData.action),
14571419 ) && <ErrorText>{actionData.error}</ErrorText>}
14581420 </div>
14751437 >
14761438 {/* Other than a draft, a pull request shows its checks in full in the conversation. */}
14771439 {pull.status === "draft" && <WorkflowStatuses statuses={statuses} />}
1478− {affects.length > 0 && (
1479− <section>
1480− <h3 className="flex items-center gap-1.5 text-sm font-medium">
1481− <Network size={14} className="text-faint" />
1482− Affects
1483− </h3>
1484− <p className="mt-1 text-xs text-muted">Projects that use this one, and so may feel this change:</p>
1485− <ul className="mt-2 space-y-1 text-sm">
1486− {affects.map((project) => (
1487− <li key={project.slug} className="flex items-center justify-between gap-2">
1488− <Link to={`/${params.owner}/${project.slug}`} className="hover:underline">
1489− {project.name}
1490− </Link>
1491− {project.as && <code className="font-mono text-xs text-faint">{project.as}</code>}
1492− </li>
1493− ))}
1494− </ul>
1495− {preview?.branch && canMerge && (
1496− <Form method="post" className="mt-3">
1497− <input type="hidden" name="action" value="stack" />
1498− <input type="hidden" name="branch" value={preview.branch} />
1499− <SubmitButton
1500− match={{ action: "stack" }}
1501− pending="Starting the builds…"
1502− className="flex w-full items-center justify-center gap-1.5 rounded-md border border-line px-3 py-1.5 text-xs text-muted transition-colors hover:border-line-strong hover:text-fg disabled:opacity-50"
1503− >
1504− Preview them against this change
1505− </SubmitButton>
1506− </Form>
1507− )}
1508− {actionData?.action === "stack" &&
1509− ("notice" in actionData ? (
1510− <p className="mt-2 text-xs text-success">{String(actionData.notice)}</p>
1511− ) : (
1512− <ErrorText>{actionData.error}</ErrorText>
1513− ))}
1514− </section>
1515− )}
1516−
15171440 <section>
15181441 <h3 className="text-sm font-medium">Reviewers</h3>
15191442 <ul className="mt-2 space-y-1.5 text-sm">
17311654 function DeploymentCard({
17321655 preview,
17331656 build,
1734− stacked,
1735− stacking,
17361657 base,
17371658 }: {
17381659 preview: LiveApp | null;
17391660 build: Deployment | null;
1740− stacked: Promise<Stacked[]>;
1741− /** Projects use this one, so previews built against it may be on their way. */
1742− stacking: boolean;
17431661 base: string;
17441662 }) {
17451663 const building = build?.status === "queued" || build?.status === "building";
17951713 {preview.branch && ` · from ${preview.branch}`}
17961714 </p>
17971715 )}
1798− {/* Read after the page: the card's own part shows at once. */}
1799− <Suspense
1800− fallback={
1801− stacking && (
1802− <Loading className="border-t border-line px-4 py-2.5 text-xs">
1803− <SkeletonLine className="w-40" />
1804− <SkeletonLine className="mt-1.5 w-64 max-w-full" />
1805− </Loading>
1806− )
1807− }
1808− >
1809− <Await resolve={stacked}>
1810− {(stacked) =>
1811− stacked.length > 0 && (
1812− <div className="animate-fade-in border-t border-line px-4 py-2.5">
1813− <p className="text-xs text-muted">Built against this change:</p>
1814− <ul className="mt-1.5 space-y-1">
1815− {stacked.map((entry) => (
1816− <li key={entry.slug} className="flex items-center gap-2 text-xs">
1817− <span className="font-medium">{entry.name}</span>
1818− <a href={entry.url} className="truncate font-mono text-muted hover:text-accent">
1819− {entry.url.replace(/^https?:[/][/]/, "")}
1820− </a>
1821− </li>
1822− ))}
1823− </ul>
1824− </div>
1825− )
1826− }
1827− </Await>
1828− </Suspense>
18291716 </section>
18301717 );
18311718 }
+11−0
1+import { redirect } from "react-router";
2+
3+import type { Route } from "./+types/settings-dependencies";
4+
5+/**
6+ * Projects no longer declare which other projects they use. An old link to
7+ * that settings page lands on the project's settings.
8+ */
9+export function loader({ params }: Route.LoaderArgs) {
10+ throw redirect(`/${params.owner}/${params.repo}/settings`, 301);
11+}
+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

This change is too large to show in full.