Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
ac95873
chore(web): remove dead front-end code left by the Foldkit migration
Makisuo Nov 10, 2026
5d051f8
chore(web): drop the type of the removed VITE_MAPLE_CAPTURE flag
Makisuo Nov 10, 2026
01fb03e
Merge branch 'chore/audit-docs-leftovers' into chore/audit-frontend-d…
Makisuo Nov 10, 2026
65267ce
Merge branch 'chore/audit-docs-leftovers' into chore/audit-frontend-d…
Makisuo Nov 10, 2026
145cf7d
Merge branch 'chore/audit-docs-leftovers' into chore/audit-frontend-d…
Makisuo Nov 10, 2026
a32be04
Merge branch 'chore/audit-docs-leftovers' into chore/audit-frontend-d…
Makisuo Nov 10, 2026
798e57e
Merge branch 'chore/audit-docs-leftovers' into chore/audit-frontend-d…
Makisuo Nov 10, 2026
e4f04ff
Merge branch 'chore/audit-docs-leftovers' into chore/audit-frontend-d…
Makisuo Nov 10, 2026
f3b9151
Merge branch 'chore/audit-docs-leftovers' into chore/audit-frontend-d…
Makisuo Nov 10, 2026
82130a5
Merge branch 'chore/audit-docs-leftovers' into chore/audit-frontend-d…
Makisuo Nov 10, 2026
66367a3
Merge branch 'chore/audit-docs-leftovers' into chore/audit-frontend-d…
Makisuo Nov 10, 2026
4b8792e
Merge branch 'chore/audit-docs-leftovers' into chore/audit-frontend-d…
Makisuo Nov 10, 2026
39ad900
Merge branch 'chore/audit-docs-leftovers' into chore/audit-frontend-d…
Makisuo Nov 10, 2026
7a774b5
Merge branch 'chore/audit-docs-leftovers' into chore/audit-frontend-d…
Makisuo Nov 10, 2026
eaedf90
Merge branch 'chore/audit-docs-leftovers' into chore/audit-frontend-d…
Makisuo Nov 10, 2026
03adff3
test(query-engine): give the list-nesting property test room on a loa…
Makisuo Nov 10, 2026
8d3f920
Merge branch 'chore/audit-docs-leftovers' into chore/audit-frontend-d…
Makisuo Nov 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
<link rel="preconnect" href="https://favicon.maple.dev" />

<!-- Apply the saved theme before first paint to avoid a flash of the wrong theme.
Must stay in sync with the theme store in @maple/ui/hooks/use-theme
Must stay in sync with the shell (`THEME_STORAGE_KEY` in src/shell/command.ts, `readTheme` in
src/shell/flags.ts)
(storage key "maple-theme", `light`/`dark` class on <html>, default "dark"). -->
<script>
;(() => {
Expand Down
24 changes: 0 additions & 24 deletions apps/web/src/components/infra/gcp/inventory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import type { GcpResource } from "@maple/domain/http"
import {
gcpCloudSqlInstances,
gcpConsoleLinks,
gcpConsoleProjectPages,
gcpConsoleScopePage,
gcpExplorerWhere,
gcpMatchResource,
gcpResourceQuery,
Expand Down Expand Up @@ -250,25 +248,3 @@ describe("gcpCloudSqlInstances", () => {
expect(instances).toEqual([{ ...settings, id: "acme-prod:orders-db", name: "orders-db" }])
})
})

describe("gcpConsoleScopePage", () => {
it("opens a project's dashboard, and a folder or organization in the resource manager", () => {
expect(gcpConsoleScopePage({ scope_type: "project", scope_id: "acme prod" })).toBe(
"https://console.cloud.google.com/home/dashboard?project=acme%20prod",
)
expect(gcpConsoleScopePage({ scope_type: "folder", scope_id: "4521" })).toBe(
"https://console.cloud.google.com/cloud-resource-manager?folder=4521",
)
expect(gcpConsoleScopePage({ scope_type: "organization", scope_id: "1234" })).toBe(
"https://console.cloud.google.com/cloud-resource-manager?organizationId=1234",
)
})
})

describe("gcpConsoleProjectPages", () => {
it("opens every page on the project", () => {
for (const page of gcpConsoleProjectPages("acme prod")) {
expect(new URL(page.href).searchParams.get("project"), page.label).toBe("acme prod")
}
})
})
29 changes: 0 additions & 29 deletions apps/web/src/components/infra/gcp/inventory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,35 +243,6 @@ export function gcpConsoleLinks(service: GcpInfraServiceId, keys: ReadonlyArray<
}
}

