Skip to content

Commit

Permalink
fix: 🐛 Add refresh button back (#2124)
Browse files Browse the repository at this point in the history
  • Loading branch information
ZedLi authored Jan 31, 2024
1 parent 4d3c993 commit 06cc64e
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 164 deletions.
20 changes: 20 additions & 0 deletions addons/core/addon/styles/addon.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,26 @@
.hds-table {
margin-bottom: 1rem;
}

.search-filtering-toolbar {
display: flex;

// TODO: Remove these copied styles by migrating to HDS for the toolbar refresher component.
// The original styles assumed we were using the old toolbar component under a "rose-toolbar" class.
.rose-button-inline-link-action {
font-size: 0.8125rem;
line-height: 1.8461538462;
font-weight: 600;
color: var(--stark);
display: inline-block;
vertical-align: middle;
padding: 0.375rem 1rem;
}

> :last-child {
margin-left: auto;
}
}
}

// Flyout with table
Expand Down
22 changes: 10 additions & 12 deletions addons/rose/app/styles/rose/components/toolbar/_info.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@
@use '../../variables/media';
@use '../../utilities/type';

.rose-toolbar {
.rose-toolbar-info {
@include type.type(button);
.rose-toolbar-info {
@include type.type(button);

color: var(--ui-gray);
position: relative;
display: inline-block;
vertical-align: middle;
white-space: nowrap;
overflow: hidden;
color: var(--ui-gray);
position: relative;
display: inline-block;
vertical-align: middle;
white-space: nowrap;
overflow: hidden;

$y-padding: sizing.rems(xxs) + sizing.rems(xxxs);
$y-padding: sizing.rems(xxs) + sizing.rems(xxxs);

padding: $y-padding sizing.rems(m) $y-padding sizing.rems(l);
}
padding: $y-padding sizing.rems(m) $y-padding sizing.rems(l);
}
86 changes: 56 additions & 30 deletions ui/desktop/app/routes/scopes/scope/projects/sessions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route {
@service session;
@service store;
@service ipc;
@service router;

// =attributes

Expand Down Expand Up @@ -66,8 +67,7 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route {
* all targets and all projects for filtering options for the current user.
* @return {Promise<{sessions: [SessionModel], projects: [ScopeModel], allSessions: [SessionModel], allTargets: [TargetModel], totalItems: number}>}
*/
async model({ targets, status, scopes, page, pageSize }, transition) {
const from = transition.from?.name;
async model({ targets, status, scopes, page, pageSize }) {
const projects = this.modelFor('scopes.scope.projects');
const orgScope = this.modelFor('scopes.scope');
// orgFilter used to narrow down resources to only those under
Expand Down Expand Up @@ -105,34 +105,11 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route {
const totalItems = sessions.meta?.totalItems;

// Query all sessions and all targets for defining filtering values if entering route for the first time
if (from !== 'scopes.scope.projects.sessions.index') {
const options = { pushToStore: false };
const allSessionsQuery = {
scope_id: orgScope.id,
recursive: true,
query: {
filters: {
user_id: [{ equals: this.session.data.authenticated.user_id }],
},
},
};
if (orgScope.isOrg && scopes.length === 0) {
allSessionsQuery.filter = orgFilter;
}
this.allSessions = await this.store.query(
'session',
allSessionsQuery,
options,
);
const allTargetsQuery = { scope_id: orgScope.id, recursive: true };
if (orgScope.isOrg) {
allTargetsQuery.filter = orgFilter;
}
this.allTargets = await this.store.query(
'target',
allTargetsQuery,
options,
);
if (!this.allSessions) {
await this.getAllSessions(orgScope, scopes, orgFilter);
}
if (!this.allTargets) {
await this.getAllTargets(orgScope, orgFilter);
}

return {
Expand All @@ -145,6 +122,39 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route {
};
}

async getAllTargets(orgScope, orgFilter) {
const allTargetsQuery = {
scope_id: orgScope.id,
recursive: true,
force_refresh: true,
};
if (orgScope.isOrg) {
allTargetsQuery.filter = orgFilter;
}
this.allTargets = await this.store.query('target', allTargetsQuery, {
pushToStore: false,
});
}

async getAllSessions(orgScope, scopes, orgFilter) {
const allSessionsQuery = {
scope_id: orgScope.id,
recursive: true,
query: {
filters: {
user_id: [{ equals: this.session.data.authenticated.user_id }],
},
},
force_refresh: true,
};
if (orgScope.isOrg && scopes.length === 0) {
allSessionsQuery.filter = orgFilter;
}
this.allSessions = await this.store.query('session', allSessionsQuery, {
pushToStore: false,
});
}

resetController(controller, isExiting, transition) {
const fromScope = transition.from.find(
(routeInfo) => routeInfo.name === 'scopes.scope',
Expand All @@ -166,4 +176,20 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route {
});
}
}

@action
async refreshAll() {
const orgScope = this.modelFor('scopes.scope');
const orgFilter = `"/item/scope/parent_scope_id" == "${orgScope.id}"`;

await this.getAllTargets(orgScope, orgFilter);
await this.getAllSessions(orgScope, [], orgFilter);

// Prime the store by searching for orgs only in case there are new org scopes;
// otherwise we won't be able to correctly peek the org scopes for their display name in the UI.
await this.store.query('scope', {});

// Refresh the proj scopes so our `modelFor` returns accurate data
this.router.refresh('scopes.scope.projects');
}
}
58 changes: 37 additions & 21 deletions ui/desktop/app/routes/scopes/scope/projects/targets/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,16 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route {
*
* @returns {Promise<{totalItems: number, targets: [TargetModel], projects: [ScopeModel], allTargets: [TargetModel] }> }
*/
async model(
{ search, scopes, availableSessions, types, page, pageSize },
transition,
) {
async model({ search, scopes, availableSessions, types, page, pageSize }) {
const orgScope = this.modelFor('scopes.scope');
// orgFilter used to narrow down resources to only those under
// the current org scope if org is not global
const orgFilter = `"/item/scope/parent_scope_id" == "${orgScope.id}"`;
await this.getAllTargets(transition, orgScope, orgFilter);

if (!this.allTargets) {
await this.getAllTargets(orgScope, orgFilter);
}

const projects = this.modelFor('scopes.scope.projects');

const filters = { scope_id: [], id: { values: [] }, type: [] };
Expand Down Expand Up @@ -172,26 +173,27 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route {
/**
* 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.
* @param transition
* @param orgScope
* @param orgFilter
* @returns {Promise<void>}
*/
async getAllTargets(transition, orgScope, orgFilter) {
const from = transition.from?.name;

async getAllTargets(orgScope, orgFilter) {
// Query all targets for defining filtering values if entering route for first time
if (from !== 'scopes.scope.projects.targets.index') {
const query = { scope_id: orgScope.id, recursive: true };
if (orgScope.isOrg) {
query.filter = orgFilter;
}
const options = { pushToStore: false };
const allTargets = await this.store.query('target', query, options);

// Filter out targets to which users do not have the connect ability
this.allTargets = allTargets.filter((target) =>
target.authorized_actions.includes('authorize-session'),
);
const query = {
scope_id: orgScope.id,
recursive: true,
force_refresh: true,
};
if (orgScope.isOrg) {
query.filter = orgFilter;
}
const options = { pushToStore: false };
const allTargets = await this.store.query('target', query, options);

// Filter out targets to which users do not have the connect ability
this.allTargets = allTargets.filter((target) =>
target.authorized_actions.includes('authorize-session'),
);
}

/**
Expand Down Expand Up @@ -233,4 +235,18 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route {
}
});
};

@action
async refreshAll() {
const orgScope = this.modelFor('scopes.scope');
const orgFilter = `"/item/scope/parent_scope_id" == "${orgScope.id}"`;
await this.getAllTargets(orgScope, orgFilter);

// Prime the store by searching for only orgs in case there are new org scopes;
// otherwise we won't be able to correctly peek the org scopes for their display name in the UI.
await this.store.query('scope', {});

// Refresh the proj scopes so our `modelFor` returns accurate data
this.router.refresh('scopes.scope.projects');
}
}
100 changes: 53 additions & 47 deletions ui/desktop/app/templates/scopes/scope/projects/sessions/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,60 @@

{{#if (or @model.sessions @model.allSessions)}}
{{#if @model.isClientDaemonRunning}}
<Hds::SegmentedGroup as |S|>
<S.Generic>
<Dropdown
@name={{t 'resources.target.title'}}
@itemOptions={{this.availableTargets}}
@checkedItems={{this.targets}}
@applyFilter={{fn this.applyFilter 'targets'}}
@isSearchable={{true}}
@listPosition='bottom-left'
/>
</S.Generic>
<S.Generic>
<Dropdown
@name={{t 'form.status.label'}}
@itemOptions={{this.sessionStatusOptions}}
@checkedItems={{this.status}}
@applyFilter={{fn this.applyFilter 'status'}}
/>
</S.Generic>
<S.Generic>
<Dropdown
@name={{t 'resources.scope.title'}}
@itemOptions={{this.availableScopes}}
@checkedItems={{this.scopes}}
@applyFilter={{fn this.applyFilter 'scopes'}}
@isSearchable={{true}}
as |FD selectItem itemOptions|
>
{{#let (group-by itemOptions 'scopeModel') as |orgs|}}
{{#each orgs as |org|}}
<FD.Generic>
<FlightIcon @name='org' />
{{org.key.displayName}}
</FD.Generic>
{{#each org.items as |project|}}
<FD.Checkbox
@value={{project.id}}
checked={{includes project.id this.scopes}}
{{on 'change' selectItem}}
>
{{project.displayName}}
</FD.Checkbox>
<div class='search-filtering-toolbar'>
<Hds::SegmentedGroup as |S|>
<S.Generic>
<Dropdown
@name={{t 'resources.target.title'}}
@itemOptions={{this.availableTargets}}
@checkedItems={{this.targets}}
@applyFilter={{fn this.applyFilter 'targets'}}
@isSearchable={{true}}
@listPosition='bottom-left'
/>
</S.Generic>
<S.Generic>
<Dropdown
@name={{t 'form.status.label'}}
@itemOptions={{this.sessionStatusOptions}}
@checkedItems={{this.status}}
@applyFilter={{fn this.applyFilter 'status'}}
/>
</S.Generic>
<S.Generic>
<Dropdown
@name={{t 'resources.scope.title'}}
@itemOptions={{this.availableScopes}}
@checkedItems={{this.scopes}}
@applyFilter={{fn this.applyFilter 'scopes'}}
@isSearchable={{true}}
as |FD selectItem itemOptions|
>
{{#let (group-by itemOptions 'scopeModel') as |orgs|}}
{{#each orgs as |org|}}
<FD.Generic>
<FlightIcon @name='org' />
{{org.key.displayName}}
</FD.Generic>
{{#each org.items as |project|}}
<FD.Checkbox
@value={{project.id}}
checked={{includes project.id this.scopes}}
{{on 'change' selectItem}}
>
{{project.displayName}}
</FD.Checkbox>
{{/each}}
{{/each}}
{{/each}}
{{/let}}
</Dropdown>
</S.Generic>
</Hds::SegmentedGroup>
{{/let}}
</Dropdown>
</S.Generic>
</Hds::SegmentedGroup>
<span>
<ToolbarRefresher @onClick={{route-action 'refreshAll'}} />
</span>
</div>

<FilterTags @filters={{this.filters}} />
{{/if}}
{{#if @model.sessions}}
Expand Down
Loading

0 comments on commit 06cc64e

Please sign in to comment.