Skip to content

Commit

Permalink
feat: 🎸 scope picker component (#2646)
Browse files Browse the repository at this point in the history
* feat: 🎸 scope picker component
---------

Co-authored-by: lisbet-alvarez <[email protected]>
Co-authored-by: Zhihe Li <[email protected]>
  • Loading branch information
3 people authored Feb 20, 2025
1 parent f941179 commit 00c9381
Show file tree
Hide file tree
Showing 10 changed files with 791 additions and 111 deletions.
3 changes: 3 additions & 0 deletions addons/core/translations/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ descriptions:
provider: This is the provider for this host catalog. The format of the host set filters are specific to each provider.
no-search-results: Sorry, we weren't able to find any {resource} for "{query}".
no-filter-results: Sorry, we weren’t able to find any {resource} within the filtered parameters.
and-more: ...and more
view-all-orgs: 'View all orgs ({total})'
view-all-projects: 'View all projects ({total})'
questions:
delete-confirm: Are you sure you want to delete this resource?
remove-confirm: Are you sure you want to remove this association?
Expand Down
2 changes: 1 addition & 1 deletion addons/rose/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
},
"dependencies": {
"@embroider/test-setup": "^2.1.1",
"@hashicorp/design-system-components": "^4.13.0",
"@hashicorp/design-system-components": "^4.16.0",
"codemirror": "5.65.7",
"ember-auto-import": "^2.8.1",
"ember-cli-babel": "^8.2.0",
Expand Down
99 changes: 99 additions & 0 deletions ui/admin/app/components/scope-picker/index.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}

<Hds::Dropdown
@enableCollisionDetection={{true}}
@matchToggleWidth={{true}}
{{! HDS provided class to automatically fade in/out }}
class='hds-side-nav-hide-when-minimized scope-picker'
as |D|
>
{{#let this.currentScope as |scope|}}
<D.ToggleButton
@text={{scope.name}}
@icon={{scope.icon}}
class='scope-picker__toggle-button'
/>
{{/let}}

<D.Checkmark
@icon='globe'
@route='scopes.scope'
@model='global'
@selected={{this.scope.org.isGlobal}}
>
{{t 'titles.global'}}
</D.Checkmark>

{{#if this.scope.orgsList}}
<D.Separator />

<D.Title @text={{t 'resources.org.title_plural'}} />
{{/if}}

{{#each this.truncatedOrgsList as |org|}}
<D.Checkmark
@icon='org'
@route='scopes.scope'
@model={{org.id}}
@selected={{and (eq this.scope.org.id org.id) (not this.scope.project)}}
data-test-scope-picker-org-item
>
{{org.displayName}}
</D.Checkmark>
{{/each}}

{{#if (gt this.scope.orgsList.length 5)}}
<D.Description
@text={{t 'descriptions.and-more'}}
data-test-scope-picker-org-and-more-text
/>

<D.Interactive
@route='scopes.scope.scopes'
@model='global'
data-test-scope-picker-org-count
>{{t
'descriptions.view-all-orgs'
total=this.scope.orgsList.length
}}</D.Interactive>
{{/if}}

{{! All project scopes in org are only loaded when current scope is of project type. }}
{{#if this.scope.project}}
<D.Title @text={{t 'resources.project.title_plural'}} class='indentation' />

{{#each this.truncatedProjectsList as |project|}}
<D.Checkmark
@icon='grid'
@route='scopes.scope'
@model={{project.id}}
@selected={{eq this.scope.project.id project.id}}
class='indentation'
data-test-scope-picker-project-item
>
{{project.displayName}}
</D.Checkmark>
{{/each}}

{{#if (gt this.scope.projectsList.length 5)}}
<D.Description
@text={{t 'descriptions.and-more'}}
class='indentation'
data-test-scope-picker-project-and-more-text
/>

<D.Interactive
@route='scopes.scope.scopes'
@model={{this.scope.org.id}}
class='indentation'
data-test-scope-picker-project-count
>{{t
'descriptions.view-all-projects'
total=this.scope.projectsList.length
}}</D.Interactive>
{{/if}}
{{/if}}
</Hds::Dropdown>
48 changes: 48 additions & 0 deletions ui/admin/app/components/scope-picker/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import orderBy from 'lodash/orderBy';

export default class ScopePickerIndexComponent extends Component {
// =services

@service intl;
@service scope;
@service session;

// =attributes

/**
* Returns display name and icon for current scope.
* @type {object}
*/
get currentScope() {
if (this.scope.project) {
return { name: this.scope.project.displayName, icon: 'grid' };
} else if (this.scope.org.isOrg) {
return { name: this.scope.org.displayName, icon: 'org' };
} else {
return { name: this.intl.t('titles.global'), icon: 'globe' };
}
}

/**
* Returns first five orgs ordered by most recently updated.
* @type {[ScopeModel]}
*/
get truncatedOrgsList() {
return orderBy(this.scope.orgsList, 'updated_time', 'desc').slice(0, 5);
}

/**
* Returns first five projects ordered by most recently updated.
* @type {[ScopeModel]}
*/
get truncatedProjectsList() {
return orderBy(this.scope.projectsList, 'updated_time', 'desc').slice(0, 5);
}
}
1 change: 1 addition & 0 deletions ui/admin/app/controllers/scopes/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export default class ScopesScopeController extends Controller {
// =services

@service session;
@service scope;
}
24 changes: 0 additions & 24 deletions ui/admin/app/routes/scopes/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,29 +72,5 @@ export default class ScopesScopeRoute extends Route {
this.scope.project = selectedProject;
this.scope.orgsList = orgs;
this.scope.projectsList = projects;
this.scopes = { orgs, projects, selectedOrg, selectedProject };
// Update the controller (if exists), since setupController is only
// called once the first time the route is activated. It is not called
// again on route refreshes.
/* eslint-disable-next-line ember/no-controller-access-in-routes */
if (this.controller) this.setControllerProperties(this.scopes);
}

/**
* Adds the scopes hash to the controller context (see `afterModel`).
* @param {Controller} controller
*/
setupController(/* controller */) {
super.setupController(...arguments);
this.setControllerProperties(this.scopes);
}

/**
* Updates the controller's `scopes`.
* @param {array} scopes
*/
setControllerProperties(scopes) {
/* eslint-disable-next-line ember/no-controller-access-in-routes */
this.controller.setProperties({ scopes });
}
}
12 changes: 12 additions & 0 deletions ui/admin/app/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1083,3 +1083,15 @@
margin-bottom: 0;
}
}

// scope picker
.scope-picker {
&__toggle-button {
width: 100%;
}

li:has(.indentation),
li.indentation {
margin-left: 2rem;
}
}
6 changes: 3 additions & 3 deletions ui/admin/app/templates/scopes/scope.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@

{{#if @model.isProject}}
{{page-title (t 'resources.org.title_plural')}}
{{page-title this.scopes.selectedOrg.displayName}}
{{page-title this.scope.org.displayName}}
{{page-title (t 'resources.project.title_plural')}}
{{page-title @model.displayName}}
<Breadcrumbs::Item
@text={{this.scopes.selectedOrg.displayName}}
@text={{this.scope.org.displayName}}
@icon='org'
@route='scopes.scope.edit'
@model={{this.scopes.selectedOrg.id}}
@model={{this.scope.org.id}}
/>
<Breadcrumbs::Item
@text={{@model.displayName}}
Expand Down
Loading

0 comments on commit 00c9381

Please sign in to comment.