Skip to content

feat(web): Google Cloud integration card - #1334

Open
JeremyFunk wants to merge 44 commits into
feat/gcp-metrics-pollerfrom
feat/gcp-integration-card
Open

JeremyFunk wants to merge 44 commits into
feat/gcp-metrics-pollerfrom
feat/gcp-integration-card

Conversation

@JeremyFunk

@JeremyFunk JeremyFunk commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on the metrics poller PR (which is stacked on #1320 and #1321). Merge order: bottom up.

Summary

Adds the Google Cloud page to Integrations. An org admin connects an organization, a folder or a project, chooses log forwarding and metrics and resources per connection, and runs the generated script in Cloud Shell. Built on the /v2/integrations/gcp API; no backend or contract changes.

  • Catalog entry "Google Cloud" (infrastructure shelf, isNew). Hub row and page header read the connection's worst state.
  • The page shows status. Everything that changes a connection, and the script that applies the change, is behind one door per connection: Configure.
  • Disconnect: a dialog that puts the cleanup script first and sees it finish, then Disconnect. A connection removed before its cleanup was seen keeps a panel with the cleanup script until it is dismissed, across reloads.
  • Non-admins see status only.

Interaction model

What a change does, as the API has it: turning a capability off acts in Maple at once (logs are no longer stored within about a minute, the poller skips the connection from the next 5-minute read) while Google Cloud keeps its resources until the script runs. Turning one on does nothing until the script has run. The page is built on that.

  1. A connection's two capabilities are status on the page: a dot, a label, when it last delivered, a link to its data. There are no switches on the page.
  2. Configure opens a dialog with two stages, named under its title: Configure > Apply in Google Cloud.
  3. Stage 1 holds what to collect (two checkboxes) and the log filter. Under a checkbox that differs from what is set up, one line says what saving does and when: Starts once the script has run in Google Cloud., or Maple stops storing these logs within about a minute of saving. Google Cloud keeps forwarding them until the script has run.
  4. A change that acts in Maple the moment it is saved asks first: turning something off, and turning something back on whose Google Cloud resources still exist. The confirmation says what happens In Maple and what goes on In Google Cloud.
  5. Saving leads into stage 2: a recap of what is saved and what this run does about it, then Open Cloud Shell, Copy script, and a step that waits for the run and turns into Google Cloud matches this configuration.
  6. The setup script exists only in stage 2. With nothing changed, stage 1's button reads Continue to the script: that is how the script is run again.
  7. When the saved configuration and what the script last reported differ, or a new connection's script has not reported, the card shows a band with one filled button that opens the dialog at stage 2: Finish setup or Apply changes. The band says what goes on until then (Google Cloud keeps forwarding logs, billed by Google, until the script has removed the log sink.). A failure whose text asks for the setup script gets the same band with Run the script again, once per connection.
  8. Adding a connection is the same dialog: Connect > Apply in Google Cloud. Stage 1 has the scope, the IDs, what to collect and the log filter; Create and continue leads into the same stage 2.
  9. Disconnect is in the card's menu, with its cleanup-first dialog.
  10. A hint or a failure is a headline, at most two lines or a short list, then one action. A failure from the API is cut, not reworded: its first sentence is the headline, each further sentence a line, what Google answered the fine print.

Layout

  • Full content width, gap-4, like the Cloudflare and PlanetScale pages. Breakpoints are container queries on the page (@container/page): beside two sidebars the viewport says little.
  • One Panel per connection, worst state first. Header: name, Configure, the menu. Under it the band, when the script has to run. Under that the two capabilities, side by side while both are one line of status; a capability with a hint or a failure takes the card's width, with its state next to its name.
  • The dialog's footer is its buttons. What a stage needs to say sits in its body.
  • integration-empty-state.tsx: the value tiles go three-up on the page's width (@2xl/page), not the viewport's.
  • GcpMessage lays a failure out as headline, lines and fine print wherever it renders, which includes the Infrastructure page's notices in the PR above.

Decisions to look at:

  • The log filter is a parameter of the script; the API does not store it. A connection with a sink starts on Keep the sink's current filter, so running the script again never resets a filter, and the filter's own lines say Applies: when the script runs. Changing only the filter saves nothing, so the button stays Continue to the script.
  • Include GKE container logs keeps its acknowledgement (title, both sentences and the checkbox sentence unchanged). Ticking the box is the confirmation: the stage's button stays disabled until then, and the former Confirm and show script button is gone because the script is now the next stage.
  • Turning back on what still exists in Google Cloud leaves nothing to run: the stage's button reads Save, its note Nothing to run after this, the confirmation Turn on, and the dialog then shows that Google Cloud matches.
  • A capability the script has not set up reads Not set up; Setup pending is the connection's word (header, hub, band).
  • The band replaces the card's badge for pending states. With one connection the card has no badge at all: the page header names its state.
  • One read of status per page; a save shows at once in the dialog (the saved flags are overlaid until the status read catches up).

Kept after screenshot review, with the reason:

  • Configure stays on the card beside the band's button: it is the stable door, the band's button is the shortcut to its second stage.
  • A one-item menu for Disconnect: it keeps the destructive action out of the primary position.
  • The 20-minute hint for a silent sink has the test command as its action and names Configure for a rerun in its text: the rerun is the fallback, not the first thing to do.
  • The same status can appear in two layouts on one page (side by side on one card, full width on another): a failure or a warning at half width left the other half of the card empty. Neutral hints of a line or two stay side by side.
  • An incomplete resource list leaves the connection Healthy with an amber dot on the capability: metrics are unaffected, and for a scope over the list limit it would never clear.
  • An amber Needs attention badge over a red capability dot: the hub's and the header's tone for the state. The dot carries the severity.
  • The selected scope card's check mark, dialog title line height and the phone footer's button order come from shared primitives.

Status model

gcp-connector-state.ts holds the rules, pure and tested; the card, the configuration dialog, the hub and the Infrastructure page call the same functions.

Capability States
Log forwarding Off, Rejecting logs, Not set up, Setup running, Waiting for first logs (with a test command after 20 minutes), No logs in 24 hours, Receiving logs
Metrics and resources Off, Not set up, Setup running, Waiting for first metrics (after 15 minutes it says none have arrived), Can't read metrics, Receiving metrics incomplete, Metrics stalled, Receiving metrics
Connection (header, hub, card) Needs attention, Setup pending, Changes pending, Waiting for data, Healthy
  • The states use applied_logs_enabled, applied_metrics_enabled and setup_reported_at: what the latest script run reported.
  • gcpDraftEffect says what saving a choice does and when (starts-after-script, stops-now, resumes-now, removed-by-script); the dialog's notes and its confirmation read it.
  • gcpPendingChanges says, per capability, what goes on until the script has run; gcpRunAsked names the capabilities whose failure asks for the setup script; gcpMessageParts cuts a failure into headline, lines and Google's answer.
  • A new connection and a pending change do not count toward the hub's "need attention".
  • The poller's "can't sign in yet" text stays hidden until a run reported metrics access, and for 10 minutes after a report.
  • An error with the last successful read older than 10 minutes (two polls) is Can't read metrics; with a read inside 10 minutes it stays Receiving metrics, incomplete.
  • A capability that no run has reported on reads Setup running for two minutes after a report on the other one: the script reports its sections seconds apart.
  • An incomplete resource list keeps Receiving metrics and adds resource list incomplete with an amber dot: metrics are unaffected, and the connection stays healthy.
  • The apply stage knows a newer run by a changed setup_reported_at, not by the browser's clock. Its "no confirmation yet" help counts five minutes from the connection's creation, so a reload does not restart it.

Decisions

  • The setup and cleanup scripts are read with a bare MapleApiV2AtomClient.query, not retainedQueryV2: they embed the connector's secret, so they are disposed with the dialog. The <pre> carries REPLAY_BLOCK_CLASS. Only the cleanup script from the delete response, which has no secret, is persisted (Atom.kvs, per organization) for the panel that stays after a disconnect.
  • Only what changed is sent on save: the API leaves an omitted capability as it is.
  • The card's links into the docs (Roles if you aren't an Owner, Troubleshooting, Write a filter of your own, and the links from the acknowledgement and the filter lines) and the catalog's docs link arrive with the docs PR above, so nothing here points at a page that is not there.
  • The numbers at the top of the page and the links to Infrastructure arrive with the Infrastructure PR above.
  • Status polls every 10s while any connection is pending, waiting or failing, and while the apply stage or the disconnect dialog waits for a run; otherwise every 60s.
  • Two files where there was one: gcp-integration-card.tsx (the page, 0.8k lines) and gcp-configure.tsx (the dialog, the scripts and the disconnect dialog, 1.5k lines), from 1.7k.