/** The console page of what a connection covers: the project's dashboard, or the folder or organization in the resource manager. */
export function gcpConsoleScopePage(scope: {
readonly scope_type: string
readonly scope_id: string
}): string {
switch (scope.scope_type) {
case "organization":
return consoleUrl("cloud-resource-manager", "organizationId", scope.scope_id)
case "folder":
return consoleUrl("cloud-resource-manager", "folder", scope.scope_id)
default:
return consoleUrl("home/dashboard", "project", scope.scope_id)
}
}

/** A project's console pages for what Maple shows of it: its metrics, logs and resources. */
export const gcpConsoleProjectPages = (
project: string,
): ReadonlyArray<{ readonly label: string; readonly href: string }> =>
Arr.map(
[
["Dashboard", "home/dashboard"],
["Metrics Explorer", "monitoring/metrics-explorer"],
["Logs Explorer", "logs/query"],
["Asset Inventory", "iam-admin/asset-inventory/dashboard"],
] as const,
([label, path]) => ({ label, href: consoleUrl(path, "project", project) }),
)

/**
* Where a workload's other telemetry is. Its metrics, and its traces when it is instrumented, are
* under `serviceName`: the workload's own for compute, `gcp/<resource type>` for a managed
Expand Down
24 changes: 0 additions & 24 deletions apps/web/src/components/infra/gcp/tabs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@ import { GCP_INFRA_SERVICE_IDS, GCP_INFRA_SERVICES, gcpInfraMetrics } from "@map
import { GCP_ASSET_TYPES } from "@maple/domain/gcp-metrics"
import {
GCP_INFRA_COLUMNS,
GCP_VIEW_SERVICES,
formatGcpValue,
gcpAssetTypeLabel,
gcpHasRegion,
gcpInfraNotice,
gcpInfraSetupPending,
gcpServiceView,
gcpResourceName,
gcpResourcesError,
gcpStateLabel,
Expand Down Expand Up @@ -227,13 +224,6 @@ describe("workload identity", () => {
expect(gcpWorkloadName("cloudRun", API)).toBe("api")
})

it("knows which services have a region to filter by", () => {
expect(Arr.filter(GCP_INFRA_SERVICE_IDS, (id) => !gcpHasRegion(id))).toEqual([
"pubsub",
"loadBalancing",
])
})

it("marks the columns that are totals over the range", () => {
expect(
Arr.map(
Expand Down Expand Up @@ -273,20 +263,6 @@ describe("formatGcpValue", () => {
})
})

describe("gcpServiceView", () => {
it("lists every service in exactly the view it names", () => {
for (const service of GCP_INFRA_SERVICE_IDS) {
const views = Arr.filter(Rec.toEntries(GCP_VIEW_SERVICES), ([, services]) =>
Arr.some(services, (listed) => listed === service),
)
expect(
Arr.map(views, ([view]) => view),
service,
).toEqual([gcpServiceView(service)])
}
})
})

describe("gcpInfraNotice", () => {
const NOW = Date.parse("2026-10-08T12:00:00.000Z")
const ago = (minutes: number) => new Date(NOW - minutes * 60_000).toISOString()
Expand Down
8 changes: 0 additions & 8 deletions apps/web/src/components/infra/gcp/tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,10 +382,6 @@ export const gcpWorkloadName = (service: GcpInfraServiceId, keys: ReadonlyArray<
)(keys[0] ?? "")
: (keys[0] ?? "")

/** Whether a service's workloads run in a region or zone; a subscription and a URL map are global. */
export const gcpHasRegion = (service: GcpInfraServiceId): boolean =>
Arr.some(GCP_INFRA_SERVICES[service].identity, ([label]) => REGION_LABELS.includes(label))

