Skip to content

Commit 7cf2cce

Browse files
Thomas StrombergThomas Stromberg
authored andcommitted
fix workspace toggling
1 parent 02b3708 commit 7cf2cce

File tree

6 files changed

+582
-3
lines changed

6 files changed

+582
-3
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
deploy:
33
./hacks/deploy.sh
44

5+
.PHONY: test
6+
test:
7+
node --test assets/workspace.test.js
8+
59

610
# BEGIN: lint-install .
711
# http://github.com/codeGROOVE-dev/lint-install

assets/README.tests.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Automated Tests
2+
3+
## Running Tests
4+
5+
```bash
6+
make test
7+
```
8+
9+
Or directly with Node.js:
10+
11+
```bash
12+
node --test assets/workspace.test.js
13+
```
14+
15+
## Test Coverage
16+
17+
### `workspace.test.js`
18+
Tests for the workspace module (`assets/workspace.js`):
19+
20+
- **currentWorkspace()**: Validates workspace detection from subdomain
21+
- Base domain returns `null`
22+
- Reserved subdomains (www, api, etc.) return `null`
23+
- Org subdomains return the org name
24+
- Localhost returns `null`
25+
26+
- **hiddenOrgs()**: Validates reading hidden organizations from cookies
27+
- Returns empty array when no preferences exist
28+
- Reads from workspace-specific cookies
29+
- Handles both personal and org workspaces
30+
31+
- **setHiddenOrgs()**: Validates setting hidden organizations
32+
- Creates workspace-specific cookies
33+
- Handles empty arrays
34+
- Works for both personal and org workspaces
35+
36+
- **toggleOrgVisibility()**: Validates toggling org visibility
37+
- Adds org when not present
38+
- Removes org when present
39+
- Works correctly across multiple toggles
40+
41+
- **initializeDefaults()**: Validates default behavior for org workspaces
42+
- Hides personal account PRs by default in org workspaces
43+
- Does NOT set defaults in personal workspace
44+
- Does NOT override existing preferences
45+
- Requires username cookie to be set
46+
- Maintains independent preferences per workspace
47+
48+
- **Integration tests**: Validates full workflow scenarios
49+
- Users can override defaults by toggling
50+
- Preferences persist across page reloads
51+
- Repeated toggles work correctly (idempotency)
52+
- No duplicate orgs from rapid clicking (regression test)
53+
54+
## Test Framework
55+
56+
Tests use Node.js built-in test runner (available in Node.js 18+). No external dependencies required.
57+
58+
The tests create a mock DOM environment with:
59+
- `MockDocument`: Simulates `document` with cookie storage
60+
- `MockWindow`: Simulates `window` with location/hostname
61+
62+
This allows testing browser-specific code in a Node.js environment.