Verification

  • gcp-connector-state.test.ts (70 tests): one case per row of the state tables, the partial-report window, the script-needed rule, what a draft does and when, which failures ask for the script, how a failure is cut, the order of the log filters and the acknowledgement rule.
  • Rendered against a local stack, each state produced by seeding the connector row: 57 states at 1440px, 1024px and 390px. Two directions were built first (connection cards with a stat row and a dialog; capability panels with a side sheet) and compared from screenshots by a fresh reviewer; then seven rounds, each judged by a fresh reviewer from screenshots alone against this checklist: dead space, numbers at a glance, whether every control says when it takes effect, single-colour text blocks, orphan buttons. The last round found no blocker and marked numbers, effect timing, text blocks and orphan buttons clean; what it listed under dead space (one amber hint at half width) and wording was changed afterwards and spot-checked, not put before another reviewer.
  • Not run against Google Cloud in this PR: the states come from seeded rows, not from a real script run.

Review notes

  • Maple review F1 (the card linked a docs page this PR does not add): applied. The links are in the docs PR.
  • Maple review F2 (no test that the script block carries the replay-block class): not added. Script applies the class unconditionally in one line, and it only ever renders a secret-bearing script; a render test would pin a class name.
  • Texts inside failure messages come from the ingest gateway and the poller (lower PRs); this PR only lays them out.
  • Kept as is:
    • An error inside 10 minutes of the last successful read reads Receiving metrics, incomplete whatever the message says. The card does not read meaning out of message text, with one exception: a failure that names the setup script gets the band's Run the script again.
    • Setup running rests on the report of the other capability alone. If the script stopped between its sections, the row says so two minutes later.
    • Waiting for data stays the connection's word also when only one capability waits.
    • Turning log forwarding off and on again without running the script shows the 20-minute test-command hint early, because the API clears the last-received time. It clears with the next accepted entry.

