Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 🎸 scope picker component #2646

Merged
merged 17 commits into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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