Fix workspace selection and secret modal layout
This commit is contained in:
@@ -99,15 +99,21 @@ impl AdminService {
|
|||||||
.registry
|
.registry
|
||||||
.list_workspaces_for_user(&authenticated.user.id)
|
.list_workspaces_for_user(&authenticated.user.id)
|
||||||
.await?;
|
.await?;
|
||||||
let current_workspace_id = authenticated
|
let default_workspace_id = memberships
|
||||||
.current_workspace_id
|
.iter()
|
||||||
.as_ref()
|
.find(|membership| membership.workspace.id.as_str() == "ws_default")
|
||||||
.map(|workspace_id| workspace_id.as_str().to_owned())
|
.map(|membership| membership.workspace.id.as_str().to_owned());
|
||||||
.or_else(|| {
|
let current_workspace_id = default_workspace_id.or_else(|| {
|
||||||
memberships
|
authenticated
|
||||||
.first()
|
.current_workspace_id
|
||||||
.map(|membership| membership.workspace.id.as_str().to_owned())
|
.as_ref()
|
||||||
});
|
.map(|workspace_id| workspace_id.as_str().to_owned())
|
||||||
|
.or_else(|| {
|
||||||
|
memberships
|
||||||
|
.first()
|
||||||
|
.map(|membership| membership.workspace.id.as_str().to_owned())
|
||||||
|
})
|
||||||
|
});
|
||||||
let current_workspace_ref = current_workspace_id
|
let current_workspace_ref = current_workspace_id
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|workspace_id| WorkspaceId::new(workspace_id.clone()));
|
.map(|workspace_id| WorkspaceId::new(workspace_id.clone()));
|
||||||
|
|||||||
@@ -154,6 +154,40 @@
|
|||||||
max-width: 1160px;
|
max-width: 1160px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 36px 40px 60px;
|
padding: 36px 40px 60px;
|
||||||
|
animation: page-enter 0.18s ease-out both;
|
||||||
|
transition: opacity 0.12s ease, transform 0.12s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.page-leaving .page,
|
||||||
|
body.page-leaving .wizard-body,
|
||||||
|
body.page-leaving .ws-setup-body {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes page-enter {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(8px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.page {
|
||||||
|
animation: none;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.page-leaving .page,
|
||||||
|
body.page-leaving .wizard-body,
|
||||||
|
body.page-leaving .ws-setup-body {
|
||||||
|
opacity: 1;
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Hamburger button (hidden on desktop) ── */
|
/* ── Hamburger button (hidden on desktop) ── */
|
||||||
|
|||||||
@@ -767,7 +767,10 @@
|
|||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 480px;
|
max-width: 480px;
|
||||||
|
max-height: calc(100dvh - 48px);
|
||||||
box-shadow: 0 8px 40px rgba(0,0,0,0.6);
|
box-shadow: 0 8px 40px rgba(0,0,0,0.6);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -801,8 +804,8 @@
|
|||||||
}
|
}
|
||||||
.modal-close:hover { background: var(--bg-overlay); color: var(--text-primary); }
|
.modal-close:hover { background: var(--bg-overlay); color: var(--text-primary); }
|
||||||
|
|
||||||
.modal-body { padding: 20px; }
|
.modal-body { padding: 20px; overflow: auto; }
|
||||||
.modal-footer { padding: 14px 20px; border-top: 1px solid var(--border-subtle); display: flex; justify-content: flex-end; gap: 8px; }
|
.modal-footer { padding: 14px 20px; border-top: 1px solid var(--border-subtle); display: flex; justify-content: flex-end; gap: 8px; flex-shrink: 0; }
|
||||||
|
|
||||||
/* ══════════════════════════════════════════════════
|
/* ══════════════════════════════════════════════════
|
||||||
RESPONSIVE
|
RESPONSIVE
|
||||||
|
|||||||
@@ -153,6 +153,8 @@
|
|||||||
padding: 40px 40px 140px;
|
padding: 40px 40px 140px;
|
||||||
gap: 36px;
|
gap: 36px;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
animation: page-enter 0.18s ease-out both;
|
||||||
|
transition: opacity 0.12s ease, transform 0.12s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox-pill {
|
.checkbox-pill {
|
||||||
|
|||||||
@@ -47,6 +47,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 48px 24px 80px;
|
padding: 48px 24px 80px;
|
||||||
|
animation: page-enter 0.18s ease-out both;
|
||||||
|
transition: opacity 0.12s ease, transform 0.12s ease;
|
||||||
}
|
}
|
||||||
.ws-setup-container {
|
.ws-setup-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -19,6 +19,11 @@
|
|||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
line-height: 1.55;
|
line-height: 1.55;
|
||||||
}
|
}
|
||||||
|
#secret-json-value {
|
||||||
|
min-height: 132px;
|
||||||
|
max-height: 220px;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
.secrets-card-list { display: none; }
|
.secrets-card-list { display: none; }
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
#secrets-table-wrap { display: none; }
|
#secrets-table-wrap { display: none; }
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var transitionMs = 120;
|
||||||
|
|
||||||
|
function prefersReducedMotion() {
|
||||||
|
return window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInternalNavigation(link) {
|
||||||
|
if (!link || !link.href || link.target || link.hasAttribute('download')) return false;
|
||||||
|
|
||||||
|
var targetUrl;
|
||||||
|
try {
|
||||||
|
targetUrl = new URL(link.href, window.location.href);
|
||||||
|
} catch (_error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetUrl.origin !== window.location.origin) return false;
|
||||||
|
if (targetUrl.pathname === window.location.pathname && targetUrl.search === window.location.search) {
|
||||||
|
return targetUrl.hash && targetUrl.hash !== window.location.hash;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initPageTransitions() {
|
||||||
|
if (prefersReducedMotion()) return;
|
||||||
|
|
||||||
|
document.addEventListener('click', function(event) {
|
||||||
|
if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var link = event.target.closest ? event.target.closest('a[href]') : null;
|
||||||
|
if (!isInternalNavigation(link)) return;
|
||||||
|
|
||||||
|
var targetUrl = new URL(link.href, window.location.href);
|
||||||
|
if (targetUrl.pathname === window.location.pathname && targetUrl.search === window.location.search) return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
document.body.classList.add('page-leaving');
|
||||||
|
window.setTimeout(function() {
|
||||||
|
window.location.href = targetUrl.href;
|
||||||
|
}, transitionMs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', initPageTransitions, { once: true });
|
||||||
|
} else {
|
||||||
|
initPageTransitions();
|
||||||
|
}
|
||||||
|
})();
|
||||||
@@ -538,12 +538,15 @@ function initSecretsPage() {
|
|||||||
state.search = event.target.value || '';
|
state.search = event.target.value || '';
|
||||||
renderSecrets();
|
renderSecrets();
|
||||||
});
|
});
|
||||||
document.addEventListener('workspace:changed', function () {
|
window.addEventListener('crank:workspacechange', function () {
|
||||||
void load();
|
void load();
|
||||||
});
|
});
|
||||||
|
|
||||||
updateKindFields();
|
updateKindFields();
|
||||||
void load();
|
void (async function bootSecretsPage() {
|
||||||
|
await (window.whenWorkspacesReady ? window.whenWorkspacesReady() : Promise.resolve());
|
||||||
|
await load();
|
||||||
|
}());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.CrankDiagnostics && typeof window.CrankDiagnostics.bootstrap === 'function') {
|
if (window.CrankDiagnostics && typeof window.CrankDiagnostics.bootstrap === 'function') {
|
||||||
|
|||||||
+30
-5
@@ -1,6 +1,4 @@
|
|||||||
var WS_LIST = [
|
var WS_LIST = [];
|
||||||
{ id: 'ws_default', slug: 'default', name: 'Default workspace', role: 'Owner', letter: 'D', color: '#0d9488' }
|
|
||||||
];
|
|
||||||
|
|
||||||
var workspaceLoadPromise = null;
|
var workspaceLoadPromise = null;
|
||||||
var workspaceLoadFailed = false;
|
var workspaceLoadFailed = false;
|
||||||
@@ -41,8 +39,35 @@ function cacheCurrentWorkspace(workspace) {
|
|||||||
} catch (_error) {}
|
} catch (_error) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function storedWorkspaceId() {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem('crank_workspace_id') || '';
|
||||||
|
} catch (_error) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sessionWorkspaceId() {
|
||||||
|
if (!(window.CrankAuth && typeof window.CrankAuth.getCachedSession === 'function')) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
var session = window.CrankAuth.getCachedSession();
|
||||||
|
return session && session.current_workspace_id ? session.current_workspace_id : '';
|
||||||
|
}
|
||||||
|
|
||||||
function resolveCurrentWorkspace() {
|
function resolveCurrentWorkspace() {
|
||||||
return WS_LIST[0] || null;
|
var preferredId = sessionWorkspaceId() || storedWorkspaceId();
|
||||||
|
if (preferredId) {
|
||||||
|
var preferred = WS_LIST.find(function(workspace) {
|
||||||
|
return workspace.id === preferredId;
|
||||||
|
});
|
||||||
|
if (preferred) {
|
||||||
|
return preferred;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return WS_LIST.find(function(workspace) {
|
||||||
|
return workspace.id === 'ws_default';
|
||||||
|
}) || WS_LIST[0] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateWorkspaceHeader(workspace) {
|
function updateWorkspaceHeader(workspace) {
|
||||||
@@ -88,7 +113,7 @@ async function loadWorkspaces() {
|
|||||||
var response = await window.CrankApi.listWorkspaces();
|
var response = await window.CrankApi.listWorkspaces();
|
||||||
var items = (response && response.items ? response.items : []).map(mapWorkspace);
|
var items = (response && response.items ? response.items : []).map(mapWorkspace);
|
||||||
if (items.length > 0) {
|
if (items.length > 0) {
|
||||||
WS_LIST = [items[0]];
|
WS_LIST = items;
|
||||||
}
|
}
|
||||||
workspaceLoadFailed = false;
|
workspaceLoadFailed = false;
|
||||||
} catch (_error) {
|
} catch (_error) {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const BUNDLES = {
|
|||||||
'js/overlay-loader.js',
|
'js/overlay-loader.js',
|
||||||
'js/dom.js',
|
'js/dom.js',
|
||||||
'js/diagnostics.js',
|
'js/diagnostics.js',
|
||||||
|
'js/page-transitions.js',
|
||||||
'js/workspace.js',
|
'js/workspace.js',
|
||||||
'js/api.js',
|
'js/api.js',
|
||||||
'js/ui-feedback.js',
|
'js/ui-feedback.js',
|
||||||
|
|||||||
@@ -65,3 +65,22 @@ test('secret modal shows fields for selected secret kind only', async ({ page })
|
|||||||
await expect(basicField).toBeHidden();
|
await expect(basicField).toBeHidden();
|
||||||
await expect(jsonField).toBeHidden();
|
await expect(jsonField).toBeHidden();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('generic json secret modal stays inside compact viewport', async ({ page }) => {
|
||||||
|
await page.setViewportSize({ width: 900, height: 520 });
|
||||||
|
await login(page);
|
||||||
|
await page.goto('/secrets');
|
||||||
|
|
||||||
|
await page.locator('[data-testid="secret-create-button"]').click();
|
||||||
|
await page.locator('[data-testid="secret-kind-select"]').selectOption('generic');
|
||||||
|
|
||||||
|
const modal = page.locator('[data-testid="secret-create-modal"] .modal');
|
||||||
|
await expect(modal).toBeVisible();
|
||||||
|
|
||||||
|
const box = await modal.boundingBox();
|
||||||
|
expect(box).not.toBeNull();
|
||||||
|
expect(box.y).toBeGreaterThanOrEqual(0);
|
||||||
|
expect(box.y + box.height).toBeLessThanOrEqual(520);
|
||||||
|
await expect(page.locator('[data-testid="secret-name-input"]')).toBeVisible();
|
||||||
|
await expect(page.locator('[data-testid="secret-submit-button"]')).toBeVisible();
|
||||||
|
});
|
||||||
|
|||||||
@@ -272,17 +272,23 @@ impl PostgresRegistry {
|
|||||||
};
|
};
|
||||||
let memberships = self.list_workspaces_for_user(&user_id).await?;
|
let memberships = self.list_workspaces_for_user(&user_id).await?;
|
||||||
let stored_workspace_id = row.current_workspace_id.map(WorkspaceId::new);
|
let stored_workspace_id = row.current_workspace_id.map(WorkspaceId::new);
|
||||||
let current_workspace_id = stored_workspace_id
|
let default_workspace_id = memberships
|
||||||
.filter(|workspace_id| {
|
.iter()
|
||||||
memberships
|
.find(|membership| membership.workspace.id.as_str() == "ws_default")
|
||||||
.iter()
|
.map(|membership| membership.workspace.id.clone());
|
||||||
.any(|membership| membership.workspace.id == *workspace_id)
|
let current_workspace_id = default_workspace_id.or_else(|| {
|
||||||
})
|
stored_workspace_id
|
||||||
.or_else(|| {
|
.filter(|workspace_id| {
|
||||||
memberships
|
memberships
|
||||||
.first()
|
.iter()
|
||||||
.map(|membership| membership.workspace.id.clone())
|
.any(|membership| membership.workspace.id == *workspace_id)
|
||||||
});
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
memberships
|
||||||
|
.first()
|
||||||
|
.map(|membership| membership.workspace.id.clone())
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
Ok(Some(SessionRecord {
|
Ok(Some(SessionRecord {
|
||||||
session_id: UserSessionId::new(row.id),
|
session_id: UserSessionId::new(row.id),
|
||||||
|
|||||||
@@ -38,22 +38,22 @@ impl PostgresRegistry {
|
|||||||
&self,
|
&self,
|
||||||
user_id: &UserId,
|
user_id: &UserId,
|
||||||
) -> Result<Vec<WorkspaceMembershipRecord>, RegistryError> {
|
) -> Result<Vec<WorkspaceMembershipRecord>, RegistryError> {
|
||||||
let rows = sqlx::query!(
|
let rows = sqlx::query(
|
||||||
"select
|
"select
|
||||||
w.id,
|
w.id,
|
||||||
w.slug,
|
w.slug,
|
||||||
w.display_name,
|
w.display_name,
|
||||||
w.status,
|
w.status,
|
||||||
w.settings_json,
|
w.settings_json,
|
||||||
w.created_at as \"created_at!: time::OffsetDateTime\",
|
w.created_at,
|
||||||
w.updated_at as \"updated_at!: time::OffsetDateTime\",
|
w.updated_at,
|
||||||
m.role
|
m.role
|
||||||
from memberships m
|
from memberships m
|
||||||
join workspaces w on w.id = m.workspace_id
|
join workspaces w on w.id = m.workspace_id
|
||||||
where m.user_id = $1
|
where m.user_id = $1
|
||||||
order by w.slug asc",
|
order by (w.id = 'ws_default') desc, w.slug asc",
|
||||||
user_id.as_str(),
|
|
||||||
)
|
)
|
||||||
|
.bind(user_id.as_str())
|
||||||
.fetch_all(&self.pool)
|
.fetch_all(&self.pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@@ -61,15 +61,18 @@ impl PostgresRegistry {
|
|||||||
.map(|row| {
|
.map(|row| {
|
||||||
Ok(WorkspaceMembershipRecord {
|
Ok(WorkspaceMembershipRecord {
|
||||||
workspace: Workspace {
|
workspace: Workspace {
|
||||||
id: WorkspaceId::new(row.id),
|
id: WorkspaceId::new(row.try_get::<String, _>("id")?),
|
||||||
slug: row.slug,
|
slug: row.try_get("slug")?,
|
||||||
display_name: row.display_name,
|
display_name: row.try_get("display_name")?,
|
||||||
status: deserialize_enum_text(&row.status, "status")?,
|
status: deserialize_enum_text(
|
||||||
settings: row.settings_json,
|
&row.try_get::<String, _>("status")?,
|
||||||
created_at: row.created_at,
|
"status",
|
||||||
updated_at: row.updated_at,
|
)?,
|
||||||
|
settings: row.try_get("settings_json")?,
|
||||||
|
created_at: row.try_get("created_at")?,
|
||||||
|
updated_at: row.try_get("updated_at")?,
|
||||||
},
|
},
|
||||||
role: deserialize_enum_text(&row.role, "role")?,
|
role: deserialize_enum_text(&row.try_get::<String, _>("role")?, "role")?,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ use crank_registry::{
|
|||||||
DescriptorMetadata, OperationSampleMetadata, PlatformApiKeyRecord, PostgresRegistry,
|
DescriptorMetadata, OperationSampleMetadata, PlatformApiKeyRecord, PostgresRegistry,
|
||||||
PublishAgentRequest, PublishRequest, RegistryError, RegistryOperation, SampleKind,
|
PublishAgentRequest, PublishRequest, RegistryError, RegistryOperation, SampleKind,
|
||||||
SaveAuthProfileRequest, SaveDescriptorMetadataRequest, SaveSampleMetadataRequest,
|
SaveAuthProfileRequest, SaveDescriptorMetadataRequest, SaveSampleMetadataRequest,
|
||||||
WorkspaceRecord, YamlImportJobCompletion, YamlImportJobId, YamlImportJobStatus,
|
UpdateWorkspaceRequest, WorkspaceRecord, YamlImportJobCompletion, YamlImportJobId,
|
||||||
|
YamlImportJobStatus,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn test_workspace_id() -> WorkspaceId {
|
fn test_workspace_id() -> WorkspaceId {
|
||||||
@@ -151,6 +152,85 @@ async fn manages_workspace_read_paths() {
|
|||||||
database.cleanup().await;
|
database.cleanup().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn lists_default_workspace_first_for_community_sessions() {
|
||||||
|
let database = TestDatabase::new().await;
|
||||||
|
let registry = database.registry().await;
|
||||||
|
let default_workspace = Workspace {
|
||||||
|
id: WorkspaceId::new("ws_default"),
|
||||||
|
slug: "solo".to_owned(),
|
||||||
|
display_name: "Solo".to_owned(),
|
||||||
|
status: crank_core::WorkspaceStatus::Active,
|
||||||
|
settings: json!({}),
|
||||||
|
created_at: timestamp("2026-03-25T12:00:00Z"),
|
||||||
|
updated_at: timestamp("2026-03-25T12:00:00Z"),
|
||||||
|
};
|
||||||
|
let legacy_workspace = Workspace {
|
||||||
|
id: WorkspaceId::new("ws_growth_lab"),
|
||||||
|
slug: "growth-lab".to_owned(),
|
||||||
|
display_name: "Growth Lab".to_owned(),
|
||||||
|
status: crank_core::WorkspaceStatus::Active,
|
||||||
|
settings: json!({}),
|
||||||
|
created_at: timestamp("2026-03-25T12:01:00Z"),
|
||||||
|
updated_at: timestamp("2026-03-25T12:01:00Z"),
|
||||||
|
};
|
||||||
|
let user_id = registry
|
||||||
|
.upsert_bootstrap_user("community-owner@example.com", "Owner", "hashed-password")
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
registry
|
||||||
|
.create_workspace(CreateWorkspaceRequest {
|
||||||
|
workspace: &legacy_workspace,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
registry
|
||||||
|
.update_workspace(UpdateWorkspaceRequest {
|
||||||
|
workspace: &default_workspace,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
registry
|
||||||
|
.ensure_membership(&legacy_workspace.id, &user_id, MembershipRole::Owner)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
registry
|
||||||
|
.ensure_membership(&default_workspace.id, &user_id, MembershipRole::Owner)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let workspaces = registry.list_workspaces_for_user(&user_id).await.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(workspaces[0].workspace.id, WorkspaceId::new("ws_default"));
|
||||||
|
assert_eq!(workspaces[0].workspace.slug, "solo");
|
||||||
|
|
||||||
|
let session_id = UserSessionId::new("sess_workspace_default_first");
|
||||||
|
let secret_hash = "test-secret-hash";
|
||||||
|
registry
|
||||||
|
.create_user_session(
|
||||||
|
&session_id,
|
||||||
|
&user_id,
|
||||||
|
Some(&legacy_workspace.id),
|
||||||
|
secret_hash,
|
||||||
|
×tamp("2027-03-25T13:00:00Z"),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let session = registry
|
||||||
|
.get_user_session(&session_id, secret_hash)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
session.current_workspace_id,
|
||||||
|
Some(WorkspaceId::new("ws_default"))
|
||||||
|
);
|
||||||
|
|
||||||
|
database.cleanup().await;
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn manages_user_profile_and_workspace_access_reads() {
|
async fn manages_user_profile_and_workspace_access_reads() {
|
||||||
let database = TestDatabase::new().await;
|
let database = TestDatabase::new().await;
|
||||||
|
|||||||
Reference in New Issue
Block a user