/** What one row of a tab is, in running text: "container", "URL map". */
export const gcpWorkloadNoun = (service: GcpInfraServiceId): string =>
replaceWith(GCP_INFRA_SERVICES[service].identity[0][0], /^[A-Z](?=[a-z])/, (letter) =>
Expand Down Expand Up @@ -420,10 +416,6 @@ export const GCP_VIEW_SERVICES = {
loadBalancing: ["loadBalancing"],
} as const satisfies Record<GcpServiceView, ReadonlyArray<GcpInfraServiceId>>

/** The list a service's workloads are in: `?view=` of the way back from a workload's page. */
export const gcpServiceView = (service: GcpInfraServiceId): GcpServiceView =>
service === "cloudRun" || service === "cloudFunctions" ? "services" : service

export type GcpInfraNotice =
/** A connector's reads fail, or arrive with part of the metrics missing. */
| { readonly kind: "failing" | "incomplete"; readonly error: string }
Expand Down
22 changes: 1 addition & 21 deletions apps/web/src/components/integrations/gcp-connector-state.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ import { GcpLogRuntime } from "@maple/domain/primitives"
import {
GCP_LOG_RUNTIMES,
cloudShellUrl,
gcpApplyLine,
gcpCollectLock,
gcpConnectionState,
gcpCreateRequest,
gcpDraftEffect,
gcpApplicationLogsLine,
gcpLogFilterChoice,
gcpLogState,
gcpMessageParts,
Expand Down Expand Up @@ -522,17 +520,6 @@ describe("gcpRunAsked", () => {
})
})

describe("gcpApplyLine", () => {
it("says what the run does about a capability", () => {
expect(gcpApplyLine(true, true)).toBe("On")
expect(gcpApplyLine(true, null)).toBe("On after this run")
expect(gcpApplyLine(true, false)).toBe("On after this run")
expect(gcpApplyLine(false, true)).toBe("Off in Maple. This run removes it from Google Cloud.")
expect(gcpApplyLine(false, false)).toBe("Off")
expect(gcpApplyLine(false, null)).toBe("Off")
})
})

describe("gcpMessageParts", () => {
it("cuts the first sentence, the remedy and what Google answered, without rewording", () => {
expect(
Expand Down Expand Up @@ -714,14 +701,7 @@ describe("gcpLogFilterChoice", () => {
})
})

describe("gcpApplicationLogsLine", () => {
it("names the runtimes in display order, whatever order they were ticked in", () => {
expect(gcpApplicationLogsLine(["gke", "cloud_run"])).toBe(
"Platform logs and the output of Cloud Run, GKE containers",
)
expect(gcpApplicationLogsLine([])).toBe("Platform logs only, no application output")
})

describe("GCP_LOG_RUNTIMES", () => {
it("has a name for every runtime the API takes", () => {
expect(Arr.map(GCP_LOG_RUNTIMES, ({ value }) => value)).toEqual([...GcpLogRuntime.literals])
})
Expand Down
21 changes: 0 additions & 21 deletions apps/web/src/components/integrations/gcp-connector-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,16 +358,6 @@ export function gcpDraftEffect(
return setUp ? (wanted ? "stops-now" : "removed-by-script") : null
}

/** One line of the apply step's recap: what the script does about a capability. */
export const gcpApplyLine = (wanted: boolean, applied: boolean | null): string =>
wanted
? applied === true
? "On"
: "On after this run"
: applied === true
? "Off in Maple. This run removes it from Google Cloud."
: "Off"

/**
* A failure in the API's words, cut for display and not reworded: the first sentence, the
* sentences that say what to do, and what Google answered, which closes the message in brackets.
Expand Down Expand Up @@ -506,17 +496,6 @@ export const gcpLogFilterChoice = (draft: GcpLogFilterDraft, sinkExists: boolean
}
}

/** One line of the apply step's recap: whose application output the new filter forwards. */
export const gcpApplicationLogsLine = (runtimes: ReadonlyArray<GcpLogRuntime>): string => {
const labels = Arr.map(
Arr.filter(GCP_LOG_RUNTIMES, ({ value }) => runtimes.includes(value)),
({ label }) => label,
)
return labels.length === 0
? "Platform logs only, no application output"
: `Platform logs and the output of ${Arr.join(labels, ", ")}`
}

const LOG_ROUTER_SCOPE = { project: "project", folder: "folder", organization: "organizationId" } as const

/** The console's Log Router for the scope that holds the connection's sink. */
Expand Down
19 changes: 8 additions & 11 deletions apps/web/src/components/service-map/three/factory-routing.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { describe, expect, it } from "vitest"
import { SERVICE_MAP_3D_TOPOLOGY as topology } from "../../../lab/service-map-3d/fixture"
import { factoryLinks, factoryRoutes, decorateRoutes, beltGeometry, CurveSection } from "./factory-routing"
import { spatialLayout } from "./spatial-layout"
import { factoryRoutes, decorateRoutes, beltGeometry } from "./factory-routing"
import { spatialLayout, type SpatialView } from "./spatial-layout"
import { Array as Arr } from "effect"

const linksOf = (view: SpatialView) =>
decorateRoutes(factoryRoutes(topology, spatialLayout(topology, view)), topology.edges)

describe("factory transports", () => {
it("updates live rates without replacing transport geometry", () => {
const routes = factoryRoutes(topology, spatialLayout(topology, "atlas"))
Expand All @@ -22,7 +25,7 @@ describe("factory transports", () => {
it.each(["atlas", "cascade"] as const)(
"routes every call with finite, continuous geometry in %s",
(view) => {
const links = factoryLinks(topology, spatialLayout(topology, view))
const links = linksOf(view)
expect(links).toHaveLength(topology.edges.length)
for (const link of links) {
expect(link.curve.getLength()).toBeGreaterThan(0)
Expand All @@ -34,26 +37,20 @@ describe("factory transports", () => {
expect(point.distanceTo(previous)).toBeLessThan(link.curve.getLength() / 50)
previous = point
}
const glass = new CurveSection(link.curve, 0.38, 0.62)
expect(glass.getPoint(0).distanceTo(link.curve.getPointAt(0.38))).toBeLessThan(0.0001)
expect(glass.getPoint(1).distanceTo(link.curve.getPointAt(0.62))).toBeLessThan(0.0001)
}
},
)
it("uses conveyors only for calls involving a queue", () => {
const nodes = new Map(Arr.map(topology.nodes, (node) => [node.id, node]))
for (const link of factoryLinks(topology, spatialLayout(topology, "atlas"))) {
for (const link of linksOf("atlas")) {
const queued =
nodes.get(link.edge.source)?.kind === "queue" || nodes.get(link.edge.target)?.kind === "queue"
expect(link.kind).toBe(queued ? "conveyor" : "pipe")
expect(link.signPosition.y).toBeGreaterThan(link.curve.getPointAt(0.5).y)
}
})
it("builds finite indexed belt decks on slopes and elbows", () => {
for (const link of Arr.filter(
factoryLinks(topology, spatialLayout(topology, "cascade")),
(link) => link.kind === "conveyor",
)) {
for (const link of Arr.filter(linksOf("cascade"), (link) => link.kind === "conveyor")) {
const geometry = beltGeometry(link.curve, 0.8)
expect(Arr.every([...geometry.getAttribute("position").array], Number.isFinite)).toBe(true)
expect(Arr.every([...geometry.getAttribute("normal").array], Number.isFinite)).toBe(true)
Expand Down
17 changes: 0 additions & 17 deletions apps/web/src/components/service-map/three/factory-routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,6 @@ export function roundedRoute(points: THREE.Vector3[], radius = 0.65) {
return path
}

export class CurveSection extends THREE.Curve<THREE.Vector3> {
constructor(
readonly curve: THREE.Curve<THREE.Vector3>,
readonly start: number,
readonly end: number,
) {
super()
}
getPoint(t: number, target = new THREE.Vector3()) {
return this.curve.getPointAt(this.start + (this.end - this.start) * t, target)
}
}

export function factoryRoutes(topology: RoutingTopology, layout: SpatialLayout): FactoryRoute[] {
const nodes = new Map(Arr.map(topology.nodes, (node) => [node.id, node]))
const edges = Arr.sort(
Expand Down Expand Up @@ -148,10 +135,6 @@ export function decorateRoutes(routes: FactoryRoute[], edges: ReadonlyArray<Edge
})
}

export function factoryLinks(topology: Topology3D, layout: SpatialLayout): FactoryLink[] {
return decorateRoutes(factoryRoutes(topology, layout), topology.edges)
}

/** A ribbon follows the belt's horizontal normal, remaining upright on ramps. */
export function beltGeometry(curve: THREE.Curve<THREE.Vector3>, width: number, offset = 0) {
const vertices: number[] = [],
Expand Down
20 changes: 0 additions & 20 deletions apps/web/src/components/settings/audit-log-filters.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
parseAuditLogSearch,
parseAuditLookup,
pickAuditLogSearch,
resolveAuditDateRange,
} from "./audit-log-filters"

describe("parseAuditLogSearch", () => {
Expand Down Expand Up @@ -95,25 +94,6 @@ describe("auditLogSearchFrom", () => {
})
})

describe("resolveAuditDateRange", () => {
const now = Date.parse("2026-10-17T12:00:00.000Z")

it("resolves a rolling preset against the given moment", () => {
expect(resolveAuditDateRange({ kind: "preset", preset: "24h" }, now)).toEqual({
since: "2026-10-16T12:00:00.000Z",
until: undefined,
})
})

it("passes a fixed range through and leaves all time unbounded", () => {
expect(resolveAuditDateRange({ kind: "custom", since: "2026-10-01T00:00:00.000Z" }, now)).toEqual({
since: "2026-10-01T00:00:00.000Z",
until: undefined,
})
expect(resolveAuditDateRange({ kind: "all" }, now)).toEqual({ since: undefined, until: undefined })
})
})

describe("the resource, action, request and kind filters", () => {
it("keeps known values and round-trips them through the URL", () => {
const search = {
Expand Down
19 changes: 0 additions & 19 deletions apps/web/src/components/settings/audit-log-filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,25 +174,6 @@ export function pickAuditLogSearch(search: AuditLogSearch): AuditLogSearchUpdate
return auditLogSearchFrom(parseAuditLogSearch(search))
}

/** The `since`/`until` bounds a range resolves to at `now`. */
export function resolveAuditDateRange(
range: AuditDateRange,
now: number,
): { readonly since: string | undefined; readonly until: string | undefined } {
if (range.kind === "custom") return { since: range.since, until: range.until }
const preset =
range.kind === "preset"
? Arr.findFirst(AUDIT_RANGE_PRESETS, (option) => option.value === range.preset)
: Option.none()
return {
since: Option.match(preset, {
onNone: () => undefined,
onSome: (found) => new Date(now - found.ms).toISOString(),
}),
until: undefined,
}
}

export function hasAuditLogFilters(filters: AuditLogFilters): boolean {
return (
filters.range.kind !== "all" ||
Expand Down
Loading
Loading