Summary by CodeRabbit

  • New Features
    • Added Google Cloud as an integration, with connection setup for organizations, folders, and projects.
    • Choose log and metrics collection options, review setup progress and connection health, and apply or retry setup changes.
    • Disconnect connections and access cleanup scripts, with options to copy scripts or open them in Google Cloud Shell.
    • View collection status, setup issues, and relevant Google Cloud links from the integration overview. Admins can manage connections; other users can view status.

@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3862072b-f0ee-424a-bfd4-bf778df539c8
📥 Commits

Reviewing files that changed from the base of the PR and between 47294ac and 0590969.

📒 Files selected for processing: 2
  • apps/web/src/components/icons/index.ts
  • apps/web/src/routes/integrations.tsx

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 1 remain after this review.

📝 Walkthrough

Adds Google Cloud as an integrations-page option. The change includes connector state rules, connection setup and editing, status displays, disconnect and cleanup flows, and catalog status and overview data.

Changes: Google Cloud integration

Layer / File(s) Summary
Connector states and validation
apps/web/src/components/integrations/gcp-connector-state.ts, apps/web/src/components/integrations/gcp-connector-state.test.ts
Adds log and metrics state classification, setup timing, capability effects and locks, scope and request validation, and log-filter rules. Tests cover these states and helpers.
Connection configuration and cleanup
apps/web/src/components/integrations/gcp-configure.tsx
Adds flows to create and edit connections, apply setup scripts, refresh setup status, and disconnect with cleanup status.
Connection status and retained cleanup
apps/web/src/atoms/gcp-removed-connectors-atoms.ts, apps/web/src/components/integrations/gcp-integration-card.tsx
Adds connection status displays and admin controls. Retains cleanup details after disconnect when applied capabilities remain on.
Integrations catalog and route
apps/web/src/components/icons/google-cloud.tsx, apps/web/src/components/icons/index.ts, apps/web/src/components/integrations/integration-catalog.tsx, apps/web/src/components/integrations/integration-empty-state.tsx, apps/web/src/routes/integrations.tsx
Adds Google Cloud catalog status and overview data, icons, and route rendering. Uses shared health tones and a container-based breakpoint for the empty-state feature grid.

Priority: ⬇️ Low

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Feature

Suggested reviewers: makisuo

Merge Risk: ⚪ Minimal · up to 05909

The selected changes correctly expose the Google Cloud icon and route catalog selection to the Google Cloud integration card; no merge-blocking issue is identified.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 68.09% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 47 functions across 10 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly identifies the primary change: adding a Google Cloud integration card to the web application.
  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@maple-review-bot

maple-review-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
CI's web typecheck and effect-lint fail on this head, so the card is not yet proven to compile or render.
quality 100/100 · no findings · tests covered · risk medium

Adds the Google Cloud card to the Integrations page: connect form, per-capability switches with status, and the Cloud Shell setup/cleanup scripts, on the existing v2 API. The card state machine and its contract use check out; the head still fails CI's web typecheck, so it is unproven as compiling.

  • GcpIntegrationCard lists connectors with a switch and status per capability
  • gcpCreateRequest validates the draft with the API's own create schema
  • gcpSwitchLock locks the last-on switch and metrics on a deployment without access
  • The setup script is read without retention, so its secret dies with the panel
What was checked
  • PATCH carries only the flipped flag; the API keeps omitted fields (integrations-gcp.ts:193, route test :228)
  • CopyButton never puts the script in the DOM, and the <pre> carries rr-block (copy-button.tsx:285)
  • gcpStatusQuery and both mutations share reactivityKeys: ["gcpIntegration"], so a save invalidates the read

c123d38 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Warning

The review of 64061ac could not finish. It stopped before it finished, so its partial findings are not posted here. Comment @maple-review-bot review to try again.

@maple-review-bot

maple-review-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
The pure state rules are pinned by 30 tests; the React wiring (optimistic switch, panel reopen) was read, not run, and the card has no browser test.
quality 100/100 · no findings · tests partial · risk medium

Adds the Google Cloud integration card: a scope-picker connect form, per-capability switches and status, setup/cleanup scripts, and hub status/overview derived from the existing v2 status read. UI-only, no backend or contract change, and safe to merge.

  • gcp-connector-state.ts derives log/metrics states, switch locks and the create request
  • GcpIntegrationCard adds, lists and disconnects connectors; one PATCH per flipped switch
  • A switch save invalidates the script key and reopens the setup panel
  • Hub status chip and overview read gcpStatusQuery, polling 10s while settling, else 60s
