-
Notifications
You must be signed in to change notification settings - Fork 0
Version Control nav group, sidebar parity, ⌘K palette #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
e518920
feat(web): Version Control nav group + Connections/Policies sub-tab p…
67e4210
feat(web): Ctrl/Cmd+K command palette for jump-to-page navigation
07eca51
fix(pr24): address Copilot round 1
99448cf
fix(pr24): address Copilot round 2 (real-new threads)
e73761f
fix(pr24): consolidate test GET helper, address Copilot round 3
56ade39
fix(pr24): address Copilot round 4
9b52aba
fix(pr24): address Copilot round 5
244d80d
fix(pr24): address Copilot round 6
4f3c71d
fix(pr24): address Copilot round 7
7f3c047
fix(pr24): address Copilot round 8 (cmdk a11y polish)
b2b5f36
fix(pr24): address Copilot round 9 (disclosure a11y + Enter respect)
bf1c0d8
fix(pr24): address Copilot round 10
e13e70f
fix(pr24): register httpproxy connector in version_control test
fda46d3
fix(pr24): address Copilot round 11 (arrow-key focus preservation)
6a019d4
fix(pr24): address Copilot round 12 (path + decorative-svg nits)
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| package web_test | ||
|
|
||
| // Regression test for the synthetic "version_control" connector-tab | ||
| // filter that groups github + gitlab cards (and existing github/gitlab | ||
| // connections) under one /connections sub-page. Lives next to the | ||
| // parallel /policies?scope=version_control test so a future refactor | ||
| // can't silently drop either branch of the filter. | ||
|
|
||
| import ( | ||
| "net/http" | ||
| "strings" | ||
| "testing" | ||
|
|
||
| "github.com/trilitech/Sieve/internal/connector" | ||
| githubconn "github.com/trilitech/Sieve/internal/connectors/github" | ||
| gitlabconn "github.com/trilitech/Sieve/internal/connectors/gitlab" | ||
| "github.com/trilitech/Sieve/internal/connectors/httpproxy" | ||
| ) | ||
|
|
||
| // TestConnectionsPage_VersionControlTab asserts: | ||
| // - /connections?type=version_control surfaces both the github and | ||
| // gitlab connector catalog cards. | ||
| // - It also surfaces existing connections whose ConnectorType is | ||
| // "github" or "gitlab", and excludes other connections. | ||
| // - The narrower ?type=github tab only shows GitHub (no GitLab). | ||
| func TestConnectionsPage_VersionControlTab(t *testing.T) { | ||
| handler, env := newTestWebServer(t) | ||
|
|
||
| // Register the real github + gitlab connector metas so the catalog | ||
| // loop has cards to render. The mock connector seeded by | ||
| // newTestWebServer is registered under "mock", which is fine — | ||
| // it's the negative control. | ||
| env.Registry.Register(githubconn.Meta(), func(raw map[string]any) (connector.Connector, error) { | ||
| return githubconn.Factory()(raw) | ||
| }) | ||
| env.Registry.Register(gitlabconn.Meta(), func(raw map[string]any) (connector.Connector, error) { | ||
| return gitlabconn.Factory()(raw) | ||
| }) | ||
| // http_proxy is needed for the "forged category" negative control below. | ||
| env.Registry.Register(httpproxy.Meta, httpproxy.Factory) | ||
|
|
||
| // Seed one connection per connector type. Config payloads are | ||
| // intentionally empty: the filter under test keys off | ||
| // ConnectorType + display name, not the connector's typed config | ||
| // schema, and a too-specific seed would tie the test to a | ||
| // schema that may evolve. | ||
| if err := env.Connections.Add("my-github", "github", "My GitHub", map[string]any{}); err != nil { | ||
| t.Fatalf("add github connection: %v", err) | ||
| } | ||
| if err := env.Connections.Add("my-gitlab", "gitlab", "My GitLab", map[string]any{}); err != nil { | ||
| t.Fatalf("add gitlab connection: %v", err) | ||
| } | ||
| if err := env.Connections.Add("my-mock", "mock", "My Mock", map[string]any{}); err != nil { | ||
| t.Fatalf("add mock connection: %v", err) | ||
| } | ||
| // Negative control: an http_proxy whose config.category is set to | ||
| // "github" must NOT appear under ?type=version_control. The filter | ||
| // keys off ConnectorType (immutable) rather than the per-connection | ||
| // category override, so this stays excluded. | ||
| if err := env.Connections.Add("fake-vcs-proxy", "http_proxy", "Fake VCS Proxy", map[string]any{ | ||
| "target_url": "https://example.com", | ||
| "category": "github", | ||
| }); err != nil { | ||
| t.Fatalf("add fake-vcs proxy: %v", err) | ||
| } | ||
|
|
||
| t.Run("version_control tab shows both catalog cards + both connections", func(t *testing.T) { | ||
| rec := getRequest(handler, env, "/connections?type=version_control") | ||
| if rec.Code != http.StatusOK { | ||
| t.Fatalf("expected 200, got %d (body: %s)", rec.Code, rec.Body.String()) | ||
| } | ||
| body := rec.Body.String() | ||
| // Catalog cards: the page renders each connector card by | ||
| // emitting both the connector's Meta().Name (in an h4) and its | ||
| // Meta().Description (in a sibling p). Pin both Name strings — | ||
| // the Name is the load-bearing label and is stable text. | ||
| // "GitLab" alone is too soft a probe (it also appears in the | ||
| // connection-row display name), so we also pin a Description | ||
| // substring per connector so a regression that removed the | ||
| // catalog cards while leaving the connection list intact would | ||
| // fail. | ||
| for _, want := range []string{ | ||
| "My GitHub", // existing connection display name | ||
| "My GitLab", // existing connection display name | ||
| "PAT or GitHub App", // GitHub Meta() Description substring | ||
| "merge requests", // GitLab Meta() Description substring | ||
| } { | ||
| if !strings.Contains(body, want) { | ||
| t.Errorf("version_control tab missing %q", want) | ||
| } | ||
| } | ||
| if strings.Contains(body, "My Mock") { | ||
| t.Errorf("version_control tab incorrectly includes non-VCS connection 'My Mock'") | ||
| } | ||
| // An http_proxy with config.category="github" must NOT slip | ||
| // into the version_control tab — the filter keys off the | ||
| // immutable ConnectorType, not the per-connection override. | ||
| if strings.Contains(body, "Fake VCS Proxy") { | ||
| t.Errorf("version_control tab incorrectly includes an http_proxy whose config.category is forged to 'github'") | ||
| } | ||
| }) | ||
|
|
||
| t.Run("github tab excludes gitlab", func(t *testing.T) { | ||
| rec := getRequest(handler, env, "/connections?type=github") | ||
| if rec.Code != http.StatusOK { | ||
| t.Fatalf("expected 200, got %d", rec.Code) | ||
| } | ||
| body := rec.Body.String() | ||
| if !strings.Contains(body, "My GitHub") { | ||
| t.Errorf("github tab missing 'My GitHub' connection") | ||
| } | ||
| if strings.Contains(body, "My GitLab") { | ||
| t.Errorf("github tab incorrectly includes 'My GitLab' connection") | ||
| } | ||
| }) | ||
|
|
||
| t.Run("gitlab tab excludes github", func(t *testing.T) { | ||
| rec := getRequest(handler, env, "/connections?type=gitlab") | ||
| if rec.Code != http.StatusOK { | ||
| t.Fatalf("expected 200, got %d", rec.Code) | ||
| } | ||
| body := rec.Body.String() | ||
| if !strings.Contains(body, "My GitLab") { | ||
| t.Errorf("gitlab tab missing 'My GitLab' connection") | ||
| } | ||
| if strings.Contains(body, "My GitHub") { | ||
| t.Errorf("gitlab tab incorrectly includes 'My GitHub' connection") | ||
| } | ||
| }) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| package web_test | ||
|
|
||
| // Regression test for the synthetic "version_control" policy scope that | ||
| // groups github + gitlab policies under one sidebar tab. The filter is | ||
| // implemented in server.go's handlePolicies; this test pins the | ||
| // inclusion rule so a future refactor can't silently drop github/gitlab | ||
| // from the group or accidentally widen it to other scopes. | ||
|
|
||
| import ( | ||
| "net/http" | ||
| "strings" | ||
| "testing" | ||
|
|
||
| "github.com/trilitech/Sieve/internal/testing/testenv" | ||
| ) | ||
|
|
||
| // TestPoliciesPage_VersionControlScope asserts: | ||
| // - ?scope=version_control includes policies tagged github and gitlab. | ||
| // - That synthetic scope does NOT include policies for unrelated | ||
| // connectors (slack, gmail). | ||
| // - The narrower ?scope=github tab shows only github (legacy/empty | ||
| // scopes also show, but explicitly-scoped gitlab policies do not). | ||
| func TestPoliciesPage_VersionControlScope(t *testing.T) { | ||
| handler, env := newTestWebServer(t) | ||
|
|
||
| // Seed four policies, three of which carry an explicit scope. | ||
| mustSeedPolicy(t, env, "github-allow", "github") | ||
| mustSeedPolicy(t, env, "gitlab-allow", "gitlab") | ||
| mustSeedPolicy(t, env, "slack-allow", "slack") | ||
| mustSeedPolicy(t, env, "legacy-no-scope", "") // empty scope — shows under all tabs | ||
| // Hand-crafted "version_control"-scoped policy stands in for a | ||
| // DB row that slipped past the create-time block in | ||
| // handlePolicyCreate. The version_control filter MUST NOT | ||
| // surface it (scope is a browse-only filter, not a real scope). | ||
| mustSeedPolicy(t, env, "vcs-stamped", "version_control") | ||
|
|
||
| t.Run("version_control includes github + gitlab, excludes slack", func(t *testing.T) { | ||
| rec := getRequest(handler, env, "/policies?scope=version_control") | ||
| if rec.Code != http.StatusOK { | ||
| t.Fatalf("expected 200, got %d (body: %s)", rec.Code, rec.Body.String()) | ||
| } | ||
| body := rec.Body.String() | ||
| for _, want := range []string{"github-allow", "gitlab-allow", "legacy-no-scope"} { | ||
| if !strings.Contains(body, want) { | ||
| t.Errorf("version_control scope missing policy %q", want) | ||
| } | ||
| } | ||
| if strings.Contains(body, "slack-allow") { | ||
| t.Errorf("version_control scope incorrectly includes slack policy") | ||
| } | ||
| if strings.Contains(body, "vcs-stamped") { | ||
| t.Errorf("version_control scope incorrectly includes a policy literally stamped scope=version_control (this scope is browse-only and such a policy is nonsense)") | ||
| } | ||
| }) | ||
|
|
||
| t.Run("github scope excludes gitlab", func(t *testing.T) { | ||
| rec := getRequest(handler, env, "/policies?scope=github") | ||
| if rec.Code != http.StatusOK { | ||
| t.Fatalf("expected 200, got %d", rec.Code) | ||
| } | ||
| body := rec.Body.String() | ||
| if !strings.Contains(body, "github-allow") { | ||
| t.Errorf("github scope missing github-allow policy") | ||
| } | ||
| if strings.Contains(body, "gitlab-allow") { | ||
| t.Errorf("github scope incorrectly includes gitlab-allow") | ||
| } | ||
| }) | ||
|
|
||
| t.Run("slack scope excludes both vcs policies", func(t *testing.T) { | ||
| rec := getRequest(handler, env, "/policies?scope=slack") | ||
| if rec.Code != http.StatusOK { | ||
| t.Fatalf("expected 200, got %d", rec.Code) | ||
| } | ||
| body := rec.Body.String() | ||
| for _, unwanted := range []string{"github-allow", "gitlab-allow"} { | ||
| if strings.Contains(body, unwanted) { | ||
| t.Errorf("slack scope incorrectly includes %q", unwanted) | ||
| } | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| // mustSeedPolicy creates a minimal rules-evaluator policy carrying the | ||
| // given scope (empty string = unscoped). The rules body is intentionally | ||
| // trivial — we're testing the scope filter, not the evaluator. | ||
| func mustSeedPolicy(t *testing.T, env *testenv.Env, name, scope string) { | ||
| t.Helper() | ||
| cfg := map[string]any{ | ||
| "rules": []any{ | ||
| map[string]any{"action": "allow"}, | ||
| }, | ||
| } | ||
| if scope != "" { | ||
| cfg["scope"] = scope | ||
| } | ||
| if _, err := env.Policies.Create(name, "rules", cfg); err != nil { | ||
| t.Fatalf("seed policy %q: %v", name, err) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.