Skip to content

feat: Atlas data source access-state UI (#2963 #2959) - #3213

Open
ohdsi-trex wants to merge 1 commit into
mainfrom
trex/atlas-access-state-clean
Open

feat: Atlas data source access-state UI (#2963 #2959)#3213
ohdsi-trex wants to merge 1 commit into
mainfrom
trex/atlas-access-state-clean

Conversation

@ohdsi-trex

Copy link
Copy Markdown
Collaborator

Implements access-state badges (read, pending, restricted, no_access) on Atlas data source list and detail pages per Figma designs in issues #2963 and #2959. UI changes scoped to plugins/atlas only. Write state omitted per design.

Copilot AI balanced review requested due to automatic review settings August 26, 2026 08:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds server-derived data-source access states and an Atlas list/detail experience with access-request handling.

Changes:

  • Derives read, write, pending, restricted, and no-access states.
  • Adds current-user request lookup and request submission.
  • Implements Atlas cards, sorting, detail views, badges, and styling.

Reviewed changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 19 comments.

Show a summary per file
File Description
plugins/functions/portal/src/user-mgmt/user-mgmt.service.ts Wraps authenticated user-management calls.
plugins/functions/portal/src/user-mgmt/user-mgmt.mock.ts Adds user-management mocks.
plugins/functions/portal/src/user-mgmt/user-mgmt.api.ts Fetches memberships and pending requests.
plugins/functions/portal/src/types.d.ts Defines access-state response types.
plugins/functions/portal/src/dataset/query/dataset-query.service.ts Derives access states for datasets.
plugins/functions/portal/src/dataset/query/dataset-query.service.spec.ts Tests access-state precedence.
plugins/functions/alp-usermgmt/src/types.ts Adds membership/request types.
plugins/functions/alp-usermgmt/src/routes/StudyAccessRequestRouter.ts Adds current-user request retrieval.
plugins/atlas/src/portal-main.ts Mounts and routes the Atlas data-source UI.
plugins/atlas/src/data-sources/use-data-sources.ts Manages loading, sorting, and requests.
plugins/atlas/src/data-sources/types.ts Defines Atlas data-source models.
plugins/atlas/src/data-sources/DataSourceListPage.vue Implements the list page.
plugins/atlas/src/data-sources/DataSourceDetailPage.vue Implements the detail page.
plugins/atlas/src/data-sources/DataSourceDetailHeader.vue Displays detail access actions.
plugins/atlas/src/data-sources/DataSourceCard.vue Displays source cards and badges.
plugins/atlas/src/data-sources/data-sources.css Styles the new experience.
plugins/atlas/src/data-sources/data-source-api.ts Adds portal and request API calls.
plugins/atlas/src/data-sources/AccessStatusBadge.vue Renders access-state badges.
plans/atlas-data-sources-access-state.md Documents scope and implementation plan.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +26 to +34
export function getDataSources(token: string, searchText?: string): Promise<DataSource[]> {
const search = new URLSearchParams();
if (searchText) search.set('searchText', searchText);
const query = search.toString();
return request<DataSource[]>(
`${SYSTEM_PORTAL_URL}/dataset/list${query ? `?${query}` : ''}`,
token,
);
}
Comment on lines +30 to +31
return request<DataSource[]>(
`${SYSTEM_PORTAL_URL}/dataset/list${query ? `?${query}` : ''}`,
}

async getDatasets(queryParams?: IDatasetQueryDto) {
const { role, searchText, ...filterParams } = queryParams;
Comment on lines +39 to +48
const { studyId, role } = req.body || {}
const userId = req.user.userId

if (!studyId) {
this.logger.warn(`Param 'studyId' is required`)
return res.status(400).send({ message: `Param 'studyId' is required` })
} else if (!role) {
this.logger.warn(`Param 'role' is required`)
return res.status(400).send({ message: `Param 'role' is required` })
}
Comment on lines +52 to +55
const check = await this.groupService.getGroupByStudyRole(studyId, role)
if (check == null) {
this.logger.info(`Group ${role} does not exist. Creating role...`)
await this.groupService.createGroup({ role, tenantId, studyId })
.access-status--read { background: #dcfce7; color: #166534; }
.access-status--pending { background: #fef3c7; color: #92400e; }
.access-status--restricted { background: #fee2e2; color: #b91c1c; }
.access-status--no_access { background: #e5e7eb; color: #4b5563; }
Comment on lines +32 to +33
window.addEventListener('popstate', syncRoute);
window.addEventListener('hashchange', syncRoute);
setup() {
const pluginProps = inject<PluginProps>('pluginProps');
const getToken = pluginProps?.getToken ?? (async () => pluginProps?.authContext?.token ?? '');
const isAuthenticated = computed(() => Boolean(pluginProps?.getToken || pluginProps?.authContext?.isAuthenticated));
<div><dt>Data source name</dt><dd>{{ source.datasetDetail.name }}</dd></div>
<div><dt>Type</dt><dd>{{ source.type || 'Not specified' }}</dd></div>
<div><dt>Data model</dt><dd>{{ source.dataModel || 'Not specified' }}</dd></div>
<div><dt>Schema</dt><dd>{{ source.tokenDatasetCode || 'Not specified' }}</dd></div>
@@ -0,0 +1,34 @@
<template>
<span class="access-status" :class="`access-status--${visualState}`" :title="tooltip">
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.

2 participants