What was checked
  • Every branch of gcpLogState/gcpMetricsState/gcpAttention/gcpSwitchLock/gcpCreateRequest is covered in gcp-connector-state.test.ts
  • The setup script is the only secret-bearing text: it renders inside REPLAY_BLOCK_CLASS (gcp-integration-card.tsx:143), and renderGcpCleanupScript interpolates no push endpoint (`setup-scripts.ts…
  • ConfirmDialog treats a resolved false as keep-open, matching handleDisconnect (confirm-dialog.tsx:67); errorMessage accepts both an Exit and an error (error-toast.ts:25)

1af3b22 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 7/10 · likely safe to merge
The pure state module has 30 tests over every branch; 900 lines of JSX around it have never been rendered.
quality 100/100 · no findings · tests partial · risk medium

Adds the Google Cloud integration card, its pure state/validation module and the catalog entry, all on the /v2/integrations/gcp contract the base branch already ships. Contained UI work; safe to merge once the stacked base PRs land.

  • gcpConnectorState derives log, metrics, attention and switch-lock state from a connector
  • GcpIntegrationCard lists connections with a switch per capability and a setup panel
  • gcpCreateRequest validates the add form with the API's own create schema
  • Catalog gets the Google Cloud entry, hub status and overview, plus a mono icon

Before merge

What was checked
  • Setup script only rendered when the result is settled (!waiting), so a held-over script can't be copied (gcp-integration-card.tsx:373)
  • Setup script <pre> carries REPLAY_BLOCK_CLASS; rrweb blocks the subtree (record.ts default blockClass), so the embedded secret never reaches replay
  • gcpSwitchLock mirrors the API rule: the last-on switch is locked and metrics is locked when the deployment can't read them

7da92a7 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Maple review

🟡 Confidence 6/10 · needs attention
The web diff reads correctly and is pinned by 30 tests, but the eight backend files the kickoff names as changed since the last review were never fetched (sandbox clone stalled), so that half is unvou…
quality 100/100 · no findings · tests partial · risk medium

Adds the Google Cloud integration card: catalog entry, connect form, per-connection log and metrics status rows with switches, and the setup/cleanup script panels, all over the existing /v2/integrations/gcp API. The web half matches the contract and its own tests; the backend files named as changed since the last review could not be read in this pass.

  • gcp-connector-state.ts derives log, metrics and attention state and builds the create payload from the API schema
  • GcpIntegrationCard lists connections, flips one switch per PATCH, and reminds the admin to re-run the script
  • Catalog gets the gcp entry, hub status and overview; useIntegrationOverviews counts connectors receiving data
  • GoogleCloudIcon gains a GoogleCloudMonoIcon in currentColor
What was checked
  • Create payload is rebuilt per scope variant and trimmed, matching V2GcpCreateConnectorRequest (gcp-connector-state.ts:132)
  • The setup script is fetched with a bare query and hidden while waiting, so a stale secret-bearing script is never copied (gcp-integration-card.tsx:364)
  • The script <pre> carries REPLAY_BLOCK_CLASS for the secret copy; the cleanup script does not, matching the API's no-secret response

09af2fb · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
Pure state machine is pinned by 30 unit tests; the card itself was never rendered in a browser, so its render paths are unverified.
quality 100/100 · no findings · tests covered · risk medium

Adds the Google Cloud card to the Integrations page: connect form, per-connection capability switches with a shared status model, setup and disconnect panels. Contained to apps/web and safe to merge; the new logic is unit-tested.

  • gcp-connector-state.ts derives log/metrics state, pending changes and switch locks from a connector
  • GcpIntegrationCard renders connect, per-connection switches, setup and guided disconnect
  • Catalog gains a gcp entry plus HEALTH_TONE (new pending health) and gcpStatusQuery
  • PlanetScaleSetupChecklist is generic over step ids and ReactNode details
What was checked
  • gcpCreateRequest narrows the payload per scope_type and rejects both-opt-ins-off (gcp-connector-state.ts:273)
  • useGcpScripts hides a held-over script while the new one loads, and is a bare non-retained query so the secret does not outlive the panel (card:256)
  • save sends only the flipped flag; updating disables every row's switches while one save is in flight (card:990)

8450b98 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
The connector-state rules that changed are pinned by unit tests; only the card's hardcoded docs link is wrong.
quality 90/100 · 1 warning · tests covered · risk medium · 1/1 new units observable

The last commits refine the Google Cloud card: capability states, the setup panel's confirmation, and a stacked checklist layout. Presentational and safe to merge, except the card's hardcoded docs link, whose page does not exist.

  • needsSetup keeps a removed capability in Setup pending even while old data is fresh
  • An incomplete resource sync now shows under Metrics and resources instead of failing the row
  • The setup panel confirms only on a script run newer than when it opened
  • PlanetScaleSetupChecklist gains a stacked layout for sentence details

Findings

🟠 Warning · F1 · GCP card hardcodes a docs URL whose page does not exist

correctness · apps/web/src/components/integrations/gcp-integration-card.tsx:98

apps/landing/src/content/docs/integrations/ has no gcp.md at this head, so the connect form's Costs link (${DOCS}#google-cloud-costs) 404s. The same commit dropped docsUrl: docsUrl("gcp") from the catalog entry, so apps/web/src/lib/docs.test.ts — which exists to fail in the PR that would rot a docs link into a 404 — no longer covers this page.

Add the landing page (`apps/landing/src/content/docs/integrations/gcp.md`), add `gcp: "/docs/integrations/gcp"` to `DOCS` in `apps/web/src/lib/docs.ts`, and go back to `docsUrl("gcp")` here and on the catalog entry. If the page is not shipping with this stack, drop the `Costs` link instead of hardcoding it.
🤖 Prompt to fix this finding with an AI agent
Findings from an automated review of commit a2e26791f944d2eb432f116222fa5009fa99adb5. Verify each one against the current code before changing anything, fix only those that still apply, and keep each fix to the lines it names.

---

F1 · Warning · correctness · apps/web/src/components/integrations/gcp-integration-card.tsx:98
GCP card hardcodes a docs URL whose page does not exist
`apps/landing/src/content/docs/integrations/` has no `gcp.md` at this head, so the connect form's `Costs` link (`${DOCS}#google-cloud-costs`) 404s. The same commit dropped `docsUrl: docsUrl("gcp")` from the catalog entry, so `apps/web/src/lib/docs.test.ts` — which exists to fail in the PR that would rot a docs link into a 404 — no longer covers this page.
Suggested fix: Add the landing page (`apps/landing/src/content/docs/integrations/gcp.md`), add `gcp: "/docs/integrations/gcp"` to `DOCS` in `apps/web/src/lib/docs.ts`, and go back to `docsUrl("gcp")` here and on the catalog entry. If the page is not shipping with this stack, drop the `Costs` link instead of hardcoding it.
What was checked
  • The new needsSetup branches and resourcesError shape are pinned by the added cases in gcp-connector-state.test.ts
  • Messages with console links read correctly through the new GcpMessage (checked against the wording in GcpMetricsService.ts:87)
  • Browser queries already carry client spans through tracedFetch (apps/web/src/lib/services/common/telemetry.ts:112)
Observability coverage: 1 of 1 changes observable
Change Kind Observable Evidence
GET /v2/integrations/gcp/status and setupScripts (browser atom queries) Client (browser fetch) yes apps/web/src/lib/services/common/v2-atom-client.ts uses MapleFetchHttpClientLive, i.e. tracedFetch (telemetry.ts:112), which sets peer/status and traceparent

a2e2679 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot maple-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 inline note from Maple's review. The score and summary are in the review comment above.

/** How much of a script shows before "Show all lines": the wrapper and the header comment. */
const SCRIPT_PREVIEW_LINES = 10

const DOCS = "https://maple.dev/docs/integrations/gcp"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

GCP card hardcodes a docs URL whose page does not exist

F1 · Warning · correctness

apps/landing/src/content/docs/integrations/ has no gcp.md at this head, so the connect form's Costs link (${DOCS}#google-cloud-costs) 404s. The same commit dropped docsUrl: docsUrl("gcp") from the catalog entry, so apps/web/src/lib/docs.test.ts — which exists to fail in the PR that would rot a docs link into a 404 — no longer covers this page.

Add the landing page (`apps/landing/src/content/docs/integrations/gcp.md`), add `gcp: "/docs/integrations/gcp"` to `DOCS` in `apps/web/src/lib/docs.ts`, and go back to `docsUrl("gcp")` here and on the catalog entry. If the page is not shipping with this stack, drop the `Costs` link instead of hardcoding it.
🤖 Prompt to fix with an AI agent
In `apps/web/src/components/integrations/gcp-integration-card.tsx:98`: GCP card hardcodes a docs URL whose page does not exist.

`apps/landing/src/content/docs/integrations/` has no `gcp.md` at this head, so the connect form's `Costs` link (`${DOCS}#google-cloud-costs`) 404s. The same commit dropped `docsUrl: docsUrl("gcp")` from the catalog entry, so `apps/web/src/lib/docs.test.ts` — which exists to fail in the PR that would rot a docs link into a 404 — no longer covers this page.

Suggested fix: Add the landing page (`apps/landing/src/content/docs/integrations/gcp.md`), add `gcp: "/docs/integrations/gcp"` to `DOCS` in `apps/web/src/lib/docs.ts`, and go back to `docsUrl("gcp")` here and on the catalog entry. If the page is not shipping with this stack, drop the `Costs` link instead of hardcoding it.

Verify the problem exists at that location before changing it, and keep the fix to those lines.

@maple-review-bot

maple-review-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
Pure state model is pinned by 544 lines of tests; the card around it, including the setup script's replay-block guard, has none.
quality 98/100 · 1 note · tests partial · risk low

Adds the Google Cloud integration card and catalog entry to /integrations on the existing /v2/integrations/gcp API, with a pure, well-tested state model shared by the card, hub and header. UI-only and contained; the still-open item is the untested replay-block guard on the script preview.

  • Google Cloud catalog entry, hub row and connect form on /integrations
  • gcp-connector-state.ts derives every capability and connection state, shared by card, hub and header
  • PlanetScaleSetupChecklist becomes generic over step id and takes a stacked layout
  • Removed-connection cleanup panels persist per org through Atom.kvs

Still open from earlier reviews

What was checked
  • Persisted cleanup script carries no secret: the delete response renders it without a push endpoint (GcpConnectorService.ts:386), asserted by notInclude(..., "maple_gcp_")
  • The card's both-switches-false cleanedUp check can complete for a metrics-only connection: the cleanup script reports "logs":false,"metrics":false (setup-scripts.ts:774)
  • gcpStatusQuery filters by org through the existing v2 client, and status/scripts/update/delete all go through MapleApiV2AtomClient (gcp-integration-card.tsx:273), so no new inbound or outbound u…

7e4eecb · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

A run that stopped before a capability asks for the script again, the wrong-ID remedy does not
claim the script names the ID, and a read that stays out says when to write to support.
@maple-review-bot

maple-review-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
Since the last review only card copy and the runScript string changed; the untested rr-block guard on the secret-bearing script stays open.
quality 98/100 · 1 note · tests partial · risk medium

Wording-only pass over the Google Cloud card: the setup and failure copy, and the "run the script again" hint now keyed on any reported run instead of per capability. Safe to merge.

  • runScript says "again" whenever any run reported, not per capability
  • Metrics overdue copy points at support@maple.dev
  • Setup copy reworded for a connection with a wrong ID

Still open from earlier reviews

What was checked
  • runScript reaches only the setup-pending/setup-running branches (gcp-integration-card.tsx:826 and :889), so dropping the per-capability argument changes no other state
  • reportedAt is saved.setup_reported_at (:1117), set on every run, so the new text covers a run that stopped before a capability
  • REPLAY_BLOCK_CLASS still sits on the script <pre> (:226) and no test asserts it, unlike the repo's other secret surfaces

e697643 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

…sk before including them

The Log filter select lists the recommended filter first and starts a connection without a sink on it. Choosing Include GKE container logs shows an acknowledgement where the script would be: the script is fetched with that filter only after it is confirmed, and choosing the option again asks again. The form, the empty state and the filter's helper text say that GKE container logs are left out by default.
The confirm button says that it shows the script, backing out returns to the filter the panel started on (the sink's own filter when one exists), and a filter that replaces a sink's filter says so. Labels fit at 390px, and a link's icon stays with its last word.
@maple-review-bot

maple-review-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
State rules are pinned by a 596-line test; the one open item is the earlier note that the card's rr-block guard is untested.
quality 98/100 · 1 note · tests partial · risk medium

Adds the Google Cloud integration card: catalog entry, connect form, per-capability switches and status rows, setup and disconnect panels, all driven by the pure, tested gcp-connector-state module. No backend or contract change, so the web surface is safe to merge.

  • gcpConnectionState/gcpLogState/gcpMetricsState drive the card, hub row and page header
  • Connect form validates IDs with the API's own schema before submitting
  • Setup and disconnect panels run on the shared setup checklist with the generated scripts
  • removedGcpConnectorsAtomFamily keeps a removed connection's cleanup script across reloads

Before merge

Still open from earlier reviews

775897a · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

…up steps and the script on request

Layout, spacing and hierarchy of Integrations -> Google Cloud. Content, state rules and the API
stay as they are.

- One 768px column like the settings pages: a "Connections" section with a card per connection,
  and the connect form as its own "New connection" section. The page header ends with the column.
- Setup steps of the card's own: numbered, one filled button per step, the script text and the
  log filter opened on request. A first setup leads with its steps; a later run has them under
  the switches, in one band with the notice that asks for it. A connection that waits on a
  change opens on its steps after a reload too.
- Small print keeps to 72 characters; inputs, the select, notices and the script span their
  container. Names are 14px, explanations brighter than fine print.
- A capability is its name and switch over its status line; what to do is said once per
  connection. A connection that is not healthy carries its state as a badge, and its buttons
  sit beside the name on a wide card and under it on a narrow one.
- A failure's bracketed answer from Google goes on a line of its own; a command breaks between
  its words only; a named link stays on one line.
- The value tiles break on the page's width, so they stack beside two sidebars.
- The setup checklist is PlanetScale's alone again.
@maple-review-bot

maple-review-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
Read the whole card plus the three smaller diffs at this head; the state rules it leans on are unchanged and tested, and only the carried-over untested replay guard is open.
quality 98/100 · 1 note · tests partial · risk low

Reworks the Google Cloud card's status lines, setup panel and empty state, and retires PlanetScale's generic checklist API. No new defect found in the files changed since the last review, so it is safe to merge once the stacked base branches land.

  • Status renders each part in its own wrapping span with a · separator.
  • GcpMessage moves a trailing (...) into a second muted paragraph.
  • Script shows a line count and an optional note; Command wraps between words.
  • PlanetScaleSetupChecklist drops stacked and the generic ChecklistStep.

Before merge

Still open from earlier reviews

What was checked
  • @2xl/page resolves: PageLayout.Content declares @container/page (packages/ui/src/components/ui/page-layout.tsx:286).
  • Ran the new bracket regex from GcpMessage on the real connector messages: prose kept, (Cloud Monitoring returned …) split into its own paragraph.
  • A first setup's steps (stepsFirst) render above the switches and are not duplicated by the notice band (line 1476).

d437061 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
The rewritten state module and both new components read clean here, but no component test exercises the configure or disconnect flows.
quality 98/100 · 1 note · tests partial · risk medium

Adds the Google Cloud integration page: catalog entry, per-connection cards, and a two-stage configure dialog that generates, copies and polls on the setup and cleanup scripts. New web UI over the existing /v2/integrations/gcp API, no contract change; safe to merge once the untested replay guard is covered.

  • GcpConfigure runs a choose → apply dialog that fetches the script and polls until a run reports
  • gcp-connector-state.ts derives each capability's state and a connection's worst state
  • GcpDisconnectDialog holds Disconnect until the cleanup script is seen to report
  • A removed connection keeps its cleanup script in local storage until dismissed

Before merge

Still open from earlier reviews

What was checked
  • REPLAY_BLOCK_CLASS wraps the script pre (gcp-configure.tsx:324), so the embedded connector secret stays out of rrweb replays
  • useGcpScripts uses the bare atom query, not retainedQueryV2, so the secret-bearing scripts are not kept past unmount (gcp-configure.tsx:394)
  • Both new components were read in full from the head checkout; the card and configure diffs were truncated at their tails, not skipped

6e37942 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

…he cleanup script; panel first in the dialog body
@maple-review-bot

maple-review-bot Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
The two files changed since 6e37942 are copy plus a branch reorder that renders the same stage; the earlier missing rr-block test is untouched and still open.
quality 98/100 · 1 note · tests partial · risk medium · 1/1 new units observable

Since the last review the Google Cloud card changes are copy (EffectNote's second wording, the cleanup panel) and a reordering of GcpConfigure's stage branches that renders the same panel for every reachable target. Safe to merge; the one open finding, the untested replay-block guard around the script, is untouched.

  • EffectNote takes scripted and stops promising a script when a save leaves nothing to apply
  • Cleanup panel and setup-pending copy reworded on the connection card

Still open from earlier reviews

What was checked
  • GcpConfigure's reordered stage branches are equivalent: connector is undefined for every target.kind === "new" (gcp-configure.tsx:1280)
  • New outbound calls stay traced: the web v2 client opens Effect.withSpan("http.client") (lib/services/common/telemetry.ts:170)
  • No test covers the GCP Script component, the only place the script's rr-block guard lives (gcp-configure.tsx:324)
Observability coverage: 1 of 1 changes observable
Change Kind Observable Evidence
Google Cloud connector mutations and setup-scripts fetch (web) outbound call yes client HTTP spans via Effect.withSpan("http.client") at apps/web/src/lib/services/common/telemetry.ts:170

74d403c · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 9/10 · safe to merge
Three lines of copy and layout on a page already reviewed; the only open item is F2, unchanged at this head.
quality 98/100 · 1 note · tests partial · risk low

Safe to merge: three lines of copy and layout on the Google Cloud page (the apply recap drops the log-filter row once Google Cloud matches, a stalled metrics warning takes the card's width). The open item, the setup script's rr-block guard having no test, still stands.

Still open from earlier reviews

What was checked
  • The delta since 74d403c is exactly three lines: one copy clause, && !confirmed, and metrics.kind === "stalled" in hinted
  • confirmed (gcp-configure.tsx:1044) is computed above the recap dl, and the steps render only when !confirmed (gcp-configure.tsx:1077), so the new gate pairs the filter row with a visible scr…
  • F1's docs URL is gone: no docsUrl on the gcp catalog entry, and no #google-cloud-costs link anywhere in the page

a7262b9 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

…ibling cards

The loading skeleton takes the panel radius and the connect button's icon
takes its size from the button, as on every other integration card.
@maple-review-bot

maple-review-bot Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
The new rules module is pinned by 739 lines of tests, but the components rendering it (card, configure, disconnect) have none, which is why F2's rr-block guard stays open.
quality 98/100 · 1 note · tests partial · risk medium

Adds the Google Cloud integrations page: catalog entry, hub row, a worst-state card per connection, a two-stage Configure dialog ending in the Cloud Shell script, and a cleanup-first Disconnect. The rules module is well tested and every mutating path stays behind the org-admin gate; the earlier F2 finding still stands.

  • GcpIntegrationCard renders one Panel per connection, worst state first
  • GcpConfigure splits a saved change from the Cloud Shell script into two stages
  • GcpConnection puts cleanup first on Disconnect, keeping the script until dismissed

Still open from earlier reviews

4bb6cbe · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

As the primitives pass did on the sibling cards: the text link that shows the
script is a Button with the link variant, and the icon in Open Cloud Shell
takes its size from the button.
@maple-review-bot

maple-review-bot Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
The only new hunk is a link-toggle refactor into a native button; the secret-bearing script's replay guard still has no test.
quality 98/100 · 1 note · tests partial · risk low

Since the last review the head only turns the "Read the script" toggle into the shared link Button and drops the explicit icon size; both stay presentational, so the page is safe to merge. The one open test gap on the script's replay guard is untouched.

  • GcpConfigure runs a two-stage connect or configure dialog ending in the setup script
  • ApplyStage waits for a new setup_reported_at before saying Google Cloud matches
  • Script hides the pasted script behind rr-block and a Read/Hide toggle
  • GcpDisconnectDialog runs the cleanup script before removing the connection

Before merge

  • Manual · Merge the stacked #1320, #1321 and feat/gcp-metrics-poller branches first: the page has no /v2/integrations/gcp API without them

Still open from earlier reviews

What was checked
  • New toggle still renders a native button with type="button" (packages/ui/src/components/ui/button.tsx:69), so it cannot submit a form
  • ConfirmDialog keeps itself open when save resolves false (packages/ui/src/components/ui/confirm-dialog.tsx:74), so a failed save is retryable
  • gcpScriptNeeded/gcpSetupRunning gate confirmed on the connector's own flags, so the apply step cannot claim success early

47294ac · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@JeremyFunk
JeremyFunk added this pull request to stack #1373 October 10, 2026 14:28
# Conflicts:
#	apps/web/src/routes/integrations.tsx
@maple-review-bot

maple-review-bot Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
Read the whole diff; the untested rr-block guard on the setup script is the one open gap, and I checked it against the rrweb blockClass convention.
quality 98/100 · 1 note · tests partial · risk medium

Adds the Google Cloud integration page: one panel per connection with its two capabilities' state, and a single Configure dialog that saves what to collect, hands over the setup script, and keeps the cleanup script for a removed connection. Client-only, no contract change; the state rules carry a large unit suite.

  • Catalog entry, hub row and page header state for Google Cloud
  • GcpConfigure: a configure stage then an apply-script stage, one per connection
  • gcp-connector-state.ts derives capability state, pending changes and draft effects
  • Removed connectors keep their cleanup script in org-scoped local storage

Still open from earlier reviews

What was checked
  • @2xl/page on the empty-state grid resolves: PageLayout.Content declares @container/page (packages/ui page-layout.tsx)
  • The setup script's plain text stays under rr-block (gcp-configure.tsx:328), rrweb's default blockClass
  • The new 10s/60s poll cannot reset each clock tick: useIntervalRefresh deps are refresh, intervalMs, enabled (use-interval-refresh.ts)

0590969 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
The pure state machine is pinned by its own test file; the card and dialog wiring is not.
quality 98/100 · 1 note · tests partial · risk medium

Adds the Google Cloud page to Integrations — catalog entry, hub row, one panel per connection and a two-stage Configure/Apply dialog with cleanup-first Disconnect — on the existing /v2/integrations/gcp API, with no backend or contract change. Safe to merge; the open test gap on the setup script's replay guard is unchanged at this head.

  • gcp-connector-state.ts derives each capability's state, the script to ask for, and what a draft change does
  • GcpIntegrationCard shows one panel per connection, worst state first, with the script band and cleanup-first Disconnect
  • GcpConfigure runs Connect/Configure > Apply, saving flags then waiting on the script
  • Hub row and page header read the connection's worst state; pending is neutral and not counted

Still open from earlier reviews

What was checked
  • setupScripts is a POST whose payload carries log_filter and the route reads payload.log_filter (integrations-gcp.http.ts:101), matching useGcpScripts's payload
  • gcpScopeRoles names the same roles the script itself checks (setup-scripts.ts:66, :72)
  • Atom.kvs with localStorageRuntime follows the existing useQuickStart read/set pattern; the delete response's cleanup script carries no secret

7d0a5db · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@maple-review-bot

maple-review-bot Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge
The state machine is well tested, but the script's replay-privacy guard still has no test and the two icon files went unread.
quality 98/100 · 1 note · tests partial · risk medium

Adds the Google Cloud integrations page: catalog entry, per-connection status, a two-stage Configure dialog and a disconnect flow that keeps the cleanup script until dismissed. The diff is client-side only, built on the existing /v2/integrations/gcp contract; one earlier tests gap is still open.

  • gcp-connector-state derives connection state, pending script work and status text from a connector row
  • GcpConfigure runs Connect/Configure then Apply, with the setup script only in stage 2
  • GcpIntegrationCard renders one panel per connection and keeps a removed connection's cleanup script in localStorage
  • integration-catalog adds the Google Cloud entry and its hub overview

Before merge

Still open from earlier reviews

What was checked
  • Delete returns cleanup_script and no push secret (apps/api/src/routes/v2/integrations-gcp.http.ts), so the script kept in localStorage is not a credential
  • gcpMessageParts cuts the real API error texts (plan-limit, billing, no-log-entry) without rewording, pinned by tests
  • No new outbound call or entrypoint: the page reads and mutates through the existing v2 atom client

fa6b703 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant