feat: 🎸 target list will update according to org scope selected (#2083)

* feat: 🎸 target list will update according to org scope selected

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12205

* refactor: 💡 add comment to resetController logic

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12205

* feat: 🎸 filter sessions by org selected at global level

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12205
This commit is contained in:
Cameron Perera authored and Zhihe Li committed 2024-01-16 10:17:46 -05:00
1 parent ba0c7d5683
commit 9046c01238
6 files changed
+171 -29

No files matched your search

@@ -62,6 +62,8 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route {
*/
async model({ targets, status, scopes, page, pageSize }, transition) {
const from = transition.from?.name;
const projects = this.modelFor('scopes.scope.projects');
const projectIds = projects.map((project) => project.id);
const filters = {
user_id: [{ equals: this.session.data.authenticated.user_id }],
@@ -78,6 +80,11 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route {
scopes.forEach((scope) => {
filters.scope_id.push({ equals: scope });
});
if (scopes.length === 0) {
projectIds.forEach((projectId) => {
filters.scope_id.push({ equals: projectId });
});
}
const queryOptions = {
query: { filters },
@@ -105,8 +112,6 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route {
this.allTargets = await this.store.query('target', {}, options);
}
const projects = this.modelFor('scopes.scope.projects');
return {
sessions,
projects,
@@ -115,4 +120,14 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route {
totalItems,
};
}
resetController(controller, isExiting, transition) {
const { to } = transition;
// Reset the scopes query param when changing org scope
if (!isExiting && to.queryParams.scopes === '[]') {
controller.setProperties({
scopes: [],
});
}
}
}
@@ -84,11 +84,18 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route {
transition,
) {
await this.getAllTargets(transition);
const projects = this.modelFor('scopes.scope.projects');
const projectIds = projects.map((project) => project.id);
const filters = { scope_id: [], id: { values: [] }, type: [] };
scopes.forEach((scope) => {
filters.scope_id.push({ equals: scope });
});
if (scopes.length === 0) {
projectIds.forEach((projectId) => {
filters.scope_id.push({ equals: projectId });
});
}
types.forEach((type) => {
filters.type.push({ equals: type });
});
@@ -124,7 +131,6 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route {
targets = targets.filter((target) =>
this.can.can('connect target', target),
);
const projects = this.modelFor('scopes.scope.projects');
return {
targets,
@@ -134,6 +140,16 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route {
};
}
resetController(controller, isExiting, transition) {
const { to } = transition;
// Reset the scopes query param when changing org scope
if (!isExiting && to.queryParams.scopes === '[]') {
controller.setProperties({
scopes: [],
});
}
}
/**
* Get all the targets but only load them once when entering the route. Ideally we would lazy load it when needed
* but this can be revisited in the future.
@@ -84,7 +84,7 @@
<LinkTo
@route='scopes.scope.projects.sessions.session.index'
@model={{B.data.id}}
data-test-session-detail-link
data-test-session-detail-link={{B.data.id}}
>
<Hds::Text::Code>{{B.data.id}}</Hds::Text::Code>
</LinkTo>
@@ -101,7 +101,7 @@
@acknowledgeText={{t 'states.copied'}}
>
<Hds::Text::Code
data-test-session-id-copy
data-test-session-id-copy={{B.data.id}}
>{{B.data.id}}</Hds::Text::Code>
</Copyable>
{{/if}}
@@ -127,7 +127,9 @@
@buttonText={{t 'actions.copy-to-clipboard'}}
@acknowledgeText={{t 'states.copied'}}
>
<Hds::Text::Code>{{B.data.project.id}}</Hds::Text::Code>
<Hds::Text::Code
data-test-target-project-id={{B.data.project.id}}
>{{B.data.project.id}}</Hds::Text::Code>
</Copyable>
</div>
{{#if B.data.project.name}}
@@ -35,19 +35,25 @@ module('Acceptance | projects | sessions | index', function (hooks) {
scopes: {
global: null,
org: null,
org2: null,
project: null,
project2: null,
},
authMethods: {
global: null,
},
user: null,
target: null,
target2: null,
session: null,
session2: null,
};
const urls = {
scopes: {
global: null,
org: null,
org2: null,
},
authenticate: {
global: null,
@@ -56,7 +62,9 @@ module('Acceptance | projects | sessions | index', function (hooks) {
},
},
projects: null,
projects2: null,
sessions: null,
sessions2: null,
session: null,
};
@@ -74,7 +82,10 @@ module('Acceptance | projects | sessions | index', function (hooks) {
authenticateSession({ user_id: instances.user.id });
// create scopes
instances.scopes.global = this.server.create('scope', { id: 'global' });
instances.scopes.global = this.server.create('scope', {
id: 'global',
name: 'Global',
});
const globalScope = { id: 'global', type: 'global' };
instances.scopes.org = this.server.create('scope', {
type: 'org',
@@ -85,7 +96,17 @@ module('Acceptance | projects | sessions | index', function (hooks) {
type: 'project',
scope: orgScope,
});
instances.scopes.org2 = this.server.create('scope', {
type: 'org',
scope: globalScope,
});
const org2Scope = { id: instances.scopes.org2.id, type: 'org' };
instances.scopes.project2 = this.server.create('scope', {
type: 'project',
scope: org2Scope,
});
// create resources
instances.authMethods.global = this.server.create('auth-method', {
scope: instances.scopes.global,
});
@@ -104,13 +125,33 @@ module('Acceptance | projects | sessions | index', function (hooks) {
},
'withAssociations',
);
// create resources in second org
instances.target2 = this.server.create(
'target',
{ scope: instances.scopes.project2 },
'withAssociations',
);
instances.session2 = this.server.create(
'session',
{
scope: instances.scopes.project2,
target: instances.target2,
status: STATUS_SESSION_ACTIVE,
user: instances.user,
},
'withAssociations',
);
urls.scopes.global = `/scopes/${instances.scopes.global.id}`;
urls.scopes.org = `/scopes/${instances.scopes.org.id}`;
urls.scopes.org2 = `/scopes/${instances.scopes.org2.id}`;
urls.authenticate.global = `${urls.scopes.global}/authenticate`;
urls.authenticate.methods.global = `${urls.authenticate.global}/${instances.authMethods.global.id}`;
urls.projects = `${urls.scopes.org}/projects`;
urls.projects2 = `${urls.scopes.org2}/projects`;
urls.globalSessions = `${urls.scopes.global}/projects/sessions`;
urls.sessions = `${urls.projects}/sessions`;
urls.sessions2 = `${urls.projects2}/sessions`;
urls.session = `${urls.projects}/sessions/${instances.session.id}`;
// Mock the postMessage interface used by IPC.
@@ -169,7 +210,7 @@ module('Acceptance | projects | sessions | index', function (hooks) {
await visit(urls.projects);
await click(`[href="${urls.sessions}"]`);
await click('[data-test-session-detail-link]');
await click(`[data-test-session-detail-link="${instances.session.id}"]`);
assert.strictEqual(currentURL(), urls.session);
});
@@ -181,9 +222,7 @@ module('Acceptance | projects | sessions | index', function (hooks) {
await visit(urls.sessions);
assert
.dom(
'tbody tr:first-child td:first-child [data-test-session-detail-link]',
)
.dom(`[data-test-session-detail-link="${instances.session.id}"]`)
.isVisible();
});
@@ -195,9 +234,7 @@ module('Acceptance | projects | sessions | index', function (hooks) {
await click(`[href="${urls.sessions}"]`);
assert
.dom(
'tbody tr:first-child td:first-child [data-test-session-detail-link]',
)
.dom(`[data-test-session-detail-link="${instances.session.id}"]`)
.isVisible();
});
@@ -209,9 +246,7 @@ module('Acceptance | projects | sessions | index', function (hooks) {
await click(`[href="${urls.sessions}"]`);
assert
.dom(
'tbody tr:first-child td:first-child [data-test-session-detail-link]',
)
.dom(`[data-test-session-detail-link="${instances.session.id}"]`)
.isVisible();
});
@@ -223,9 +258,7 @@ module('Acceptance | projects | sessions | index', function (hooks) {
await click(`[href="${urls.sessions}"]`);
assert
.dom(
'tbody tr:first-child td:first-child [data-test-session-detail-link]',
)
.dom(`[data-test-session-detail-link="${instances.session.id}"]`)
.isVisible();
});
@@ -235,12 +268,10 @@ module('Acceptance | projects | sessions | index', function (hooks) {
await visit(urls.sessions);
assert
.dom(
'tbody tr:first-child td:first-child [data-test-session-detail-link]',
)
.dom(`[data-test-session-detail-link="${instances.session.id}"]`)
.doesNotExist();
assert
.dom('tbody tr:first-child td:first-child [data-test-session-id-copy]')
.dom(`[data-test-session-id-copy="${instances.session.id}"]`)
.isVisible();
});
@@ -250,12 +281,10 @@ module('Acceptance | projects | sessions | index', function (hooks) {
await visit(urls.sessions);
assert
.dom(
'tbody tr:first-child td:first-child [data-test-session-detail-link]',
)
.dom(`[data-test-session-detail-link="${instances.session.id}"]`)
.doesNotExist();
assert
.dom('tbody tr:first-child td:first-child [data-test-session-id-copy]')
.dom(`[data-test-session-id-copy="${instances.session.id}"]`)
.isVisible();
});
@@ -332,4 +361,41 @@ module('Acceptance | projects | sessions | index', function (hooks) {
assert.dom('[role="alert"].is-error').isVisible();
});
test('user can change org scope and only sessions for that org will be displayed', async function (assert) {
this.stubClientDaemonSearch(
'sessions',
'sessions',
'targets',
'targets',
'sessions',
'targets',
{
resource: 'sessions',
func: () => [instances.session2],
},
'sessions',
'targets',
);
await visit(urls.globalSessions);
assert
.dom(`[data-test-session-detail-link="${instances.session.id}"]`)
.isVisible();
assert
.dom(`[data-test-session-detail-link="${instances.session2.id}"]`)
.isVisible();
// change scope in app header
await click('.rose-header-nav .rose-dropdown a:nth-of-type(3)');
// navigate to back sessions
await click(`[href="${urls.sessions2}"]`);
assert
.dom(`[data-test-session-detail-link="${instances.session.id}"]`)
.doesNotExist();
assert
.dom(`[data-test-session-detail-link="${instances.session2.id}"]`)
.isVisible();
});
});
@@ -47,12 +47,15 @@ module('Acceptance | projects | targets | index', function (hooks) {
scopes: {
global: null,
org: null,
org2: null,
project: null,
project2: null,
},
authMethods: {
global: null,
},
target: null,
target2: null,
session: null,
};
@@ -85,7 +88,10 @@ module('Acceptance | projects | targets | index', function (hooks) {
this.server.get('/targets', ({ targets }) => targets.all());
// Generate scopes
instances.scopes.global = this.server.create('scope', { id: 'global' });
instances.scopes.global = this.server.create('scope', {
id: 'global',
name: 'Global',
});
const globalScope = { id: 'global', type: 'global' };
instances.scopes.org = this.server.create('scope', {
type: 'org',
@@ -96,6 +102,15 @@ module('Acceptance | projects | targets | index', function (hooks) {
type: 'project',
scope: orgScope,
});
instances.scopes.org2 = this.server.create('scope', {
type: 'org',
scope: globalScope,
});
const org2Scope = { id: instances.scopes.org2.id, type: 'org' };
instances.scopes.project2 = this.server.create('scope', {
type: 'project',
scope: org2Scope,
});
// Generate resources
instances.authMethods.global = this.server.create('auth-method', {
@@ -119,6 +134,10 @@ module('Acceptance | projects | targets | index', function (hooks) {
},
'withAssociations',
);
instances.target2 = this.server.create('target', {
scope: instances.scopes.project2,
address: 'localhost',
});
// Generate route URLs for resources
urls.scopes.global = `/scopes/${instances.scopes.global.id}`;
@@ -412,4 +431,28 @@ module('Acceptance | projects | targets | index', function (hooks) {
assert.strictEqual(currentURL(), urls.session);
});
test('user can change org scope and only targets for that org will be displayed', async function (assert) {
this.stubClientDaemonSearch('targets', 'sessions', 'targets', 'sessions', {
resource: 'targets',
func: () => [instances.target],
});
await visit(urls.scopes.global);
assert
.dom(`[data-test-target-project-id="${instances.scopes.project.id}"]`)
.exists();
assert
.dom(`[data-test-target-project-id="${instances.scopes.project2.id}"]`)
.exists();
await click('.rose-header-nav .rose-dropdown a:nth-of-type(2)');
assert
.dom(`[data-test-target-project-id="${instances.scopes.project.id}"]`)
.exists();
assert
.dom(`[data-test-target-project-id="${instances.scopes.project2.id}"]`)
.doesNotExist();
});
});