assets/app.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,10 @@ const App = (() => {
425425
// Load current user
426426
const loadCurrentUser = async () => {
427427
state.currentUser = await Auth.loadCurrentUser();
428+
// Store username in cookie for workspace module
429+
if (state.currentUser && state.currentUser.login) {
430+
setCookie("username", state.currentUser.login, 365);
431+
}
428432
};
429433

430434
// GitHub API wrapper that uses Auth module
@@ -909,6 +913,9 @@ const App = (() => {
909913
updateSearchInputVisibility();
910914
await loadCurrentUser();
911915

916+
// Initialize workspace defaults after user is loaded
917+
Workspace.initializeDefaults();
918+
912919
// If at root URL, redirect to user's page
913920
if (!urlContext && state.currentUser) {
914921
window.location.href = `/u/${state.currentUser.login}`;

assets/user.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -996,8 +996,7 @@ export const User = (() => {
996996
const newHiddenOrgs = Workspace.hiddenOrgs();
997997
console.log("[populateOrgFilters] After toggle, hidden orgs:", newHiddenOrgs);
998998

999-
// Refresh the menu and PR sections
1000-
populateOrgFilters(state);
999+
// Refresh PR sections (which also refreshes the menu)
10011000
updatePRSections(state);
10021001
});
10031002
});

assets/workspace.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ export const Workspace = (() => {
6060
const cookieName = `hidden_orgs_${workspace}`;
6161
const cookieValue = JSON.stringify(orgs);
6262

63+
console.log(`[Workspace.setHiddenOrgs] Workspace: ${workspace}`);
64+
console.log(`[Workspace.setHiddenOrgs] Cookie name: ${cookieName}`);
65+
console.log(`[Workspace.setHiddenOrgs] Cookie value: ${cookieValue}`);
66+
6367
// Cookie size limit check (4KB is typical browser limit)
6468
// Allow some overhead for cookie name and attributes
6569
const maxCookieSize = 3800; // Conservative limit
@@ -79,23 +83,33 @@ export const Workspace = (() => {
7983
expires.setTime(expires.getTime() + 365 * 24 * 60 * 60 * 1000);
8084
const isSecure = window.location.protocol === "https:";
8185
const securePart = isSecure ? ";Secure" : "";
82-
document.cookie = `${cookieName}=${cookieValue};expires=${expires.toUTCString()};path=/;domain=.${BASE_DOMAIN};SameSite=Lax${securePart}`;
86+
const cookieString = `${cookieName}=${cookieValue};expires=${expires.toUTCString()};path=/;domain=.${BASE_DOMAIN};SameSite=Lax${securePart}`;
87+
console.log(`[Workspace.setHiddenOrgs] Setting cookie: ${cookieString}`);
88+
document.cookie = cookieString;
89+
console.log(`[Workspace.setHiddenOrgs] document.cookie after set:`, document.cookie);
8390
};
8491

8592
// Toggle org visibility
8693
const toggleOrgVisibility = (org) => {
94+
console.log(`[Workspace.toggleOrgVisibility] Toggling: ${org}`);
8795
const hidden = hiddenOrgs();
96+
console.log(`[Workspace.toggleOrgVisibility] Current hidden orgs:`, hidden);
8897
const index = hidden.indexOf(org);
98+
console.log(`[Workspace.toggleOrgVisibility] Index of ${org}:`, index);
8999

90100
if (index === -1) {
91101
// Hide the org
102+
console.log(`[Workspace.toggleOrgVisibility] Adding ${org} to hidden list`);
92103
hidden.push(org);
93104
} else {
94105
// Show the org
106+
console.log(`[Workspace.toggleOrgVisibility] Removing ${org} from hidden list`);
95107
hidden.splice(index, 1);
96108
}
97109

110+
console.log(`[Workspace.toggleOrgVisibility] New hidden list:`, hidden);
98111
setHiddenOrgs(hidden);
112+
console.log(`[Workspace.toggleOrgVisibility] After setHiddenOrgs, reading back:`, hiddenOrgs());
99113
return hidden;
100114
};
101115

@@ -104,6 +118,27 @@ export const Workspace = (() => {
104118
return hiddenOrgs().includes(org);
105119
};
106120

121+
// Initialize default hidden orgs for org-based workspaces
122+
// In org workspaces, hide personal account PRs by default, show all orgs
123+
const initializeDefaults = () => {
124+
const workspace = currentWorkspace();
125+
const username = getCookie("username");
126+
127+
// Only initialize defaults for org workspaces (not personal workspace)
128+
if (!workspace || !username) return;
129+
130+
const cookieName = `hidden_orgs_${workspace}`;
131+
const existingCookie = getCookie(cookieName);
132+
133+
// Only set defaults if no preference exists yet
134+
if (existingCookie === null) {
135+
console.log(`[Workspace] Initializing defaults for org workspace: ${workspace}`);
136+
console.log(`[Workspace] Hiding personal account: ${username}`);
137+
// Hide the user's personal GitHub account by default
138+
setHiddenOrgs([username]);
139+
}
140+
};
141+
107142
// Switch workspace (redirect to different subdomain, preserving current path)
108143
const switchWorkspace = (org) => {
109144
const protocol = window.location.protocol;
@@ -150,6 +185,7 @@ export const Workspace = (() => {
150185
isOrgHidden,
151186
switchWorkspace,
152187
username,
188+
initializeDefaults,
153189
};
154190
console.log("[Workspace Module] Exports:", workspaceExports);
155191
return workspaceExports;

0 commit comments

Comments
 (0)