Skip to content

chore(config-ui): sync with upstream apache/devlake - #83

Merged
muzamilkm merged 49 commits into
arbisoft:main-arbisoftfrom
muzamilkm:chore/config-ui-upstream-sync
Oct 6, 2026
Merged

muzamilkm merged 49 commits into
arbisoft:main-arbisoftfrom
muzamilkm:chore/config-ui-upstream-sync

Conversation

@muzamilkm

@muzamilkm muzamilkm commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Syncs config-ui with upstream Apache DevLake, as the sync plan lays out (config-ui-upstream-sync-plan.md, sections 2–7). It cherry-picks the 47-commit ledger in chronological order with -x and ports our fork-only code to the new stack: React 19, antd 6, React Router 7, Vite 8, TypeScript 6, Node 24, Yarn 4, ESLint flat config and Vitest. It also brings dark mode (#8865) and connection grouping (#9130), the foundations of the reskin. The e2e suite from #81 runs green on the new stack in both auth states.

Upstream cherry-picks

41 of the 47 ledger commits, in upstream order. Each keeps the upstream author, body and its (cherry picked from commit …) line. Numbers are upstream apache/devlake PRs.

Stack and theme

PR What How
#8865 Dark theme, theme/tokens.ts, colour refactor Whole
#9006 React 19, antd 6, Router 7, Vite 8, TS 6, Node 24, Yarn 4, ESLint flat config, Vitest Whole, then our fork code ported (below)
#9020 Dark-mode copy contrast Whole
#9130 Group connections by name Whole

Fixes and features for plugins we ship

PR What How
#8931 #8972 #9035 Jira: search API, extra JQL, project name in JQL With backend
#9024 #9159 Jira: API Gateway auth, Cloud OAuth 2.0 With backend
#9034 #9047 Duplicate-scope warning: GitHub, GitLab/Bitbucket With backend
#9014 #9152 Azure DevOps Server (on-prem), run name in pipeline regex With backend
#8935 gh-copilot hyphenated enterprise slugs With backend
#8918 #8952 #8995 Connection create: empty-plugin guard, "create a new connection", initialValues Whole
#8903 #9153 #9135 "Jira Data Center" label, GitLab pathWithNamespace, scopeId encoding Whole
#9097 #9144 PyDevLake deprecation notice #9097 UI only, #9144 whole
#9166 VITE_DEVLAKE_URL dev proxy Whole
#9093 incubator prefix removal UI only (links, banner, .tool-versions)

New upstream plugins, UI only

#8877 Rootly · #8884 Tempo · #8900 Linear · #9009 ClickUp · #9023 incident.io · #9076 Kiro · #9160 Grafana IRM · #9169 YouTrack

These stay hidden: the UI lists only plugins the backend reports, and ours doesn't ship them.

Dependencies and images

#8940 #9100 #9188 nginx · #9044 images and frontend deps · #9112 #9113 #9114 #9121 #9158 frontend bumps. Each yarn.lock is regenerated with Yarn 4.17.0 rather than merged by hand.

Not taken

PR Why
#8878 #9079 #9084 dbt / q-dev changes; our backend still ships both plugins
#9017 Upstream's cursor collides with ours
#9131 Upstream CI only
#8808 claude_code, already in via #79; resolves entirely to ours, so no commit
  • No prerequisite backend commits were pulled. #8935 builds and passes its tests without upstream's user_teams_collector.go. #9159 registers only its own OAuth migration.
  • The post-rename commits (#9159, #9152) have their imports rewritten to github.com/apache/incubator-devlake/.
  • Rewritten subjects: 7 upstream subjects don't pass our commit-message check, so only their first line was rewritten (e.g. fix(gitlab) - fix added… → fix(gitlab): …). The body and the cherry picked from line are unchanged.

Conflicts resolved toward ours

  • connection-form/index.tsx: our inline Test Connection payloads and payload.ts stay. Upstream's new fields are added to both: enterprise (#8935) and cloudId (#9159). So is YouTrack's opt-in test-result message (#9169).
  • utils/request.ts: our session verification, CSRF and 428 handling stay. Upstream's #9159 change is added: a 401 from a plugin connection test no longer counts as a DevLake session expiry.
  • routes/layout/layout.tsx and config.tsx: our account menu, OtelAttention, /access entry and Grafana login link stay. The theme toggle is added. Upstream's unused GRAFANA_PATH is dropped.
  • routes/connection/connections.tsx: our Claude/OTel cards and credential counts stay. Grouping, the A–N / O–Z split by displayed name and the deprecation alert come from upstream.
  • plugins/utils.ts: getPluginScopeId lives in our plugins/scope-id.ts, so the Linear (teamId) and ClickUp (folderId) cases go there. api/scope encodes scopeId, and scope-id.ts doesn't, so it's encoded exactly once.
  • data-scope-select: our rewrite stays, with upstream's ?? [] guards from #9014 re-applied.
  • vite.config.ts: upstream's file, plus our Grafana OAuth proxy entries.
  • package.json: upstream's, plus @playwright/test, test:e2e and test:e2e:ui. yarn.lock is regenerated with Yarn 4.17.0 rather than merged by hand.
  • Compose and Dockerfiles (#9044):
    • upstream image pins where ours were older;
    • ours where they were equal or newer (grafana/Dockerfile 13.2.2 and its provisioning lines);
    • files we had deleted stay deleted.

Fork code on the new stack

  • antd 6, in fork-owned files only:
    • destroyOnClose → destroyOnHidden;
    • maskClosable → mask={{ closable: false }};
    • Space direction → orientation;
    • Alert message → title;
    • Input addonAfter → Space.Compact.
    • Upstream-owned lines are left as upstream wrote them.
  • React 19: argument-less useRef<T>() calls become useRef<T | undefined>(undefined).
  • ESLint flat config:
    • .eslintrc.js and e2e-tests/.eslintrc.cjs are gone;
    • no-console: 'warn' moves to eslint.config.mjs;
    • an e2e-tests/** block turns off react-hooks/rules-of-hooks for Playwright's use fixture;
    • the ASF header is now enforced by eslint-plugin-headers.
  • Unit tests: our 10 node --test files are ported to Vitest with identical test and assertion counts, and tsconfig.test.json is deleted. yarn test runs upstream's and ours together.
    • One assertion was stale: access/utils.test.ts expected a disabled OIDC provider to show as Configured. c98969b4b deliberately added the Disabled state, and the test never ran because the old runner failed at tsc first. It now expects Disabled.

E2E

  • antd 6 dropped .ant-modal-content. support/selectors.ts now finds modals by accessible role (getByRole('dialog', { name })), which also survives the reskin.
  • Empty states. antd 6 Empty renders its text twice, so empty states get their own selector.
  • OTel organization column. antd 6 now truncates Typography.Text ellipsis in JS and keeps the full value only in aria-label. The test reads the cell's accessible name and still requires an exact match with the API's organizationId. On screen nothing changed: it's a truncated UUID with a copy button, as before.
  • New shell/theme spec (sync plan, section 8.4):
    • light, dark and follow-system each apply the right background;
    • the mode persists across reloads;
    • follow-system tracks the OS preference.

Other

  • chore(grafana): the Claude dashboard is titled "Claude Usage" instead of "Claude - MySQL".

Test plan

  • Rebuilt devlake and config-ui locally from this branch with FORCE_MIGRATION=true:
    • exactly the 6 new migrations ran (Jira 3, Azure DevOps Go 3), with no errors;
    • both images build and serve.
  • Local auth on: 64 passed, 2 skipped, 0 failed, about 2 minutes. The 2 skips are the state-A auth specs.
  • Local auth off (AUTH_LOCAL_ENABLED=false): 40 passed, 24 skipped, 0 failed, identical to main-arbisoft. The skips are exactly the local-auth specs.
  • Config UI:
    • tsc --noEmit: 0 errors;
    • eslint .: 0 errors;
    • yarn test: 16 files, 91 tests passed;
    • yarn build;
    • yarn install --immutable.
  • Backend: go build and go test pass for jira, github, gitlab, bitbucket, azuredevops_go and gh-copilot (the DB-backed e2e packages run in CI). gitextractor needs libgit2 and compiles in the backend image.
  • No github.com/apache/devlake/ imports remain. Every new migration is registered, and none collides with a fork migration.
  • Every upstream field in connection-form's test and save payloads is present in ours (scripted diff against upstream).
  • Dark mode checked on /login, /access, /otel, /connections, /keys, projects and the account menu: everything is readable.
  • The 8 upstream-only plugins don't appear in the catalog (connections/catalog spec).

Notes for reviewers

  • Node 24 and Yarn 4 for everyone working on config-ui. Run corepack enable; the Yarn release is vendored under .yarn/releases. Node 18 and Yarn 3 no longer work.
  • New migrations run on deploy: Jira (sub_query, extra_jql, OAuth 2.0 credentials) and Azure DevOps Go (endpoint, username, run_name). They're upstream migrations, but take a backup before deploying, as usual.
  • yarn start dev proxy: Grafana now defaults to localhost:3001. Override it with VITE_GRAFANA_PROTOCOL / _HOST / _PORT if yours runs elsewhere.
  • The diff is large because of #9006. Reviewing commit by commit is easier: our own commits are 227097827, bf0e167cf, d337cfed5, 1504fa137, 023691887, 2c8f1224a, 8a3dd355e and 3fcda8bfb. The rest are upstream picks.
  • Out of scope (sync plan, section 10):
    • the full backend sync;
    • the Cursor convergence;
    • removing q-dev and dbt;
    • adopting the new upstream plugins' backends.

rbstp and others added 30 commits October 5, 2026 16:49
Add a system-aware dark theme with a header toggle (light, dark, system) that persists in localStorage. All colors now flow through `src/theme/tokens.ts` into both the antd component library and styled-components, replacing hardcoded hex across `styled.ts` files and inline styles. Light mode is preserved the same as before.

apache#8863
(cherry picked from commit ac73e27)
* feat(rootly): scaffold plugin skeleton

Add the plugin entry point, impl shell with all required plugin
interfaces except DataSourcePluginBlueprintV200 (wired in U2),
connection model with Bearer auth, service + scope-config + placeholder
incident/user/assignment models, and the initial migration script. API
resources and subtasks are intentionally empty and will be populated by
U2-U5.

* feat(rootly): add API handlers and blueprint v200

Wire up connection test, remote scope list/search, scope CRUD, scope
sync state, and blueprint v200 endpoints. Remote scope listing speaks
JSON:API and page-based pagination to match the Rootly API shape.
TestConnection validates the bearer token via GET /users/current.
impl.go now wires api.Init and restores DataSourcePluginBlueprintV200
so the plugin can produce pipeline plans for selected Rootly services.

* feat(rootly): collect and convert services to domain boards

Add services_collector, services_extractor, and service_converter
subtasks. Collector fetches GET /services/{id} for the scoped service,
unwraps the JSON:API envelope, and populates _tool_rootly_services.
Converter emits one ticket.Board per service using the standard
domain-id generator, feeding into the existing TICKET pipeline.

Also harden remote-scope pagination termination to key off the page
we requested rather than meta.current_page so a response missing that
field does not silently truncate the service list.

* feat(rootly): collect and extract incidents with inline users

Finalize the Incident and User models and add role-specific user-id
fields (creator, started_by, mitigated_by, resolved_by, closed_by)
directly on the Incident row. Add the incidents_collector and
incidents_extractor subtasks. The collector is single-phase,
filter[services]-scoped and filter[updated_at][gt]-incremental; the
extractor unwraps the JSON:API envelope and pulls inline nested user
objects from the incident attributes, emitting deduplicated User rows
per incident.

Drop the Assignment table entirely. Rootly's incident data model is
role-per-lifecycle-event, not a list of assignees, so PagerDuty's
n-assignees shape does not fit. The schema and GetTablesInfo are
adjusted accordingly.

* feat(rootly): convert incidents to domain issues

Add incidents_converter. For each tool-layer incident, emit a
ticket.Issue (Type=INCIDENT) with status, priority, lead time, and
resolution date derived from the corresponding Rootly fields; emit one
ticket.IssueAssignee per distinct role user (creator, started_by,
mitigated_by, resolved_by, closed_by); and emit a ticket.BoardIssue
linking the incident to its service board. This feeds DevLake's
existing DORA pipeline so change-failure rate and MTTR compute
correctly for teams running on Rootly.

Unknown incident statuses fall back to IN_PROGRESS with a warning log
rather than panicking (a deliberate divergence from the PagerDuty
plugin, motivated by Rootly's more volatile status enum). Severity
mapping accepts case-insensitive sev0-sev4; unknown severities are
preserved as-is.

Guard computeLeadTime against resolved-before-started timestamps (clock
skew or backfill anomalies) by returning nil rather than the wraparound
garbage a naive uint() cast would produce. Tighten test coverage on the
dedup, key-fallback, and known-status-warning boundaries flagged during
code review.

* test(rootly): add e2e test for extract and convert pipeline

Add an end-to-end test that drives the extract and convert subtasks
over a crafted raw-incident fixture and verifies the tool-layer and
domain-layer output against snapshot CSVs. Fixtures cover every branch
of the status and severity mapping tables, the same-user-across-roles
dedup path, the zero-user case, and the safety-net filter that drops
incidents whose relationships point at a different service than the
one the task was scoped to.

* feat(rootly): register plugin in backend and config-ui

Add rootly to the backend plugin startup test and the table-info test
so CI exercises it alongside the other plugins. Register RootlyConfig
in the config-ui plugin list so operators can create connections,
browse scopes, and run blueprints through the UI.

The cloud endpoint default includes the /v1/ API version prefix,
which is what Rootly's REST API actually expects; without it requests
land on the marketing site and return 404. The DOC_URL entries point
at a Configuration/Rootly docs page that still needs to be written.

Use the Rootly wordmark glyph as the plugin icon, rewritten as a
fill-aware (currentColor) SVG so the config-ui can recolor it for
selected/unselected states the same way it does every other plugin
icon.

* fix(rootly): align archived models with live model schemas

The U1 init migration's archived Connection, Service, and ScopeConfig
models were missing columns contributed by the live models' embedded
helpers, so AutoMigrate produced tables the live models could not
read or write. Each gap surfaced as an "Unknown column" error from
MySQL the first time the table was touched:

- Connection was missing endpoint, proxy, rate_limit_per_hour
  (contributed by helper.RestConnection on the live struct).
- Service was missing scope_config_id (contributed by common.Scope).
- ScopeConfig was missing connection_id and name (contributed by
  common.ScopeConfig, which the archived base type does not include).

Fold the missing fields into the archived models so a single init
migration produces the correct schema. Since rootly has not been
deployed anywhere, keeping one init migration is cleaner than
chaining follow-up ALTERs; a fresh migrate creates the correct
tables in one pass.

* fix(rootly): align API contract with real Rootly /v1 responses

The original plugin shape was built from docs summaries rather than an
actual response capture and diverged from the Rootly API in ways that
silently produced zero incidents. Reconcile every code path with
ground truth from the OpenAPI spec and a captured GET /v1/incidents
response:

- Connection test hits /users/me (Rootly's real "who am I" path); the
  original /users/current returns 404.
- Incident list filter is filter[service_ids]=<uuid>, not
  filter[services]=<uuid>. The latter exists but accepts names and
  silently matches nothing for a UUID.
- Role-bearing user fields (user, started_by, mitigated_by,
  resolved_by, closed_by) and severity are JSON:API response
  envelopes nested on attributes: {"data":{"id":...,"attributes":...}}.
  The previous flat NestedUser / SeverityAttrs shapes were reading the
  wrong paths, so those fields were always empty.
- Service membership lives on the sibling relationships block as
  JSON:API id+type pointers, not on attributes. The safety-net
  scope-filter check now reads from the right place.
- The incident resource does not have an urgency field. Drop the
  corresponding column from the model and archived schema.

Also harden the collector: split the ResponseParser / next-page logic
so pagination state is captured during parse (rather than re-reading
the already-drained response body in GetNextPageCustomData), and add
lightweight request/response diagnostics gated behind Debug logging.

Verified end-to-end against a live Rootly tenant: 3 of 6 scoped
services returned incidents, all 3 extracted and converted into
ticket.Issue rows with creator assignees and board linkage.

* style(rootly): trim narrative comments to match plugin conventions

Match PagerDuty's comment density. Keep the few comments that flag
non-obvious invariants (archived-base field overrides, 1-based
pagination, deliberate divergence from PagerDuty's panic-on-unknown
behavior, clock-skew guard).

* refactor(rootly): address code review feedback

  Apply fixes from a multi-lens code review pass:

  - API: rename swagger {serviceId} to {scopeId} to match registered
    route; remove dead Proxy handler.
  - Models: add Sanitize() on RootlyConn; add RoleUserIds() helper on
    Incident; index ServiceId; drop unused Url field on User; remove
    dead RootlyResponse/ApiUserResponse types.
  - Migrations: mirror live schema in archived models (index on
    service_id; drop user.url).
  - Collector: switch pagination to reqData.Pager.Page (avoids
    divide-by-zero), cap at 10000 pages, extract buildIncidentsQuery
    as a pure helper, drop unreachable lastPageEmpty branch and unused
    TotalCount, remove diagnostic logs; add unit test pinning the
    filter[service_ids] param literal as a regression guard.
  - Services: preserve ScopeConfigId across re-collections; declare
    ProductTables on collector and extractor metas.
  - Extractor: skip emitting User rows with neither name nor email so
    sibling scope tasks can fill in fuller data; use generic resolve()
    for SequentialId; type ServiceRef as a named struct.
  - Converter: consolidate mapStatus to return (mapped, known); use
    Incident.RoleUserIds() instead of an inline slice.
  - impl.go: comment justifying services-before-incidents subtask
    ordering.
  - e2e: rewrite raw incident fixtures to JSON:API envelope shape;
    regenerate snapshots (drop urgency column).

* feat(rootly): add rootly dashboard

* chore: run gofmt

* chore: add isBeta flag to rootly plugin

(cherry picked from commit aff3487)
* feat(tempo): add Jira Tempo Timesheets plugin

Adds plugin for ingesting worklogs from Jira Tempo (Tempo Timesheets) API v4.

Backend:
- Plugin entry point (impl/impl.go)
- Tempo API client with Bearer token auth (tasks/api_client.go)
- Data collectors, extractors, and converters for worklogs and teams
- Connection management API endpoints (api/)
- Database migrations for _tool_tempo_worklogs, _tool_tempo_teams
- E2E tests with CSV fixtures

Config-UI:
- Connection configuration UI (config.tsx)
- Plugin registration in index.ts

Dependency: requires Jira plugin for issue ID mapping.

Closes apache#8883

* fix(tempo): resolve CI failures on tempo plugin PR

- fix Apache license headers in 5 files (missing/typo content)
- move migration script to archived models pattern (forbidden import on plugins/tempo/models)
- register tempo in plugins/table_info_test.go
- drop unused validator var/import in api/init.go
- fix malformed issue_worklogs.csv snapshot (header/body column mismatch)

* fix(tempo): align e2e team fixtures with extractor expectations

The team extractor queries _raw_tempo_api_teams with the params serialized
from TempoApiParams{ConnectionId, TeamId}, expecting the raw fixture rows
to store each team as its own record with a single-object data payload.
The previous fixture wrapped both teams into a JSON array in the data
column and used only ConnectionId in params, causing TestTeamDataFlow to
find zero matching rows.

Also extend the _tool_tempo_teams snapshot with the _raw_data_* columns
that the test verifies via ColumnWithRawData.

---------

Co-authored-by: Fix Bot <fix@example.com>

(cherry picked from commit 9e659ab)
* feat(linear): add tool-layer models and init migration

Add the Linear plugin's tool-layer data models (connection, team scope,
scope config, account, issue, comment, issue label, workflow state, cycle,
issue history) and the initial schema migration with archived snapshots.

The connection authenticates with a personal API key passed verbatim in the
Authorization header (Linear uses no Bearer prefix).

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* feat(linear): add plugin skeleton, connection API and GraphQL client

Wire the Linear plugin entry point and implement all required plugin
interfaces (meta, init, task, api, model, source, migration, blueprint v200,
closeable). Add connection/scope/scope-config CRUD via the data-source helper,
a test-connection endpoint that runs a GraphQL viewer query, and a rate-limited
async GraphQL client that injects the API key via a bare Authorization header.

SubTaskMetas is intentionally empty; collectors are added per entity in
following commits.

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* feat(linear): collect, extract and convert users to accounts

Add the users GraphQL collector (paginated), extractor to
_tool_linear_accounts, and convertor to the domain crossdomain.Account
table, wired as the first three subtasks. Includes an e2e dataflow test
with raw fixtures and verified snapshots.

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* feat(linear): collect and extract workflow states

Add the team-scoped workflow states GraphQL collector and extractor into
_tool_linear_workflow_states. These states (backlog/unstarted/started/
completed/canceled) drive deterministic issue status mapping. Includes an
e2e test covering all five state types.

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* feat(linear): collect, extract and convert issues

Add the team-scoped issues GraphQL collector (incremental via updatedAt
ordering, inline labels), extractor to _tool_linear_issues and
_tool_linear_issue_labels, and convertor to domain ticket.Issue and
ticket.BoardIssue.

Status maps deterministically from Linear's WorkflowState.type
(backlog/unstarted->TODO, started->IN_PROGRESS, completed/canceled->DONE);
priority maps to its label; lead time falls back to resolution minus
creation. Includes an e2e test spanning all state types, unassigned issues,
issues without a cycle, and multi-label issues.

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* feat(linear): collect, extract and convert issue comments

Add a per-issue comments GraphQL collector (driven by an input iterator over
collected issues, with pagination), an extractor that recovers the owning
issue id from the raw input column, and a convertor to domain
ticket.IssueComment. Includes an e2e dataflow test.

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* feat(linear): convert issue labels to domain layer

Add the convertor from _tool_linear_issue_labels (populated inline by the
issue extractor) into the domain ticket.IssueLabel table. Includes an e2e
test covering issues with multiple labels and with none.

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* feat(linear): collect cycles and convert to sprints

Add the team-scoped cycles GraphQL collector and extractor, plus convertors
producing domain ticket.Sprint and ticket.BoardSprint (status derived from
completedAt), and ticket.SprintIssue linking issues to their cycle. Includes
an e2e dataflow test covering closed/active cycles and issues with/without a
cycle.

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* feat(linear): collect issue history and convert to changelogs

Add a per-issue history GraphQL collector (input iterator over issues, with
pagination), an extractor capturing state transitions including state types,
and a convertor to domain ticket.IssueChangelogs with mapped from/to status
values. Lead time is already derived from the issue's native
startedAt/completedAt. Includes an e2e test of a full
backlog->started->completed lifecycle.

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* test(linear): add blueprint v200 scope generation tests

Cover makeScopesV200: a team scope with the ticket entity produces the
expected domain board scope id, and a scope without the ticket entity
produces none.

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* docs(linear): add plugin README

Document the Linear plugin: supported entities, tool/domain mapping tables,
deterministic status mapping, priority/type/lead-time handling, API-key auth,
connection/scope/pipeline setup examples, rate limiting, and the roadmap
(OAuth, label-based type mapping, config-ui integration).

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* fix(linear): guard lead-time fallback against resolution before creation

A resolution timestamp (completedAt/canceledAt) earlier than createdAt —
from clock skew or migrated/imported issues — produced a negative duration
that, cast to uint, yields platform-dependent garbage (0 on arm64, ~1.8e19
on amd64). Skip the fallback unless the resolution is after creation so lead
time stays unset instead.

Adds an isolated e2e dataflow test with a fixture whose canceledAt precedes
createdAt, asserting lead_time_minutes is empty.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* fix(linear): map Linear triage state type to TODO

The WorkflowState.type 'triage' (the inbox state issues land in before being
accepted) previously fell through to OTHER, contradicting the documented total
mapping and silently mislabeling triage issues. Map it to TODO; keep OTHER as
the fallback for genuinely unrecognized types so unexpected API values surface.

Adds a unit test covering every documented state type plus triage and an
unknown value.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* refactor(linear): remove unused GraphqlInlineAccount struct

The struct was documented as the shared inline-user shape but was never
referenced; each collector declares its own inline user struct. Removing it
avoids misleading a maintainer into editing a type nothing reads.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* perf(linear): raise issue collector page size to 100

Every other Linear collector uses a page size of 100; issues used 50, which
doubled the number of issue-page round-trips and the iterator size that drives
the per-issue comment/history collectors. Linear permits first: 250.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* feat(linear): populate issue assignee/creator names and issue_assignees

The issue convertor set only assignee_id/creator_id, leaving the denormalized
assignee_name/creator_name columns blank and writing no issue_assignees rows,
so dashboards reading those columns or joining through issue_assignees showed
blank names. Preload account display names (matching the account convertor's
displayName-then-name rule) and emit an IssueAssignee per assigned issue.

The issue dataflow test now loads accounts before conversion and asserts the
names plus issue_assignees; the lead-time test flushes accounts to stay
order-independent on the shared test DB.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* fix(linear): clear stale sprint_issues when issues leave their cycle

Sprint membership is derived from each issue's cycle_id, and the batch divider
only deletes outdated rows when it produces at least one row of the type. When
every issue is moved out of its cycle the convertor emits nothing, so the
divider never fires and prior sprint_issues rows linger, leaving issues shown
in sprints they no longer belong to. Delete the team's sprint_issues up front
so the result is correct regardless of how many issues remain in a cycle.

Adds a two-run e2e test that empties every issue's cycle and asserts
sprint_issues is empty afterward.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* feat(linear): derive issue lead time from state-transition history

The LinearIssue.LeadTimeMinutes field was never populated, so lead time always
fell back to the coarse createdAt -> resolutionDate span. Derive it instead from
the recorded history: the span from an issue's first transition into an
in-progress state to its first transition into a done state thereafter (active
cycle time), which is the value that genuinely requires history. ConvertIssues
still seeds the fallback; ConvertIssueHistory now overrides it when the
transitions exist, and issues lacking them keep the fallback.

Adds an e2e test asserting issue-1 (started 05-02, completed 05-03) resolves to
1440 minutes from history rather than its 2880-minute created->resolved span.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* feat(linear): add remote-scopes endpoints to enumerate teams

Other first-party ticket plugins (jira, asana, github) expose
connections/:connectionId/remote-scopes so the config UI can browse and select
scopes from the API. Linear had none, forcing users to hand-craft a PUT /scopes
with raw team UUIDs they had no in-product way to discover. Wire the standard
DsRemoteApiProxyHelper + DsRemoteApiScopeListHelper and a lister that queries
the GraphQL teams connection (flat list, cursor-paginated) through the
connection's authenticated client.

Adds unit tests for the response->scope-entry mapping, the pagination cursor,
and the route registration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* perf(linear): make comment and history collection incremental

Both child collectors used a plain GraphqlCollector and swept every issue in
the team on every run, issuing one request per issue with no since filter -
tens of thousands of requests per run on a large team against Linear's ~1500
req/hour budget. Switch them to a stateful collector and restrict the driving
cursor to issues updated since the last successful collection, so steady-state
runs scale with the change delta rather than the whole backlog. A full sync
(since == nil) still sweeps every issue.

Adds a unit test for the incremental cursor-clause builder.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* fix(linear): filter issues server-side by updatedAt for incremental sync

Incremental collection relied on the issues query returning newest-first and a
client-side early-stop, but the query pinned no sort direction (Linear's orderBy
is a scalar enum with no direction operand). If the server default were
ascending, the early-stop would fire on the first (oldest) row and collect
almost nothing. Pass a server-side IssueFilter { updatedAt: { gt: since } }
instead and drop the early-stop, so correctness no longer depends on an
undocumented default ordering. A full sync passes an empty filter (match all).

Adds a unit test pinning the filter's JSON shape to Linear's IssueFilter input.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* refactor(linear): drop dead LeadTimeMinutes tool-layer field

The _tool_linear_issues.lead_time_minutes column was never populated (the
collector never requested it and no extractor set it). Now that lead time is
derived into the domain ticket.Issue directly -- from state-transition history
when available, otherwise the createdAt->resolutionDate fallback in the issue
convertor -- the tool-layer field is pure dead weight. Remove it from the model,
the init migration's archived model, the convertor, and the extractor snapshot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* feat(config-ui): register Linear plugin

Adds the Linear data source to config-ui so it appears in the connection
picker: connection form (endpoint + personal API key + proxy + rate limit),
a flat Teams data-scope backed by the plugin's remote-scopes endpoint, and the
Linear logo. No scope-config transformation — Linear's status mapping is
deterministic. Wired into the plugin registry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* fix(config-ui): map Linear scope id to teamId

getPluginScopeId fell through to the default (scope.id) for Linear, but a
LinearTeam scope is keyed by teamId and has no id field — so the blueprint
referenced an undefined scopeId and patching failed with 'LinearTeam not found'.
Add a linear case returning scope.teamId.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* feat(linear): add Grafana dashboard

Adds grafana/dashboards/Linear.json (cloned from the Asana ticket-dashboard
template) so Linear ships a per-tool dashboard like every other ticket plugin.
Its board picker is scoped to Linear (boards id like 'linear%'); the 13 panels
(throughput, lead/cycle time, status distribution, delivery rate, sprints) read
the shared domain tables. Auto-loaded via Grafana file provisioning.

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* fix(linear): convert team scope to a domain board

board_issues and sprint_issues referenced a board_id (boardIdGen over
LinearTeam), but nothing ever created the ticket.Board row itself, so the
domain boards table stayed empty. Board-scoped dashboards (whose board picker
is 'boards where id like linear%') and any board join therefore returned no
data. Add a ConvertTeams subtask that converts the team scope in
_tool_linear_teams into a ticket.Board keyed identically to those references.

Adds an e2e test asserting the board is produced with the matching id.

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* fix(linear): widen issue title/url columns to avoid truncation

_tool_linear_issues.title and .url were varchar(255), but Linear titles can
exceed 255 chars (and the issue URL embeds a title slug), so extraction failed
with 'Error 1406: Data too long for column title'. Drop the varchar limit so
both are longtext, matching the domain issues.title and jira's tool summary.

Adds an e2e test extracting a 300-char title without truncation.

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* fix(linear): recover owning issue id for comments and history

The GraphQL collector stores the query variables (which carry issueId) in the
raw row's input column, but the comment and history extractors parsed it as
{"Id":...} (SimpleLinearIssue.Id), so the owning issue id came out empty and
the convertor joins produced zero domain comments/changelogs on real data. The
e2e fixtures hand-wrote {"Id":...}, masking it. Parse issueId (with an Id
fallback) and update the fixtures to the real collector shape.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* test: flush LinearIssueLabel before issue extraction in e2e tests

The issue extractor writes both _tool_linear_issues and
_tool_linear_issue_labels, but comment_test, cycle_test and
issue_history_test only flushed LinearIssue before running
ExtractIssuesMeta. On a clean database (as in CI) the table
_tool_linear_issue_labels was never auto-migrated, so the extractor's
DELETE on that table panicked and aborted the whole package. Flush
LinearIssueLabel too, matching the other linear e2e tests and the jira
plugin convention.

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* test: register linear plugin in Test_GetPluginTablesInfo

The plugin count check failed in CI (actual 41 vs tested 40) because the
linear plugin was not listed in table_info_test.go. Add its import and
FeedIn call so every Go plugin is covered.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

* feat(linear): map issues to ticket types via label-based scope config

Linear has no native issue type, so the issue convertor previously
hardcoded every issue to REQUIREMENT. Add optional regex fields to the
Linear scope config (issueTypeIncident/Bug/Requirement) matched against
an issue's label names, with precedence INCIDENT > BUG > REQUIREMENT and
a REQUIREMENT default when nothing matches. This lets DORA classify
Linear bugs as incidents for change-failure-rate / time-to-restore.

Also fix two gaps that made scope configs unusable for Linear:
- thread the scope's ScopeConfigId into the pipeline task options so the
  convertor can load the config at runtime
- register the standard scope-config/:scopeConfigId/projects route that
  every other plugin serves (config-ui 404'd on the scope config page)

Tested: new e2e TestLinearIssueIncidentMapping (Bug label -> INCIDENT,
other issues REQUIREMENT) plus a blueprint plan test asserting
ScopeConfigId is passed through; full plugins/linear suite green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>

---------

Signed-off-by: Eduardo Rodrigues <2961314+eduardoarantes@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

(cherry picked from commit cec4286)
…pache#8903)

* fix(jira): rename Jira Server to Jira Data Center in UI labels

* fix(jira): show both Jira Server and Jira Data Center labels

(cherry picked from commit 50010e0)
…xclusion (apache#8931)

* feat(jira): collect issues via search API to avoid kanban sub-filter exclusion

  * Switch from board Agile API to search API with saved filter JQL so
    resolved issues (e.g. released fixVersions) are no longer silently
    excluded by kanban sub-filters
  * Add sub_query field to boards model and migration to track kanban
    sub-filter changes across syncs
  * Support JIRA Cloud v3 search/jql endpoint alongside v2 for Server

* fix(jira,config-ui): correct SubQuery parsing and connection form crashes

* Fix Jira board SubQuery struct to match nested API response shape
* Prevent click event from being stored as plugin state in connection list
* Default initialValues to empty object when plugin config omits it

* feat(jira): Add BoardConfiguration unmarshal tests

  * Verify SubQuery parsing for kanban boards with, without, and empty sub-filter objects
  * Include a test using a full Jira Cloud response payload to validate all fields

(cherry picked from commit 15e34bb)
* feat(jira): Allow extra JQL when querying JIRA board

* fix: revert code so we just do extrajql, no dynamic dev lake project  name

* fix: remove reference to devlakeprojectname as a template option

(cherry picked from commit cd7bebf)
Co-authored-by: Bujjibabukatta <bujjubabukatta6@gmail.com>
Co-authored-by: Eldrick Wega <eldrick.wega@outlook.com>
Co-authored-by: Eldrick Wega <ewega@github.com>
(cherry picked from commit f93895f)
…pache#8995)

Co-authored-by: Klesh Wong <klesh@qq.com>
(cherry picked from commit 060af3a)
…pache#9006)

* chore(config-ui): modernize frontend toolchain and framework stack

Upgrade the config-ui frontend to current supported versions as one coupled
change so the build stays green:

- Node 18 -> 24, Yarn 3.4.1 -> 4.17.0 (Corepack, vendored release, .yarnrc.yml),
  nginx base image bump in config-ui/Dockerfile
- Vite 8, TypeScript config update, ESLint flat config (eslint.config.mjs)
  replacing .eslintrc.js/.eslintignore, Vitest setup replacing .file-headerrc
- React 18 -> 19 and antd 5 -> 6 with the resulting ref/hook/type fixes and a
  miller-columns-select compatibility patch
- Add main-entry and miller-columns-select tests

The q-dev connection-field files are touched only for the mandatory React 19
useRef(undefined) fix and Prettier formatting; no q-dev logic changes.

Verified on Node 24.18.0 / Yarn 4.17.0: install --immutable clean, tsc --noEmit,
eslint . (0 errors), yarn build (Vite 8), yarn test (4/4) all pass.

Signed-off-by: DoDiODev <DoDiDev@proton.me>

* ci(config-ui): bump lint workflow Node to 24
The modernized config-ui toolchain (ESLint 10.5.0) uses util.styleText in
its stylish formatter, which is only available on Node >= 20.12. The lint
workflow still pinned Node 18, causing 'TypeError: util.styleText is not a
function'. Align CI with the volta-pinned Node 24.17.0.

---------

Signed-off-by: DoDiODev <DoDiDev@proton.me>
(cherry picked from commit 2127e84)
…prints, DORA) (apache#9009)

* feat(clickup): scaffold ClickUp data-source plugin (task→issue MVP)

Add a new DevLake data-source plugin for ClickUp, mirroring the linear
(structure) and trello (REST client) tracker plugins.

- models: ClickUpConnection (token auth, no Bearer prefix), ClickUpList
  scope (keyed by list id), ClickUpTask, ClickUpUser, ClickUpTaskComment
  (stub), ClickUpScopeConfig (status + type mapping)
- migrationscripts: register + addInitTables creating all _tool_clickup_*
  tables via migrationhelper.AutoMigrateTables
- tasks: task/user collectors (page-based + member REST), extractors,
  convertors to ticket.Issue/BoardIssue/IssueAssignee, crossdomain.Account
  and ticket.Board; shared status/type/time helpers
- api: connection CRUD + test-connection (GET /team), scope, scope-config,
  hierarchical remote-scopes (Team→Space→Folder→List), proxy, blueprint v200
- impl: all required plugin interfaces incl. GetTablesInfo listing every
  model, dependency-ordered SubTaskMetas and PrepareTaskData
- register clickup in plugins/table_info_test.go

go build ./plugins/clickup/... and go vet pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(clickup): add ClickUp connector with folder-scope boards, sprints, and DORA

Add a new ClickUp data-source plugin so ClickUp workspaces feed DevLake's
issue-tracking and DORA/velocity metrics, modeled on the Jira/Linear connectors.

Backend:
- Folder is the data-source scope (ClickUpFolder ~= a Jira board); lists are
  child entities collected every sync, so rolling/archived sprint lists never
  need re-scoping.
- Sprint lists (name-matched) -> ticket.Sprint + board_sprints; start/end
  parsed from the list name (M/D vs D/M disambiguated by the >12 rule).
- Tasks -> issues + board_issues; sprint-list tasks also -> sprint_issues.
- Story points from ClickUp native sprint points (or a configured custom field).
- Scope config: sprint-name pattern, story-point field, force-issue-type
  (flag a folder INCIDENT for DORA CFR/MTTR), status/type overrides.
- remote-scopes walks Workspace -> Space -> Folder (folders selectable).
- migration 20260722 adds _tool_clickup_folders + sprint/story-point columns.
- Unit tests for sprint name/date parsing and status/type/story-point mapping.

Config UI:
- ClickUp connection registration (personal-token auth) with a Beta pill.
- Boards data-scope picker + scope-config transformation panel.
- getPluginScopeId(clickup) -> folderId so scope delete and per-scope project
  selection target one scope; fix a pre-existing Connections-page chunk() split
  that silently dropped plugins.

Docs & dashboards:
- Plugin README (connection, folder scope, sprints, story points, incidents).
- Branded ClickUp Grafana dashboard (grafana/dashboards/ClickUp.json).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Evan Lynch <e.lynch303@gmail.com>

* feat(clickup): classify issues by list name (bug/incident list patterns)

ClickUp frequently carries no per-task type, so teams group bugs and
incidents in dedicated lists (e.g. "QA Bugs", "Incident Backlog")
rather than tagging each task. Add scope-config BugListPattern and
IncidentListPattern regexes matched against a list's name; tasks in a
matching list are classified BUG / INCIDENT (INCIDENT wins when both
match). Precedence in the task convertor: forced DefaultIssueType >
list-name pattern > per-task type detection > REQUIREMENT default.

- models: BugListPattern / IncidentListPattern on ClickUpScopeConfig
- migration 20260723 adds the two columns (additive AutoMigrate)
- task convertor: loadListTypeOverrides + pure listTypeFor helper
- unit test for listTypeFor (precedence, case-insensitivity, nil regexes)
- config-ui transformation panel: two list-pattern inputs

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Evan Lynch <e.lynch303@gmail.com>

---------

Signed-off-by: Evan Lynch <e.lynch303@gmail.com>
Co-authored-by: Evan Lynch <elynch@freedomeledger.net>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

(cherry picked from commit 73fa07d)
Adds a datasource plugin for incident.io (https://incident.io), an incident
management platform, following the structure of the rootly plugin:

- Connection with Bearer-token auth against https://api.incident.io/
- Scopes are incident types (v1/incident_types); remote-scope listing included
- Collects incidents (v2/incidents, cursor pagination), extracts to
  _tool_incidentio_* tables (test/tutorial-mode incidents excluded), converts
  to ticket domain issues with type INCIDENT for DORA CFR/MTTR correlation
- Timestamps mapped from incident_timestamp_values: 'Declared at' drives the
  created date, 'Resolved at' (falling back to 'Closed at') the resolution
  date; retrospective incidents keep their resolution date even when it
  precedes the declaration
- Unit tests, e2e snapshot tests, config-ui registration, Grafana dashboard

Validated end-to-end against a production incident.io workspace via the
in-memory test server (50 incidents, field-level match with reference data).

Closes apache#9018

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

(cherry picked from commit 0194a41)
- Add JIRA_GATEWAY_REGEX and a third connection mode 'Jira Cloud (Atlassian
  API Gateway)' in the connection UI
- Auto-build endpoint from Cloud ID input: the user types only the Cloud ID
  and the full gateway URL is constructed automatically
- Force authMethod=AccessToken for gateway connections; existing BasicAuth
  path for standard cloud and server connections is unchanged
- Detect gateway endpoints on edit/load and pre-fill the Cloud ID field
- Suppress misleading /rest/ hint in testConnection() for api.atlassian.com
  endpoints (a 404 there means a bad Cloud ID, not a missing /rest/ path)
- Add unit tests for gateway and standard-cloud connection flows
- Add frontend test suite for regex patterns and Cloud ID builder

No migration script required. No new DB columns.
All collectors, extractors, converters and domain models unchanged.

(cherry picked from commit 14a4e5b)
…ction (apache#9034)

Add a scoped GET /plugins/github/scope-duplicates API and a dismissible
Config-UI Alert so users are informed before creating cross-connection
duplicate domain records (apache#8947).

Co-authored-by: Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit d323c16)
…he#9044)

* build(deps): refresh container images

Bump the pinned container images used by the dev/test stacks and the
shipped Dockerfiles to their current patch releases:

- Grafana 13.0.2 -> 13.1.3 (grafana/Dockerfile)
- PostgreSQL 18.1 -> 18.4 (docker-compose-dev-postgresql.yml,
  backend/test/e2e/remote/docker-compose.test.yml)
- MySQL 8.4.10 -> 8.4.11, LTS line (docker-compose-dev-mysql.yml,
  docker-compose.datasources.yml, .devcontainer/docker-compose.yml,
  devops/deployment/temporal/docker-compose-temporal.yml,
  backend/test/e2e/remote/docker-compose.test.yml)
- nginx-unprivileged 1.31.2 -> 1.31.3 (config-ui/Dockerfile)

Every occurrence of a given pin is raised together so the stacks stay
consistent. The Grafana bump stays within the 13.x line and requires no
dashboard JSON changes. Release artefacts under devops/releases/ are
historical and intentionally left untouched.

Signed-off-by: DoDiODev <DoDiDev@proton.me>

* build(deps): bump pinned Node.js to 24.19.0

Update the volta Node pin in config-ui/package.json from 24.17.0 to
24.19.0, the current 24.x LTS ("Krypton") release. The Docker build stays
on the floating node:24-bookworm-slim tag, so this only aligns local
development environments with the release actually used in CI/images.

Signed-off-by: DoDiODev <DoDiDev@proton.me>

* build(deps): refresh frontend dependencies

Update the pinned config-ui dependencies to their current releases and
regenerate yarn.lock:

- antd 6.4.5 -> 6.6.0
- @ant-design/icons 6.2.5 -> 6.3.2
- cron-parser 5.6.0 -> 5.8.1
- react-router-dom 7.18.0 -> 7.18.2
- styled-components 6.4.2 -> 6.5.1
- eslint 10.5.0 -> 10.8.1
- prettier 3.8.4 -> 3.9.6
- vite 8.1.0 -> 8.2.1
- vitest 4.1.9 -> 4.1.10

All target versions stay within their current major line and keep their
declared engines/peerDependencies compatible with the pinned Node 24 and
React 19 versions. TypeScript is deliberately left at 6.0.3, since 7.x is
a major upgrade that deserves its own change.

Validated locally with yarn install, yarn build, yarn test and yarn lint.

Signed-off-by: DoDiODev <DoDiDev@proton.me>

---------

Signed-off-by: DoDiODev <DoDiDev@proton.me>
(cherry picked from commit 62612a8)
…ther connection (apache#9047)

* feat(gitlab,bitbucket): extend scope-duplicate warning to GitLab and Bitbucket

Add scope-duplicates API endpoints for GitLab and Bitbucket, mirroring the
existing GitHub implementation, and generalize the config-ui data-scope-remote
component and scope API client so the duplicate-connection warning works for
all three plugins.

Co-Authored-By: Cursor Agent <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* assert specific error message

---------

Co-authored-by: Cursor Agent <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 83b457e)
* feat(kiro): add S3 collection and plugin APIs

Signed-off-by: warren <warren.chen830@gmail.com>

* feat(config-ui): add Kiro connection support

Signed-off-by: warren <warren.chen830@gmail.com>

* fix(kiro): use portable timestamp precision

Signed-off-by: warren <warren.chen830@gmail.com>

* fix(kiro): keep q_dev in table info checks

Signed-off-by: warren <warren.chen830@gmail.com>

---------

Signed-off-by: warren <warren.chen830@gmail.com>

(cherry picked from commit 0642b59)
* chore: remove incubator prefix

* fix: linting

* fix: mockery

(cherry picked from commit e355317)
…9097)

Phase 1 of the deprecation plan in apache#9092. Adds deprecation warnings across
the codebase to inform users that the Python plugin framework will be
removed in 3 months in favor of Go-based plugins.

Changes:
- backend/python/README.md: add DEPRECATED banner + migration guidance
- backend/python/plugins/azuredevops/README.md: mark plugin deprecated,
  point users to azuredevops_go
- backend/core/runner/loader.go: emit a WARN log line at server startup
  when remote (Python) plugins are being loaded
- backend/core/plugin/plugin_meta.go: add PluginDeprecation interface
- backend/server/services/remote/plugin/plugin_impl.go: implement
  PluginDeprecation on RemotePlugin so all Python plugins are flagged
- backend/server/api/plugininfo/plugininifo.go: expose  field
  on GET /plugins so config-ui can detect deprecated plugins
- config-ui: add isDeprecated/deprecationMessage to IPluginConfig, mark
  the azuredevops (Python) plugin deprecated, and render a 'Deprecated'
  badge + message in the Connections page

(cherry picked from commit 8692568)
Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 6.9.1 to 7.0.1.
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md)
- [Commits](testing-library/jest-dom@v6.9.1...v7.0.1)

---
updated-dependencies:
- dependency-name: "@testing-library/jest-dom"
  dependency-version: 7.0.1
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit 69535ed)
dependabot Bot and others added 19 commits October 5, 2026 17:25
)

Bumps [jsdom](https://github.com/jsdom/jsdom) from 29.1.1 to 30.0.1.
- [Release notes](https://github.com/jsdom/jsdom/releases)
- [Commits](jsdom/jsdom@v29.1.1...v30.0.1)

---
updated-dependencies:
- dependency-name: jsdom
  dependency-version: 30.0.1
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit 04ae22b)
…pache#9112)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 24.13.2 to 26.4.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 26.4.1
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit 36e3c07)
Bumps the docker-patch group with 1 update in the /config-ui directory: nginxinc/nginx-unprivileged.

Updates `nginxinc/nginx-unprivileged` from 1.31.3 to 1.31.5

---
updated-dependencies:
- dependency-name: nginxinc/nginx-unprivileged
  dependency-version: 1.31.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: docker-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit cc577f3)
…he#9130)

The A-N and O-Z headings were produced by cutting the plugin list at the
first plugin id starting with a letter from o to z. That agrees with the
headings only while each config's `sort` value runs alphabetically, and it
stopped doing so as plugins were appended in the order they were added:
Asana, Kiro, Linear and incident.io are all listed after Opsgenie, so all
four appeared under O-Z.

Group by the first letter of the displayed name instead, which is what a
reader is matching against, and extract the decision into a pure function
with tests.

Generated-by: Claude Code (Claude Opus 5)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 10c20d9)
…st and delete paths (apache#9135)

Co-authored-by: Veet M <veet@inst-builder-debian-12-build-build-v4yxp.europe-west4-a.c.gce-image-builder.internal>
(cherry picked from commit 40f2b0d)
… updates (apache#9158)

Bumps the js-minor-patch group with 26 updates in the /config-ui directory:

| Package | From | To |
| --- | --- | --- |
| [@ant-design/icons](https://github.com/ant-design/ant-design-icons) | `6.3.2` | `6.3.4` |
| [ahooks](https://github.com/alibaba/hooks) | `3.9.7` | `3.10.0` |
| [antd](https://github.com/ant-design/ant-design) | `6.6.0` | `6.6.4` |
| [axios](https://github.com/axios/axios) | `1.18.1` | `1.20.0` |
| [cron-parser](https://github.com/harrisiirak/cron-parser) | `5.8.1` | `5.10.1` |
| [dayjs](https://github.com/iamkun/dayjs) | `1.11.21` | `1.11.23` |
| [react](https://github.com/react/react/tree/HEAD/packages/react) | `19.2.7` | `19.3.0` |
| [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `19.2.17` | `19.3.0` |
| [react-dom](https://github.com/react/react/tree/HEAD/packages/react-dom) | `19.2.7` | `19.3.0` |
| [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) | `19.2.3` | `19.3.0` |
| [react-is](https://github.com/react/react/tree/HEAD/packages/react-is) | `19.2.7` | `19.3.0` |
| [react-medium-image-zoom](https://github.com/rpearce/react-medium-image-zoom) | `5.4.8` | `5.4.9` |
| [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) | `7.18.2` | `7.18.4` |
| [styled-components](https://github.com/styled-components/styled-components) | `6.5.1` | `6.5.3` |
| [@testing-library/dom](https://github.com/testing-library/dom-testing-library) | `10.4.1` | `10.4.2` |
| [@testing-library/react](https://github.com/testing-library/react-testing-library) | `16.3.2` | `16.3.3` |
| [@types/lodash](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash) | `4.17.24` | `4.17.25` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.4.1` | `26.6.1` |
| [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `19.2.17` | `19.3.0` |
| [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) | `19.2.3` | `19.3.0` |
| [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) | `6.0.3` | `6.1.1` |
| [eslint](https://github.com/eslint/eslint) | `10.8.1` | `10.10.0` |
| [globals](https://github.com/sindresorhus/globals) | `17.7.0` | `17.12.0` |
| [jsdom](https://github.com/jsdom/jsdom) | `30.0.1` | `30.1.0` |
| [lint-staged](https://github.com/lint-staged/lint-staged) | `17.0.8` | `17.5.1` |
| [prettier](https://github.com/prettier/prettier) | `3.9.6` | `3.9.8` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.62.0` | `8.70.0` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.2.1` | `8.3.0` |

Updates `@ant-design/icons` from 6.3.2 to 6.3.4
- [Commits](https://github.com/ant-design/ant-design-icons/commits)

Updates `ahooks` from 3.9.7 to 3.10.0
- [Release notes](https://github.com/alibaba/hooks/releases)
- [Commits](alibaba/hooks@v3.9.7...v3.10.0)

Updates `antd` from 6.6.0 to 6.6.4
- [Release notes](https://github.com/ant-design/ant-design/releases)
- [Changelog](https://github.com/ant-design/ant-design/blob/master/CHANGELOG.en-US.md)
- [Commits](ant-design/ant-design@6.6.0...6.6.4)

Updates `axios` from 1.18.1 to 1.20.0
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](axios/axios@v1.18.1...v1.20.0)

Updates `cron-parser` from 5.8.1 to 5.10.1
- [Release notes](https://github.com/harrisiirak/cron-parser/releases)
- [Changelog](https://github.com/harrisiirak/cron-parser/blob/master/CHANGELOG.md)
- [Commits](harrisiirak/cron-parser@v5.8.1...v5.10.1)

Updates `dayjs` from 1.11.21 to 1.11.23
- [Release notes](https://github.com/iamkun/dayjs/releases)
- [Changelog](https://github.com/iamkun/dayjs/blob/v1.11.23/CHANGELOG.md)
- [Commits](iamkun/dayjs@v1.11.21...v1.11.23)

Updates `react` from 19.2.7 to 19.3.0
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.3.0/packages/react)

Updates `@types/react` from 19.2.17 to 19.3.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `react-dom` from 19.2.7 to 19.3.0
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.3.0/packages/react-dom)

Updates `@types/react-dom` from 19.2.3 to 19.3.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

Updates `react-is` from 19.2.7 to 19.3.0
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.3.0/packages/react-is)

Updates `react-medium-image-zoom` from 5.4.8 to 5.4.9
- [Release notes](https://github.com/rpearce/react-medium-image-zoom/releases)
- [Changelog](https://github.com/rpearce/react-medium-image-zoom/blob/main/CHANGELOG.md)
- [Commits](rpearce/react-medium-image-zoom@v5.4.8...v5.4.9)

Updates `react-router-dom` from 7.18.2 to 7.18.4
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/react-router-dom@7.18.4/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@7.18.4/packages/react-router-dom)

Updates `styled-components` from 6.5.1 to 6.5.3
- [Release notes](https://github.com/styled-components/styled-components/releases)
- [Commits](https://github.com/styled-components/styled-components/compare/styled-components@6.5.1...styled-components@6.5.3)

Updates `@testing-library/dom` from 10.4.1 to 10.4.2
- [Release notes](https://github.com/testing-library/dom-testing-library/releases)
- [Changelog](https://github.com/testing-library/dom-testing-library/blob/main/CHANGELOG.md)
- [Commits](testing-library/dom-testing-library@v10.4.1...v10.4.2)

Updates `@testing-library/react` from 16.3.2 to 16.3.3
- [Release notes](https://github.com/testing-library/react-testing-library/releases)
- [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md)
- [Commits](testing-library/react-testing-library@v16.3.2...v16.3.3)

Updates `@types/lodash` from 4.17.24 to 4.17.25
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/lodash)

Updates `@types/node` from 26.4.1 to 26.6.1
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@types/react` from 19.2.17 to 19.3.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `@types/react-dom` from 19.2.3 to 19.3.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

Updates `@vitejs/plugin-react` from 6.0.3 to 6.1.1
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.1.1/packages/plugin-react)

Updates `eslint` from 10.8.1 to 10.10.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](eslint/eslint@v10.8.1...v10.10.0)

Updates `globals` from 17.7.0 to 17.12.0
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](sindresorhus/globals@v17.7.0...v17.12.0)

Updates `jsdom` from 30.0.1 to 30.1.0
- [Release notes](https://github.com/jsdom/jsdom/releases)
- [Commits](jsdom/jsdom@v30.0.1...v30.1.0)

Updates `lint-staged` from 17.0.8 to 17.5.1
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md)
- [Commits](lint-staged/lint-staged@v17.0.8...v17.5.1)

Updates `prettier` from 3.9.6 to 3.9.8
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](prettier/prettier@3.9.6...3.9.8)

Updates `typescript-eslint` from 8.62.0 to 8.70.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.70.0/packages/typescript-eslint)

Updates `vite` from 8.2.1 to 8.3.0
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/create-vite@8.3.0/packages/vite)

---
updated-dependencies:
- dependency-name: "@ant-design/icons"
  dependency-version: 6.3.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: js-minor-patch
- dependency-name: ahooks
  dependency-version: 3.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: antd
  dependency-version: 6.6.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: js-minor-patch
- dependency-name: axios
  dependency-version: 1.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: cron-parser
  dependency-version: 5.10.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: dayjs
  dependency-version: 1.11.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: js-minor-patch
- dependency-name: react
  dependency-version: 19.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: "@types/react"
  dependency-version: 19.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: react-dom
  dependency-version: 19.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: "@types/react-dom"
  dependency-version: 19.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: react-is
  dependency-version: 19.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: react-medium-image-zoom
  dependency-version: 5.4.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: js-minor-patch
- dependency-name: react-router-dom
  dependency-version: 7.18.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: js-minor-patch
- dependency-name: styled-components
  dependency-version: 6.5.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: js-minor-patch
- dependency-name: "@testing-library/dom"
  dependency-version: 10.4.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: js-minor-patch
- dependency-name: "@testing-library/react"
  dependency-version: 16.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: js-minor-patch
- dependency-name: "@types/lodash"
  dependency-version: 4.17.25
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: js-minor-patch
- dependency-name: "@types/node"
  dependency-version: 26.6.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: "@types/react"
  dependency-version: 19.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: "@types/react-dom"
  dependency-version: 19.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: "@vitejs/plugin-react"
  dependency-version: 6.1.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: eslint
  dependency-version: 10.10.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: globals
  dependency-version: 17.12.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: jsdom
  dependency-version: 30.1.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: lint-staged
  dependency-version: 17.5.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: prettier
  dependency-version: 3.9.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: js-minor-patch
- dependency-name: typescript-eslint
  dependency-version: 8.70.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
- dependency-name: vite
  dependency-version: 8.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: js-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit c78bc74)
)

Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.1.10 to 5.0.1.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v5.0.1/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 5.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit 64e12d6)
Service-account 2LO can mint 60-minute Bearer tokens and call the
Atlassian API gateway, so Jira Cloud connections no longer require a
user API token.

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 9abdf41)
…e#9152)

* fix(azuredevops_go) - consider runname for pipeline regex match

* fix(lint): lint issue fix in azure devops extractor

* fix(lint): migration file issue fix

---------

Co-authored-by: root <root@inst-builder-debian-12-build-build-v4yxp.europe-west4-a.c.gce-image-builder.internal>
(cherry picked from commit 54d4e91)
…KE_URL (apache#9166)

Allow overriding the Vite dev server /api proxy target using
VITE_DEVLAKE_URL, defaulting to http://localhost:8080. This avoids
modifying the tracked vite.config.ts during local or dev container
development.

(cherry picked from commit b3f1885)
* feat(grafana_irm): add Grafana IRM incident collection plugin

* test(grafana_irm): add richer live-captured e2e/unit fixtures; implement TestConnection

- Seed 2 more real (non-drill) incidents on the dev stack with a real role
  assignment and multi-label data, closing gaps the original 2-incident
  fixture never exercised (assignment mapping, per-scope label exclusion).
- Add a second e2e scenario proving label-based scope filtering end-to-end.
- Update the extractor unit test to use real captured incident data instead
  of a drill incident's.
- Implement TestConnection/TestExistingConnection via a cheap
  IncidentsService.QueryIncidents call, verified live against the real API.

* refactor(grafana_irm): revert to connection-wide scoping, drop label filtering

The originating feature request only asks for org-wide DORA correlation and
never mentions per-team scoping. The label-based per-scope filtering added
earlier this session was real and tested, but solved a problem nobody asked
for, and config-ui has no generic manual-scope-entry component to build a UI
for it on top of. Revert GrafanaIrmScopeConfig/GrafanaIrmOptions/the
collector/converter to a single connection-wide scope with no filtering, same
shape as incidentio/pagerduty. All incident labels are still collected and
stored unconditionally, just no longer used to gate conversion.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat(grafana_irm): add config-ui frontend and single-scope remote API
Backend: add remote_api.go returning the one synthetic scope every
connection has (config-ui's data-scope picker has no manual-entry flow to
fall back to, so this feeds the standard remote-picker UI a single 'All
Incidents' entry instead), wired into impl.go's routes. Frontend: add config-ui/src/plugins/register/grafana_irm (connection form,
icon, registration) mirroring incidentio's shape, using the Grafana logo
already vendored under grafana/img/. No custom scope-config UI is needed
since GrafanaIrmScopeConfig carries no extra fields (Option A). Verified
with tsc, eslint, and a production vite build - all clean.

* fix(grafana_irm): fix error raised during testing

* refactor(grafana_irm): collapse collect+refresh into one FinalizableApiCollector subtask

The two-subtask design (CollectIncidents + RefreshOpenIncidents) caused three
real bugs found via live pipeline testing: a panic, "Re-transform Data"
silently deleting resolved incidents, and a genuine full sync also losing
data because both subtasks independently wiped the raw table with no
coordination between them.

pagerduty solves the identical "list new/changed, then refresh still-open"
need with DevLake's own FinalizableApiCollector as a single subtask, which
prevents these bugs by construction (the framework never builds the
"refresh" half on a full sync, and there's only one subtask name for
Re-transform Data's filter to strip). Migrated CollectIncidents to that
pattern; all existing collector logic (query building, change-detection via
a request-scoped header) preserved, just re-wired. Live-verified against a
real server: full sync restores all incidents correctly, incremental sync
has no regression, and Re-transform Data no longer drops resolved incidents.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat(grafana_irm): add dedicated Grafana dashboard, docs, and domain board mapping

- Add dedicated Grafana dashboards for MySQL and PostgreSQL dialects
- Populate domain ticket.Board in ConvertIncidents to enable board filtering and joins
- Update config-ui brand icon with official Grafana flame SVG
- Add plugin documentation in backend/plugins/grafana_irm/README.md
- Fix struct alignment formatting in models/incident.go

* fix(grafana_irm): improve connection test error messages and add docs link

* fix(grafana_irm): truncate timestamps to milliseconds and fix e2e postgres scope setup

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

(cherry picked from commit 6502e54)
* feat(youtrack): add plugin skeleton, init migration, and connection API

New youtrack plugin:

- 9 _tool_youtrack_* models (connection, project scope,
  scope config with 6 field-name slots + flat name-keyed mappings,
  account, issue, issue_comment, issue_label, workflow_state,
  issue_changelog), all on common.NoPKModel with literal TableName()
- init migration over archived snapshots in GetTablesInfo() order,
  with the ScopeConfig/Scope embeds hand-unrolled (archived helpers
  don't carry them); schema_e2e gate passes against real MySQL
- permanent-token connection (helper.AccessToken, Bearer perm:...),
  token encdec-encrypted, Sanitize-masked, MergeFromRequest-preserving
- endpoint hard-validated to end in /api at save and test time
- test-connection diagnostic matrix: guest-fallback assertion (a 2xx
  proves nothing), 401, InCloud /youtrack-prefix hint on 404, soft
  warning on non-perm: token shape, best-effort version probe
- registered in plugins/table_info_test.go and schema_e2e

Scope/scope-config/remote/proxy/blueprint APIs land in the next commit.

* feat(youtrack): add scope, scope-config, blueprint APIs, and proxy

Scope and API layer of the YouTrack plugin:

- remote-scopes lists the instance's projects via GET /admin/projects
  with $top/$skip pagination, displaying 'shortName (name)' and
  flagging archived projects
- scopes GET/PUT and per-scope GET/PATCH/DELETE via the datasource
  helper; attaching a project creates the _tool_youtrack_projects row
- scope-config CRUD persists the six field-name slots and both JSON
  mapping maps; Entities defaults to [TICKET, CROSS] on POST when the
  body leaves it unset (handles both in-process []string and wire
  []interface{} shapes)
- singular un-nested scope-config/:scopeConfigId/projects route
  (Linear asymmetry, copied verbatim)
- GET connections/:id/proxy/rest/*path for config-ui field/bundle
  discovery
- blueprint v200 plan generation: scopes map to ticket.Board with ids
  built from the internal project id (stable across shortName renames)
- swagger annotations on the new endpoints

* feat(youtrack): collect and convert issues with anonymised e2e fixtures

Add incremental issue and workflow-state collection, extraction and conversion for projects, accounts, issues and labels. Cover field mappings, retry behaviour and captured anonymised e2e fixtures.

* feat(youtrack): add comments slice — collect, extract, convert issue comments

Collect, Extract and Convert Comments subtasks, registered in
impl.go's SubTaskMetas order: per-issue comment collection
bounded by the incremental bookmark (input = tool issues with
updated >= since; all issues on full sync), extraction keeping the
deleted flag and deriving authors into accounts (CROSS-gated), and
conversion into issue_comments with didgen ids — deleted comments never
reach the domain layer.

The issues and comments endpoints now share one JSON-array response
parser (parseJsonArrayResponse in shared.go).

Fixture: 68 anonymised live-captured comments on the staged issues,
2 of them deleted; the issue_comments snapshot carries only the 66
non-deleted ones.

* feat(youtrack): add changelogs slice — collect, extract, convert issue changelogs

Collect, Extract and Convert Changelogs subtasks, registered in
impl.go's SubTaskMetas order: the activity feed flows into
issue_changelogs. Collection walks each changed issue's activitiesPage
cursor to hasAfter=false (cursors URL-encoded via url.Values, all filter
params repeated per request, the five configured categories mandatory).
Extraction lands one tool row per activity item with multi-value
added/removed JSON-encoded, deriving authors and assignee-change users
into accounts. Conversion maps state-field changes to std statuses via
the shared helper (mappings, else isResolved looked up from
_tool_youtrack_workflow_states by project+name, cached per run),
assignee changes to didgen account ids, everything else pass-through.

The comment collector's input bound is renamed to changedIssuesSince,
now shared by both per-issue collectors.

Fixture: 29 anonymised live-captured activity items covering all five
categories — State, Assignee and other custom-field changes, multi-value
Tags changes, Summary changes (text replaced with English filler), IssueCreated and
IssueResolved items.

E2e (changelog_test.go) covers these cases at the table seam plus a full-re-extract
idempotency assertion (upsert by activity id). Unit seams: cursor-walk
query/termination, added/removed value encoding, std-status and didgen
value conversion.

* feat(youtrack): add config-ui plugin — connection form, scope picker, transformation widget

* feat(youtrack): add MySQL and PostgreSQL Grafana dashboards

Provision the YouTrack dashboards for both database engines with Kanban metrics.

* fix(youtrack): preserve incremental state and replace stale data

Align changed-issue windows for comments and changelogs, keep only the latest issue and workflow-state snapshots on replay, and remove domain comments that were deleted upstream. Make API retries cancellation-aware with a single retry owner, and extend e2e scenarios and fixtures to cover these transitions.

Skip 404s from the per-issue comment and activity endpoints so an issue deleted upstream no longer fails the subtask and freezes its bookmark. Delete the scope's domain issue labels and assignees before converting, so they are replaced even when a run emits none.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(youtrack): make e2e tests pass on a fresh MySQL and PostgreSQL database

CI runs the e2e suite against an empty database, where three things
failed that a reused local database hid:

- subtasks delete stale rows (labels, assignees, ...) before writing, so a
  test that never created one of those tables failed with "table does not
  exist"; newDataFlowTester now creates every table the subtasks touch
- rows appended after ImportCsvIntoRawTable collided with the CSV ids on
  PostgreSQL, whose sequence the explicit-id import leaves at 1; they now
  get an explicit id past the imported ones
- the mixed-language state-name check used MySQL-only REGEXP; it now runs
  in Go

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

(cherry picked from commit b28f850)
@muzamilkm
muzamilkm force-pushed the chore/config-ui-upstream-sync branch from 8544810 to 3fcda8b Compare October 5, 2026 16:17
@muzamilkm
muzamilkm merged commit ff5d81f into arbisoft:main-arbisoft Oct 6, 2026
5 checks passed
@muzamilkm
muzamilkm deleted the chore/config-ui-upstream-sync branch October 6, 2026 09:20
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.