Compare commits

..
64 Commits
Author SHA1 Message Date
Carlos Alcaide Corvo eb36cde137 Update polling intervarl (#1100) 2022-05-04 09:51:16 -07:00
Cameron PereraandZhihe Li ccb266ea7c chore: 🤖 bump binary version and update changelog (#1099)
* chore: 🤖 bump binary version and update changelog

* chore: 🤖 Update Desktop app release date

* chore: 🤖 Update release date

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2022-05-04 10:32:42 -05:00
ZedandRandall Morey 8545697b43 Add toolbar regions to align refresh button to the right (#1098)
* feat: 🎸 implement toolbar regions and apply to admin sessions

* feat: 🎸 Add toolbar regions for desktop sessions and targets

✅ Closes: ICU-4198

Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-05-03 09:46:47 -04:00
Zed a8ae8d28df fix: 🐛 Reduce extra padding in tables (#1091)
✅ Closes: ICU-4046
2022-05-02 10:14:21 -04:00
Cameron Perera 952b894a32 feat: 🎸 Add ToolbarRefresher component to targets in desktop (#1093)
✅ Closes: ICU-4134
2022-04-29 18:06:11 -05:00
Cameron Perera 6f449b3b9b feat: 🎸 Add ToolbarRefresher component to sessions in admin (#1092)
✅ Closes: ICU-4133
2022-04-29 17:54:08 -05:00
Cameron PereraandRandall Morey 0f3c2f043b style: 💄 Update Refresh Button to animate when loading (#1089)
* style: 💄 Update Refresh Button to animate when loading

* refactor: 💡 Move temporary animation styles to app level styles

Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-04-29 15:29:53 -05:00
Dharini Jeeva 82c94518d9 feat: refresh sessions view in admin ui (#1078) 2022-04-29 14:28:50 -04:00
Randall Morey 68a269efac feature: add toolbar refresher component (#1088) 2022-04-29 13:51:47 -04:00
Zed 75ef323e6d fix: 🐛 Desktop client not correctly loading ember app url (#1090) 2022-04-29 13:38:25 -04:00
Carlos Alcaide Corvo ccde5e88da fix: 🐛 Mac os window lifecycle (#1067) 2022-04-29 09:03:40 -07:00
Carlos Alcaide Corvo 1071241604 chore: 🤖 Increase polling time Admin UI (#1085) 2022-04-29 07:47:03 -07:00
Zed 316f0907fc fix: 🐛 Fix scrollbar for the sidebar in desktop client (#1076)
Fixed scroll bar always appearing in sidebar on macOS for desktop client
and sidebar not staying fixed in windows and linux

✅ Closes: ICU-4143
2022-04-29 10:16:34 -04:00
Cameron Perera 3bdae6dce8 feat: 🎸 refresh targets list view in desktop (#1087)
✅ Closes: ICU-4024
2022-04-28 17:35:52 -05:00
Carlos Alcaide Corvo 367545fd4d refactor: 💡 Encapsulate desktop client window creation (#1066)
Encapsulate desktop client window creation to reuse the creation of new
windows.
2022-04-28 15:23:43 -07:00
Randall Morey 702ad64716 Style toolbar buttons (#1086)
* chore: 🤖 move loading-button component to core addon

* style: toolbar buttons should align with Structure

* fix: buttons should have consistent font
2022-04-28 17:59:43 -04:00
Randall Morey 043dbc3736 chore: 🤖 move loading-button component to core addon (#1083) 2022-04-28 17:49:03 -04:00
Cameron Perera 01e4ec0a07 feat: 🎸 Add minimum refresh time to refresh button for sessions (#1077) 2022-04-28 16:35:46 -04:00
Randall Morey a7b3da2231 feat: 🎸 implement live relative datetime component (#1080) 2022-04-28 16:23:44 -04:00
Randall Morey de6416efbd feat: 🎸 add non-interactive rose toolbar info component (#1075) 2022-04-28 16:01:50 -04:00
76befc0c1d chore: 🤖 Increaase polling time desktop client (#1074)
Increase polling time within desktop client.

Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-04-28 15:48:33 -04:00
Carlos Alcaide Corvo f71d01902a Revert "feat: 🎸 Add feature editions (#1072)" (#1079)
This reverts commit 56d84d652b.
2022-04-28 12:14:27 -07:00
Carlos Alcaide Corvo 56d84d652b feat: 🎸 Add feature editions (#1072)
Add feature editions
2022-04-28 10:23:35 -07:00
Dharini Jeeva 9cf216179a feat: refresh sessions list view in desktop (#1069)
* feat: 🎸 add a refresh button to sessions list view in desktop
2022-04-28 08:49:37 -07:00
Zed 050cfdd056 fix: 🐛 Fix scrollbars not being dark in dark mode (#1068)
✅ Closes: ICU-4022
2022-04-27 18:18:24 -04:00
Carlos Alcaide Corvo 79fb0db882 docs: ✏️ Update node supported versions (#1071)
Update node supported versions
2022-04-26 17:06:10 -07:00
Cameron Perera a2c6bc643d chore: 🤖 Update the .template-lintrc.js file in addons/rose (#1073)
✅ Closes: ICU-4123
2022-04-26 14:56:13 -05:00
Zed 07ed40ce03 fix: 🐛 Adjusted dark mode gray scale and fixed radio card colors (#1065)
Adjusted dark mode gray scale to be a bit darker and 
made the active selected radio card lighter in dark mode

✅ Closes: ICU-4021
2022-04-26 11:28:02 -04:00
Cameron Perera e0cbbefb41 fix: 🐛 Fix new target navigation issue (#1070)
Fix issue where trying to leave the new target form via the discard
changes dialog would cause the user to have to refresh screen.

✅ Closes: ICU-4047
2022-04-26 08:21:11 -05:00
Carlos Alcaide Corvo 2a1e4858fa chore: 🤖 Update Electron from 12.x to 13.x (#1063) 2022-04-21 12:46:41 -07:00
Cameron Perera 7b154b223a feat: 🎸 Update Target types help text (#1064)
* feat: 🎸 Update Target types help text

✅ Closes: ICU-4014

* refactor: 💡 Update how radio cards determine height

Radio cards will now fill up the entire height of the fieldset they are
in

* style: 💄 Update radio card padding
2022-04-21 13:51:47 -05:00
Carlos Alcaide Corvo 550cadf612 Revert "fix: 🐛 Disable polling for sessions on Desktop (#1058)" (#1062)
This reverts commit 26e074dbef.
2022-04-19 13:22:47 -07:00
Carlos Alcaide Corvo 95cece1481 Revert "fix: 🐛 Disable polling for targets on Desktop (#1059)" (#1061)
This reverts commit 6249e945b8.
2022-04-19 13:06:42 -07:00
Carlos Alcaide Corvo 94a3c1fcf1 Revert "disable polling in admin UI (#1057)" (#1060)
This reverts commit 90c9fa8b73.
2022-04-19 12:51:03 -07:00
Cameron PereraandDharini Jeeva f2b53d2f45 chore: 🤖 Updated pr-template to include Jira base url (#1055)
Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
2022-04-19 09:35:14 -05:00
Cameron Perera 6249e945b8 fix: 🐛 Disable polling for targets on Desktop (#1059)
✅ Closes: ICU-3954
2022-04-19 09:22:13 -05:00
Cameron Perera 26e074dbef fix: 🐛 Disable polling for sessions on Desktop (#1058)
✅ Closes: ICU-3953
2022-04-19 09:10:09 -05:00
Dharini Jeeva 90c9fa8b73 disable polling in admin UI (#1057)
* fix: 🐛 disable sessions polling

* increase sessions count

* fix: 🐛 undo mirage test
2022-04-18 18:08:23 -04:00
Zed 215bf00407 test: 💍 Verify target worker filter is created correctly (#1056)
✅ Closes: ICU-3893
2022-04-15 16:00:03 -04:00
Cameron Perera d8efefc2b3 test: 💍 Verify target worker filter can be edited (#1054)
✅ Closes: ICU-3892
2022-04-15 13:52:31 -05:00
Cameron Perera 95ed2c0fda feat: 🎸 Add worker filter field in target form (#1053)
* feat: 🎸 Add worker filter field in target form

✅ Closes: ICU-3891

* feat: 🎸 Add Learn More link to Worker Filter input field
2022-04-14 15:27:36 -05:00
Carlos Alcaide Corvo 8776b46277 Chore update eslint (#1045)
Update eslint and eslint-plugin-ember to their latest versions.
2022-04-13 14:17:46 -07:00
Zed 670f38df74 feat: 🎸 Add mirage data for the worker_filter (#1051)
* feat: 🎸 Add mirage data for the "worker_filter" attribute

✅ Closes: ICU-3888
2022-04-12 17:42:13 -04:00
Cameron PereraandDharini Jeeva 226475a47d feat: 🎸 Add "worker_filter" attribute to target model (#1049)
* feat: 🎸 Add "worker_filter" attribute to target model

✅ Closes: ICU-3887

* feat: 🎸 Add missing attribute description for worker_filter

* feat: 🎸 Update worker_filter description

Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
2022-04-12 16:16:51 -05:00
Dharini Jeeva 1072be1eff refactor: 💡 improve target creation (#1050)
* refactor: 💡 improve target creation UX
2022-04-12 14:05:16 -07:00
Carlos Alcaide Corvo 22d8af72ae Feat add build admin UI workflow (#1048)
* chore: 🤖 Add build admin UI workflow
2022-04-08 14:57:20 -07:00
Cameron Perera 79596010e9 feat: 🎸 Update Success Dialog when connecting to target (#1046)
Updated the Success Dialog in desktop app when connecting to a target to
dynamically show target type

✅ Closes: ICU-3647
2022-04-08 14:15:32 -05:00
Carlos Alcaide Corvo 8e884d53ae Revert "chore: 🤖 Add build admin UI workflow (#1043)" (#1047)
This reverts commit 505820eb6c.
2022-04-08 09:06:22 -07:00
Carlos Alcaide Corvo 505820eb6c chore: 🤖 Add build admin UI workflow (#1043)
* chore: 🤖 Add build admin UI workflow
2022-04-08 08:41:48 -07:00
Carlos Alcaide Corvo 4b09c7014b Chore update babel parser (#1044)
Update babel-parser and dependencies.
2022-04-07 14:39:59 -07:00
Cameron Perera f4535c8307 test: 💍 Add tests specific to SSH target creation
* test: 💍 Add tests specific to SSH target creation

* test: 💍 creating new SSH target when enabled or disabled

Verifying the link to create new SSH targets is not present when
ssh-targets is not enabled

* refactor: update create targets acceptance test names
2022-04-06 09:30:49 -05:00
Dharini Jeeva 9fae8f2a9f feat: create ssh type target in admin-ui (#1027)
* feat: 🎸 create ssh type target in admin-UI
2022-03-31 15:34:24 -07:00
Carlos Alcaide Corvo a7bcc0c332 chore: 🤖 Update plist version on desktop (#1040)
Update plist version resolutions on desktop as per dependabot alert.
2022-03-31 10:40:57 -07:00
Dharini Jeeva f877477cd7 feat: 🎸 update target route to support ssh type (#1038)
* feat: 🎸 update target route to support ssh type
2022-03-31 09:50:03 -07:00
Carlos Alcaide Corvo 335df22a38 chore: 🤖 Update plist on admin resolutions (#1039)
Update plist version on admin resolutions as per dependabot alert.
2022-03-31 09:06:34 -07:00
Carlos Alcaide Corvo ca09b538f7 chore: 🤖 Add minimist to desktop resolutions (#1034)
Add minimist to desktop resolutions as per dependabot alert.
2022-03-28 14:10:33 -07:00
Carlos Alcaide Corvo 68ba653984 chore: 🤖 Add minimist to admin resolutions (#1032)
Add minimist to admin resolutions
2022-03-28 13:47:32 -07:00
Michele Degges 5a90533a2e [RelAPI Onboarding] Add release API metadata file (#1031) 2022-03-24 13:52:26 -07:00
Carlos Alcaide Corvo 3d7b8537e1 chore: 🤖 Resolutions ansi-html (#1030)
Add ansi-html to resolutions
2022-03-22 07:23:11 -07:00
Carlos Alcaide Corvo 8d6669c8a1 chore: 🤖 Update git-cz (#1029)
Update git-cz
2022-03-18 14:12:35 -07:00
Dharini Jeeva 7c3f57c7fa chore: display sync interval seconds on host-set plugin forms (#1014)
* chore: 🤖 display sync_interval_seconds toggle on the forms

* chore: 🤖 remove comment

* chore: 🤖 remove extra spacing

* fix: 🐛 update title and add a description for sync_interval

* fix: 🐛 lint in translation

* chore: 🤖 fix typo, remove duplicate code

* chore: 🤖 simplify sync interval field, remove toggling

* fix: 🐛 use correct error code

* fix: 🐛 move sync interval translation to forms

* fix: 🐛 use appropiate translations label
2022-03-17 13:49:18 -07:00
Cameron Perera 2543d14c5a Chore: Add a PR template file (#1028)
* chore: 🤖 Add a PR template file

* chore: 🤖 update pr template

* chore: 🤖 final pr template update

* Update .github/pull_request_template.md

Move JIRA ticket link to the top
2022-03-17 14:00:44 -05:00
Carlos Alcaide Corvo fe7cb014a0 feat: 🎸 Add default custom Model for mirage (#1013)
* feat: 🎸 Add default custom Model for mirage
2022-03-17 11:05:41 -07:00
Carlos Alcaide Corvo adcfb00131 chore: 🤖 Bump binary version and update changelog (#1026)
Bump binary version and update changelog.
2022-03-16 14:41:41 -07:00
168 changed files with 2673 additions and 1352 deletions

No files matched your search

+17
View File
@@ -0,0 +1,17 @@
:tickets: [Jira ticket](https://hashicorp.atlassian.net/browse/JIRA_TICKET_NUMBER)
## Description
<!--
Replace PATH_TO_FEATURE with Vercel link
-->
:technologist: [Admin preview](PATH_TO_FEATURE)
:rose: [Rose preview](PATH_TO_FEATURE)
:desktop_computer: [Desktop preview](PATH_TO_FEATURE)
<!-- Add a brief description of changes here. Include any other necessary relevant links -->
### Screenshots (if appropriate):
+46
View File
@@ -0,0 +1,46 @@
name: Build Admin UI
on:
push:
branches:
- main
jobs:
dependencies:
name: Install dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@v3
with:
node-version: '16.x'
- run: yarn install
build:
name: Build Admin UI
needs: [dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@v3
with:
node-version: '16.x'
if: steps.node-modules-cache.outputs.cache-hit != 'true'
- run: yarn run build:ui:admin
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: admin-ui
path: ./ui/admin/dist/
+12 -12
View File
@@ -6,15 +6,15 @@ jobs:
name: Install dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
- uses: actions/checkout@v3
- uses: actions/cache@v3
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with:
node-version: '16.x'
- run: yarn install
@@ -24,15 +24,15 @@ jobs:
needs: [dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
- uses: actions/checkout@v3
- uses: actions/cache@v3
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with:
node-version: '16.x'
if: steps.node-modules-cache.outputs.cache-hit != 'true'
@@ -44,15 +44,15 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
- uses: actions/checkout@v3
- uses: actions/cache@v3
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with:
node-version: '16.x'
if: steps.node-modules-cache.outputs.cache-hit != 'true'
@@ -64,13 +64,13 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
- uses: actions/checkout@v3
- uses: actions/cache@v3
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with:
node-version: '16.x'
if: steps.node-modules-cache.outputs.cache-hit != 'true'
+3
View File
@@ -0,0 +1,3 @@
url_license = "https://github.com/hashicorp/boundary-ui/blob/main/LICENSE"
url_project_website = "https://learn.hashicorp.com/tutorials/boundary/getting-started-desktop-app"
url_source_repository = "https://github.com/hashicorp/boundary-ui"
+2 -2
View File
@@ -38,9 +38,9 @@ You will need the following things properly installed on your computer.
* [Git][git]
* [Node.js][node]
* v10–v15
* Supported versions:`v12`, `v14` and `v16`.
* **Apple Silicon Users**: if you experience problems building or running
Boundary UIs, try Node v15.
Boundary UIs, try Node v14.
* [Yarn][yarn] installed globally
* [Google Chrome][chrome]
* [Firefox][firefox]
+6 -3
View File
@@ -2,13 +2,16 @@
module.exports = {
root: true,
parser: 'babel-eslint',
parser: '@babel/eslint-parser',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
ecmaFeatures: {
legacyDecorators: true,
// This is specific babel-config. If grows consider creating a babel config file
requireConfigFile: false,
babelOptions: {
plugins: [['@babel/plugin-proposal-decorators', { legacy: true }]],
},
// end of babel-config
},
plugins: ['ember'],
extends: [
@@ -34,6 +34,12 @@ export default class GeneratedTargetModel extends BaseModel {
})
session_connection_limit;
@attr('string', {
description:
'Optional boolean expression to filter the workers that are allowed to satisfy this request.',
})
worker_filter;
@attr('date', {
description: 'The time this resource was created\nOutput only.',
readOnly: true,
+2 -2
View File
@@ -33,7 +33,7 @@ export default class AccountSerializer extends ApplicationSerializer {
* `attributes` entirely on update.
*/
serializeOIDC(snapshot) {
const { isNew } = snapshot?.record;
const { isNew } = snapshot?.record || {};
let serialized = super.serialize(...arguments);
delete serialized.attributes;
if (isNew) {
@@ -70,7 +70,7 @@ export default class AccountSerializer extends ApplicationSerializer {
}
// Change password custom method
if (snapshot?.adapterOptions?.method === 'change-password') {
const { currentPassword, newPassword } = snapshot?.adapterOptions;
const { currentPassword, newPassword } = snapshot?.adapterOptions || {};
serialized = this.serializeForChangePassword(
snapshot,
currentPassword,
+1
View File
@@ -25,6 +25,7 @@ export default factory.extend({
* -1 means "unlimited" and we want to generate these on occasion.
*/
session_connection_limit: () => random.arrayElement([-1, datatype.number()]),
worker_filter: (i) => (i % 2 === 0 ? random.words() : null),
type: (i) => types[i % types.length],
/**
* Generates attributes fields by type.
@@ -9,6 +9,7 @@ export default Factory.extend({
name: () => random.words(),
session_max_seconds: () => datatype.number(),
session_connection_limit: () => datatype.number(),
worker_filter: () => random.words(),
description: () => random.words(),
created_time: () => date.recent(),
updated_time: () => date.recent(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+20
View File
@@ -0,0 +1,20 @@
import { Model } from 'ember-cli-mirage';
export default Model.extend({
assignDefaults(defaultAttrs, attrs) {
Object.entries(defaultAttrs).map(([key, value]) => {
if (!attrs[key]) {
attrs[key] = value;
}
});
},
defaultAttrs: () => ({
version: 1,
authorized_actions: ['no-op', 'read', 'update', 'delete'],
created_time: new Date(),
}),
save() {
this.assignDefaults(this.defaultAttrs(), this.attrs);
return Model.prototype.save.apply(this, arguments);
},
});
@@ -1,4 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
import { belongsTo, hasMany } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+5 -4
View File
@@ -33,13 +33,13 @@
"ember-fetch": "^8.1.1"
},
"devDependencies": {
"js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1",
"@babel/core": "^7.16.5",
"@babel/eslint-parser": "^7.17.0",
"@babel/plugin-proposal-decorators": "^7.17.8",
"@ember/optional-features": "^2.0.0",
"@ember/test-helpers": "^2.6.0",
"@glimmer/component": "^1.0.4",
"@glimmer/tracking": "^1.0.4",
"babel-eslint": "^10.1.0",
"broccoli-asset-rev": "^3.0.0",
"doctoc": "^2.1.0",
"ember-auto-import": "^1.12.0",
@@ -58,12 +58,13 @@
"ember-resolver": "^8.0.3",
"ember-source": "~3.28.4",
"ember-template-lint": "^3.7.0",
"eslint": "^7.32.0",
"eslint": "^8.12.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ember": "^10.5.4",
"eslint-plugin-ember": "^10.5.9",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-qunit": "^6.2.0",
"js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1",
"loader.js": "^4.7.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.4.0",
@@ -35,6 +35,7 @@ module('Unit | Serializer | target', function (hooks) {
scope_id: 'org_1',
session_max_seconds: 28800,
session_connection_limit: 1,
worker_filter: null,
attributes: {
default_port: 1234,
},
@@ -86,6 +87,38 @@ module('Unit | Serializer | target', function (hooks) {
});
});
test('it serializes the worker_filter attribute if present', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('target');
const record = store.createRecord('target', {
name: 'User',
description: 'Description',
version: 1,
type: 'ssh',
worker_filter: 'worker',
default_port: 1234,
scope: {
scope_id: 'org_1',
},
});
const snapshot = record._createSnapshot();
const serializedRecord = serializer.serialize(snapshot);
assert.deepEqual(serializedRecord, {
name: 'User',
description: 'Description',
version: 1,
type: 'ssh',
scope_id: 'org_1',
session_max_seconds: 28800,
session_connection_limit: 1,
worker_filter: 'worker',
attributes: {
default_port: 1234,
},
});
});
test('it normalizes records with array fields', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
@@ -189,4 +222,36 @@ module('Unit | Serializer | target', function (hooks) {
},
});
});
test('it normalizes the worker_filter attribute if present', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('target');
const target = store.createRecord('target').constructor;
const payload = {
id: '1',
name: 'Target 1',
worker_filter: 'worker',
};
const normalized = serializer.normalizeSingleResponse(
store,
target,
payload
);
assert.deepEqual(normalized, {
included: [],
data: {
id: '1',
type: 'target',
attributes: {
authorized_actions: [],
name: 'Target 1',
host_sources: [],
application_credential_source_ids: [],
worker_filter: 'worker',
},
relationships: {},
},
});
});
});
+6 -3
View File
@@ -2,13 +2,16 @@
module.exports = {
root: true,
parser: 'babel-eslint',
parser: '@babel/eslint-parser',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
ecmaFeatures: {
legacyDecorators: true,
// This is specific babel-config. If grows consider creating a babel config file
requireConfigFile: false,
babelOptions: {
plugins: [['@babel/plugin-proposal-decorators', { legacy: true }]],
},
// end of babel-config
},
plugins: ['ember'],
extends: [
+4 -3
View File
@@ -27,11 +27,12 @@
"ember-simple-auth": "^4.0.0"
},
"devDependencies": {
"@babel/eslint-parser": "^7.17.0",
"@babel/plugin-proposal-decorators": "^7.17.8",
"@ember/optional-features": "^2.0.0",
"@ember/test-helpers": "^2.6.0",
"@glimmer/component": "^1.0.4",
"@glimmer/tracking": "^1.0.4",
"babel-eslint": "^10.1.0",
"broccoli-asset-rev": "^3.0.0",
"core": "*",
"doctoc": "^2.1.0",
@@ -51,9 +52,9 @@
"ember-resolver": "^8.0.3",
"ember-source": "~3.28.4",
"ember-template-lint": "^3.7.0",
"eslint": "^7.32.0",
"eslint": "^8.12.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ember": "^10.5.4",
"eslint-plugin-ember": "^10.5.9",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-qunit": "^6.2.0",
+6 -3
View File
@@ -2,13 +2,16 @@
module.exports = {
root: true,
parser: 'babel-eslint',
parser: '@babel/eslint-parser',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
ecmaFeatures: {
legacyDecorators: true,
// This is specific babel-config. If grows consider creating a babel config file
requireConfigFile: false,
babelOptions: {
plugins: [['@babel/plugin-proposal-decorators', { legacy: true }]],
},
// end of babel-config
},
plugins: ['ember'],
extends: [
@@ -0,0 +1,18 @@
<Rose::Button
...attributes
@style='inline-link-action'
@iconLeft={{if
this.isLoading
'flight-icons/svg/loading-16'
'flight-icons/svg/reload-16'
}}
class={{if
this.isLoading
'loading-button is-loading'
'loading-button'
}}
@disabled={{this.isLoading}}
{{on 'click' this.toggleRefresh}}
>
{{yield}}
</Rose::Button>
@@ -0,0 +1,20 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { later } from '@ember/runloop';
export default class LoadingButton extends Component {
// =actions
@tracked isLoading = false;
@action
async toggleRefresh() {
this.isLoading = true;
try {
await this.args.onClick();
} catch (e) {
console.error('Error while loading data', e);
}
later(() => (this.isLoading = false), 1000);
}
}
@@ -0,0 +1 @@
{{this.formatted}}
@@ -0,0 +1,103 @@
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
const MILLISECOND = 1;
const SECOND = MILLISECOND * 1000;
const MINUTE = SECOND * 60;
const HOUR = MINUTE * 60;
const DAY = HOUR * 24;
const MONTH = DAY * 31;
const YEAR = MONTH * 12;
// common time intervals in milliseconds
const unitMappings = [
{
unit: 'second',
value: SECOND,
},
{
unit: 'minute',
value: MINUTE,
},
{
unit: 'hour',
value: HOUR,
},
{
unit: 'day',
value: DAY,
},
{
unit: 'month',
value: MONTH,
},
{
unit: 'year',
value: YEAR,
},
];
export default class RelativeDatetimeLiveComponent extends Component {
// =services
@service clockTick;
@service intl;
// =properties
/**
* The difference in milliseconds between the date argument and the
* current time.
* @type {number}
*/
get delta() {
return this.args.date.valueOf() - this.clockTick.now;
}
/**
* The greatest meaningful unit is the unit which delta is equal to or
* greater than. For example, the unit of a delta equivalent of 59 seconds is
* 'second' while 60 seconds is 'minute', 36 hours is 'day', etc.
* @type {object}
*/
get greatestMeaningfulUnit() {
return unitMappings.reduce((currentValue, previousValue) => {
return Math.abs(this.delta) >= previousValue.value
? previousValue
: currentValue;
}, unitMappings[0]);
}
/**
* The delta value scaled to the greatest meaningful unit. For example, if
* the delta is 1000 ms, the scaled value is 1, which corresponds to
* a GMU of 'second'. A delta of 60000 ms is also 1, corresponding to a GMU
* of 'minute'.
* @type {number}
*/
get scaledDelta() {
if (this.delta < 0) {
return Math.ceil(this.delta / this.greatestMeaningfulUnit.value);
}
return Math.floor(this.delta / this.greatestMeaningfulUnit.value);
}
/**
* A string representation of the greatest meaningful unit.
* @type {string}
*/
get unit() {
return this.greatestMeaningfulUnit.unit;
}
/**
* A localizd relative datetime. E.g. "30 seconds ago".
* @type {string}
*/
get formatted() {
return this.intl.formatRelative(this.scaledDelta, {
unit: this.unit,
numeric: 'auto',
});
}
}
@@ -0,0 +1,9 @@
{{#if this.lastRefreshed}}
<Rose::Toolbar::Info>
<RelativeDatetimeLive @date={{this.lastRefreshed}} />
</Rose::Toolbar::Info>
{{/if}}
<LoadingButton @onClick={{this.onClick}}>
{{t 'actions.refresh'}}
</LoadingButton>
@@ -0,0 +1,20 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
export default class ToolbarRefresherComponent extends Component {
// =properties
@tracked lastRefreshed = null;
// =methods
/**
* Executes the click handler argument and trackes the time it completed.
*/
@action
async onClick() {
await this.args.onClick();
this.lastRefreshed = new Date();
}
}
+78
View File
@@ -0,0 +1,78 @@
import Service from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { getOwner } from '@ember/application';
import { next } from '@ember/runloop';
export default class ClockTickService extends Service {
// =attributes
/**
* The current datetime. This is updated once every `interval` while the
* service is running (1s by default).
* @type {number}
*/
@tracked now = Date.now();
/**
* The frequency to update `now`, in milliseconds.
* @type {number}
*/
frequency = 1000;
/**
* The timer interval ID
*/
#timer;
/**
* This service is enabled only in non-test environments.
* @type {boolean}
*/
get enabled() {
const config = getOwner(this).resolveRegistration('config:environment');
return config.environment !== 'test';
}
// =methods
/**
* Starts the timer, if enabled.
*/
constructor() {
super(...arguments);
if (this.enabled) this._start();
}
/**
* Stops the timer.
*/
willDestroy() {
super.willDestroy(...arguments);
this._stop();
}
/**
* Sets up the timer interval, calling `_tick()` every
* `frequency` milliseconds.
*/
_start() {
const self = this;
this.#timer = setInterval(function () {
self._tick();
}, this.frequency);
}
/**
* Clears the timer interval.
*/
_stop() {
clearInterval(this.#timer);
}
/**
* Updates the value of `now` within the next runloop.
*/
_tick() {
next(() => (this.now = Date.now()));
}
}
@@ -0,0 +1 @@
export { default } from 'core/components/loading-button';
@@ -0,0 +1 @@
export { default } from 'core/components/relative-datetime-live';
@@ -0,0 +1 @@
export { default } from 'core/components/toolbar-refresher';
+1
View File
@@ -0,0 +1 @@
export { default } from 'core/services/clock-tick';
+4 -3
View File
@@ -41,11 +41,12 @@
"rose": "*"
},
"devDependencies": {
"@babel/eslint-parser": "^7.17.0",
"@babel/plugin-proposal-decorators": "^7.17.8",
"@ember/optional-features": "^2.0.0",
"@ember/test-helpers": "^2.6.0",
"@glimmer/component": "^1.0.4",
"@glimmer/tracking": "^1.0.4",
"babel-eslint": "^10.1.0",
"broccoli-asset-rev": "^3.0.0",
"doctoc": "^2.1.0",
"ember-auto-import": "^1.12.0",
@@ -64,9 +65,9 @@
"ember-resolver": "^8.0.3",
"ember-source": "~3.28.4",
"ember-template-lint": "^3.7.0",
"eslint": "^7.32.0",
"eslint": "^8.12.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ember": "^10.5.4",
"eslint-plugin-ember": "^10.5.9",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-qunit": "^6.2.0",
@@ -0,0 +1,12 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default class ApplicationController extends Controller {
// =services
@service clockTick;
// =properties
now = new Date();
}
@@ -1,3 +1,3 @@
<h2 id="title">Welcome to Ember</h2>
{{t "errors.401.title"}}
<RelativeDatetimeLive @date={{this.now}} />
@@ -0,0 +1,20 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, find, click } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | loading-button', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
await render(hbs`<LoadingButton />`);
assert.ok(find('.loading-button'));
});
test('it executes a function on refresh button click', async function (assert) {
assert.expect(2);
this.onClick = () => assert.ok(true, 'refresh was clicked');
await render(hbs`<LoadingButton @onClick={{this.onClick}}/>`);
assert.ok(find('.loading-button'));
await click('button');
});
});
@@ -0,0 +1,38 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | relative-datetime-live', function (hooks) {
setupRenderingTest(hooks);
test('it renders a relative datetime', async function (assert) {
assert.expect(6);
const now = Date.now();
this.date = now - 10 * 1000;
await render(hbs`<RelativeDatetimeLive @date={{this.date}} />`);
assert.dom(this.element).hasText('10 seconds ago');
this.date = now - 10 * 60 * 1000;
await render(hbs`<RelativeDatetimeLive @date={{this.date}} />`);
assert.dom(this.element).hasText('10 minutes ago');
this.date = now - 10 * 60 * 60 * 1000;
await render(hbs`<RelativeDatetimeLive @date={{this.date}} />`);
assert.dom(this.element).hasText('10 hours ago');
this.date = now - 10 * 24 * 60 * 60 * 1000;
await render(hbs`<RelativeDatetimeLive @date={{this.date}} />`);
assert.dom(this.element).hasText('10 days ago');
this.date = now - 10 * 31 * 24 * 60 * 60 * 1000;
await render(hbs`<RelativeDatetimeLive @date={{this.date}} />`);
assert.dom(this.element).hasText('10 months ago');
this.date = now - 10 * 12 * 31 * 24 * 60 * 60 * 1000;
await render(hbs`<RelativeDatetimeLive @date={{this.date}} />`);
assert.dom(this.element).hasText('10 years ago');
});
});
@@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Service | clock-tick', function (hooks) {
setupTest(hooks);
// TODO: Replace this with your real tests.
test('it exists', function (assert) {
let service = this.owner.lookup('service:clock-tick');
assert.ok(service);
});
});
+2 -1
View File
@@ -36,4 +36,5 @@ toggle-secret: Toggle secret visibility
minimize: Minimize
fullscreen: Fullscreen
clear-all-filters: Clear all filters
learn-more: Learn more
learn-more: Learn more
refresh: Refresh
+6
View File
@@ -41,6 +41,9 @@ session_max_seconds:
session_connection_limit:
label: Maximum Connections
help: The maximum number of connections allowed per session. For unlimited, specify "-1".
worker_filter:
label: Worker Filter
help: Optional boolean expression to filter the workers that are allowed to satisfy this request.
host_set:
label: Host Set
grant_scope:
@@ -143,3 +146,6 @@ host:
label: Host
ip_addresses:
label: Latest IP Addresses
sync-interval:
label: Sync Interval
help: Number of seconds between the time Boundary syncs hosts in this set.
@@ -278,6 +278,9 @@ target:
types:
tcp: TCP
ssh: SSH
help:
tcp: Connections are made over TCP to support a broad range of protocols, including SSH, RDP, databases, and more. This is the most general-purpose type.
ssh: Protocol-aware connections are made over SSH. Use when requiring SSH connections to remote hosts.
host-source:
title: Host Source
title_plural: Host Sources
+6 -3
View File
@@ -2,13 +2,16 @@
module.exports = {
root: true,
parser: 'babel-eslint',
parser: '@babel/eslint-parser',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
ecmaFeatures: {
legacyDecorators: true,
// This is specific babel-config. If grows consider creating a babel config file
requireConfigFile: false,
babelOptions: {
plugins: [['@babel/plugin-proposal-decorators', { legacy: true }]],
},
// end of babel-config
},
plugins: ['ember'],
extends: [
+2 -1
View File
@@ -1,7 +1,8 @@
'use strict';
module.exports = {
extends: 'octane',
plugins: ['ember-template-lint-plugin-prettier'],
extends: ['octane', 'ember-template-lint-plugin-prettier:recommended'],
overrides: [
{
files: [
@@ -1,14 +1,12 @@
<span ...attributes
class="rose-badge {{if @style (concat "rose-badge-" @style)}}"
<span
...attributes
class='rose-badge {{if @style (concat 'rose-badge-' @style)}}'
>
{{#if @icon}}
<Rose::Icon
@name={{@icon}}
@size="medium"
/>
<Rose::Icon @name={{@icon}} @size='medium' />
{{/if}}
<span class="rose-badge-body">
<span class='rose-badge-body'>
{{yield}}
</span>
</span>
</span>
@@ -1,34 +1,29 @@
<button
...attributes
type={{if @submit "submit" "button"}}
disabled={{if @disabled "disabled"}}
class="{{@classNames}} {{if @style (concat "rose-button-" @style)}} {{if @iconLeft "has-icon-left"}} {{if @iconRight "has-icon-right"}} {{if @iconOnly "has-icon-only"}}"
>
type={{if @submit 'submit' 'button'}}
disabled={{if @disabled 'disabled'}}
class='{{@classNames}}
{{if @style (concat 'rose-button-' @style)}}
{{if @iconLeft 'has-icon-left'}}
{{if @iconRight 'has-icon-right'}}
{{if @iconOnly 'has-icon-only'}}'
>
<span class="rose-button-wrapper">
<span class='rose-button-wrapper'>
{{#if @iconLeft}}
<Rose::Icon
@name={{@iconLeft}}
@size="medium"
/>
<Rose::Icon @name={{@iconLeft}} @size='medium' />
{{/if}}
<span class="rose-button-body">
<span class='rose-button-body'>
{{yield}}
</span>
{{#if @iconOnly}}
<Rose::Icon
@name={{@iconOnly}}
@size="medium"
/>
<Rose::Icon @name={{@iconOnly}} @size='medium' />
{{/if}}
{{#if @iconRight}}
<Rose::Icon
@name={{@iconRight}}
@size="medium"
/>
<Rose::Icon @name={{@iconRight}} @size='medium' />
{{/if}}
</span>
</button>
</button>
@@ -0,0 +1,5 @@
import Component from '@glimmer/component';
export default class RoseButtonComponent extends Component {
// =attributes
}
@@ -1,34 +1,32 @@
<article ...attributes class="rose-card-link">
<article ...attributes class='rose-card-link'>
<LinkTo
title={{@title}}
@route={{if @route @route "index"}}
@route={{if @route @route 'index'}}
@model={{@model}}
>
<div class="rose-card-link-header">
<div class='rose-card-link-header'>
{{#if @title}}
<h2 class="rose-card-link-title">
<h2 class='rose-card-link-title'>
{{#if @icon}}
<Rose::Icon
@name={{@icon}}
@size="medium" />
<Rose::Icon @name={{@icon}} @size='medium' />
{{/if}}
<span class="rose-card-link-title-text">{{@title}}</span>
<span class='rose-card-link-title-text'>{{@title}}</span>
</h2>
{{/if}}
</div>
<div class="rose-card-link-body">
<div class='rose-card-link-body'>
{{#if @description}}
<p class="rose-card-link-description">{{@description}}</p>
<p class='rose-card-link-description'>{{@description}}</p>
{{/if}}
</div>
<div class="rose-card-link-footer">
<div class='rose-card-link-footer'>
{{#if @id}}
<p class="rose-card-link-footer-id">{{@id}}</p>
<p class='rose-card-link-footer-id'>{{@id}}</p>
{{/if}}
</div>
</LinkTo>
{{yield}}
</article>
</article>
@@ -1,8 +1,3 @@
<div
...attributes
class="rose-cards"
>
{{yield (hash
link=(component "rose/card/link")
)}}
</div>
<div ...attributes class='rose-cards'>
{{yield (hash link=(component 'rose/card/link'))}}
</div>
@@ -1,3 +1,3 @@
<div class="rose-dialog-body" tabindex="0">
<div class='rose-dialog-body' tabindex='0'>
{{yield}}
</div>
</div>
@@ -1,21 +1,21 @@
<div class="rose-dialog-cover-modal-overlay"></div>
<div class='rose-dialog-cover-modal-overlay'></div>
<section
...attributes
role="dialog"
class="rose-dialog-cover"
role='dialog'
class='rose-dialog-cover'
id={{this.id}}
aria-describedby={{concat "dialog-cover-header-" this.id}}
tabindex="0"
aria-describedby={{concat 'dialog-cover-header-' this.id}}
tabindex='0'
{{focus-trap}}
>
<header
class="rose-dialog-cover-header"
id={{concat "dialog-cover-header-" this.id}}
class='rose-dialog-cover-header'
id={{concat 'dialog-cover-header-' this.id}}
>
{{yield to="header"}}
{{yield to='header'}}
</header>
<div class="rose-dialog-cover-body">
{{yield to="body"}}
<div class='rose-dialog-cover-body'>
{{yield to='body'}}
</div>
</section>
</section>
@@ -1,41 +1,44 @@
{{#if @modal}}
<div class="rose-dialog-modal-overlay"></div>
<div class='rose-dialog-modal-overlay'></div>
<section
...attributes
role="dialog"
class="rose-dialog {{if @style (concat "rose-dialog-" @style)}} {{if @modal 'modal'}}"
role='dialog'
class='rose-dialog
{{if @style (concat 'rose-dialog-' @style)}}
{{if @modal 'modal'}}'
id={{this.id}}
aria-describedby={{concat "dialog-header-" this.id}}
aria-describedby={{concat 'dialog-header-' this.id}}
{{focus-trap}}
>
<header
class="rose-dialog-header"
id={{concat "dialog-header-" this.id}}
>
<header class='rose-dialog-header' id={{concat 'dialog-header-' this.id}}>
{{#if @icon}}
<Rose::Icon @name={{@icon}} @size="medium" />
<Rose::Icon @name={{@icon}} @size='medium' />
{{/if}}
<h2 class="rose-dialog-heading">{{@heading}}</h2>
<h2 class='rose-dialog-heading'>{{@heading}}</h2>
<button
type="button"
class="rose-dialog-dismiss"
type='button'
class='rose-dialog-dismiss'
title={{@dismissButtonText}}
{{on "click" (fn this.dismiss @dismiss)}}
{{on 'click' (fn this.dismiss @dismiss)}}
>
<Rose::Icon @name="flight-icons/svg/x-16" @size="small" />
<Rose::Icon @name='flight-icons/svg/x-16' @size='small' />
</button>
</header>
{{yield (hash
body=(component 'rose/dialog/body')
footer=(component 'rose/anonymous' tagName="footer" class="rose-dialog-footer")
)}}
{{yield
(hash
body=(component 'rose/dialog/body')
footer=(component
'rose/anonymous' tagName='footer' class='rose-dialog-footer'
)
)
}}
</section>
@@ -43,36 +46,42 @@
<section
...attributes
role="dialog"
class="rose-dialog {{if @style (concat "rose-dialog-" @style)}} {{if @modal 'modal'}}"
role='dialog'
class='rose-dialog
{{if @style (concat 'rose-dialog-' @style)}}
{{if @modal 'modal'}}'
>
{{#if @heading}}
<header class="rose-dialog-header">
<header class='rose-dialog-header'>
{{#if @icon}}
<Rose::Icon @name={{@icon}} @size="medium" />
<Rose::Icon @name={{@icon}} @size='medium' />
{{/if}}
<h2 class="rose-dialog-heading">{{@heading}}</h2>
<h2 class='rose-dialog-heading'>{{@heading}}</h2>
<button
type="button"
class="rose-dialog-dismiss"
type='button'
class='rose-dialog-dismiss'
title={{@dismissButtonText}}
{{on "click" (fn this.dismiss @dismiss)}}
{{on 'click' (fn this.dismiss @dismiss)}}
>
<Rose::Icon @name="flight-icons/svg/x-16" @size="small" />
<Rose::Icon @name='flight-icons/svg/x-16' @size='small' />
</button>
</header>
{{/if}}
{{yield (hash
body=(component 'rose/dialog/body')
footer=(component 'rose/anonymous' tagName="footer" class="rose-dialog-footer")
)}}
{{yield
(hash
body=(component 'rose/dialog/body')
footer=(component
'rose/anonymous' tagName='footer' class='rose-dialog-footer'
)
)
}}
</section>
{{/if}}
{{/if}}
@@ -1,19 +1,18 @@
<button
...attributes
type={{if @submit "submit" "button"}}
disabled={{if @disabled "disabled"}}
class="rose-dropdown-button {{if @style (concat "rose-dropdown-button-" @style)}} {{if @iconOnly "has-icon-only"}}"
>
<span class="rose-dropdown-button-wrapper">
<span class="rose-dropdown-button-body">
type={{if @submit 'submit' 'button'}}
disabled={{if @disabled 'disabled'}}
class='rose-dropdown-button
{{if @style (concat 'rose-dropdown-button-' @style)}}
{{if @iconOnly 'has-icon-only'}}'
>
<span class='rose-dropdown-button-wrapper'>
<span class='rose-dropdown-button-body'>
{{yield}}
</span>
{{#if @iconOnly}}
<Rose::Icon
@name={{@iconOnly}}
@size="medium"
/>
<Rose::Icon @name={{@iconOnly}} @size='medium' />
{{/if}}
</span>
</button>
</button>
@@ -1,22 +1,23 @@
<details
...attributes
class="rose-dropdown {{if @dropdownRight "rose-dropdown-right"}} {{if @style (concat "rose-dropdown-" @style)}}"
class='rose-dropdown
{{if @dropdownRight 'rose-dropdown-right'}}
{{if @style (concat 'rose-dropdown-' @style)}}'
{{on-click-outside this.close}}
>
<summary
class="rose-dropdown-trigger {{if @iconOnly "has-icon-only"}} {{if this.showCaret "show-caret"}}"
class='rose-dropdown-trigger
{{if @iconOnly 'has-icon-only'}}
{{if this.showCaret 'show-caret'}}'
title={{@text}}
>
{{#if @icon}}
<Rose::Icon
@name={{@icon}}
@size="medium"
/>
<Rose::Icon @name={{@icon}} @size='medium' />
{{/if}}
<span class="rose-dropdown-trigger-text">
<span class='rose-dropdown-trigger-text'>
{{@text}}
{{#if @count}}
<Rose::Badge>{{@count}}</Rose::Badge>
@@ -26,27 +27,35 @@
</summary>
{{#if @ignoreClickInside}}
<div class="rose-dropdown-content">
{{yield (hash
link=(component "rose/dropdown/link" style=this.style)
button=(component "rose/dropdown/button" style=this.style)
item=(component "rose/anonymous" class="rose-dropdown-item")
separator=(component "rose/anonymous" tagName="hr" class="rose-dropdown-separator")
section=(component "rose/dropdown/section" style=this.style)
key-value=(component "rose/dropdown/key-value")
)}}
<div class='rose-dropdown-content'>
{{yield
(hash
link=(component 'rose/dropdown/link' style=this.style)
button=(component 'rose/dropdown/button' style=this.style)
item=(component 'rose/anonymous' class='rose-dropdown-item')
separator=(component
'rose/anonymous' tagName='hr' class='rose-dropdown-separator'
)
section=(component 'rose/dropdown/section' style=this.style)
key-value=(component 'rose/dropdown/key-value')
)
}}
</div>
{{else}}
<div class="rose-dropdown-content" {{on-click-inside this.close}}>
{{yield (hash
link=(component "rose/dropdown/link" style=this.style)
button=(component "rose/dropdown/button" style=this.style)
item=(component "rose/anonymous" class="rose-dropdown-item")
separator=(component "rose/anonymous" tagName="hr" class="rose-dropdown-separator")
section=(component "rose/dropdown/section" style=this.style)
key-value=(component "rose/dropdown/key-value")
)}}
<div class='rose-dropdown-content' {{on-click-inside this.close}}>
{{yield
(hash
link=(component 'rose/dropdown/link' style=this.style)
button=(component 'rose/dropdown/button' style=this.style)
item=(component 'rose/anonymous' class='rose-dropdown-item')
separator=(component
'rose/anonymous' tagName='hr' class='rose-dropdown-separator'
)
section=(component 'rose/dropdown/section' style=this.style)
key-value=(component 'rose/dropdown/key-value')
)
}}
</div>
{{/if}}
</details>
</details>
@@ -4,6 +4,6 @@
</dt>
<dd class='rose-dropdown-value'>
{{yield to='value'}}
{{yield to='value'}}
</dd>
</dl>
</dl>
@@ -10,7 +10,8 @@
@route={{@route}}
@query={{@query}}
@model={{@model}}
class="rose-dropdown-link {{if @style (concat "rose-dropdown-link-" @style)}}"
class='rose-dropdown-link
{{if @style (concat 'rose-dropdown-link-' @style)}}'
>
{{yield}}
</LinkTo>
@@ -19,7 +20,8 @@
...attributes
@route={{@route}}
@model={{@model}}
class="rose-dropdown-link {{if @style (concat "rose-dropdown-link-" @style)}}"
class='rose-dropdown-link
{{if @style (concat 'rose-dropdown-link-' @style)}}'
>
{{yield}}
</LinkTo>
@@ -30,7 +32,8 @@
...attributes
@route={{@route}}
@query={{@query}}
class="rose-dropdown-link {{if @style (concat "rose-dropdown-link-" @style)}}"
class='rose-dropdown-link
{{if @style (concat 'rose-dropdown-link-' @style)}}'
>
{{yield}}
</LinkTo>
@@ -38,9 +41,10 @@
<LinkTo
...attributes
@route={{@route}}
class="rose-dropdown-link {{if @style (concat "rose-dropdown-link-" @style)}}"
class='rose-dropdown-link
{{if @style (concat 'rose-dropdown-link-' @style)}}'
>
{{yield}}
</LinkTo>
{{/if}}
{{/if}}
{{/if}}
@@ -1,12 +1,15 @@
<section class="rose-dropdown-section" aria-labelledby={{concat "dropdown-section-title-" this.id}}>
<section
class='rose-dropdown-section'
aria-labelledby={{concat 'dropdown-section-title-' this.id}}
>
{{#if @title}}
<h2
id={{concat "dropdown-section-title-" this.id}}
class="rose-dropdown-section-title"
id={{concat 'dropdown-section-title-' this.id}}
class='rose-dropdown-section-title'
>
{{@title}}
</h2>
{{/if}}
{{yield}}
</section>
</section>
@@ -1,12 +1,12 @@
<LinkTo
...attributes
class="rose-footer-brand"
class='rose-footer-brand'
title={{@text}}
@route={{if @route @route "index"}}
@route={{if @route @route 'index'}}
>
{{#if @logo}}
{{inline-svg @logo}}
{{/if}}
</LinkTo>
</LinkTo>
@@ -1,11 +1,11 @@
<span class="rose-footer-copyright">
<span class="rose-footer-copyright-symbol">
<span class='rose-footer-copyright'>
<span class='rose-footer-copyright-symbol'>
&copy;
</span>
<span class="rose-footer-copyright-year">
<span class='rose-footer-copyright-year'>
{{this.currentYear}}
</span>
<span class="rose-footer-copyright-text">
<span class='rose-footer-copyright-text'>
{{@text}}
</span>
</span>
</span>
@@ -1,10 +1,9 @@
<footer
...attributes
class="rose-footer"
>
{{yield (hash
nav=(component 'rose/footer/nav')
brand=(component 'rose/footer/brand')
text=(component "rose/anonymous" class="rose-footer-text")
)}}
</footer>
<footer ...attributes class='rose-footer'>
{{yield
(hash
nav=(component 'rose/footer/nav')
brand=(component 'rose/footer/brand')
text=(component 'rose/anonymous' class='rose-footer-text')
)
}}
</footer>
@@ -1,5 +1,3 @@
<nav class="rose-footer-nav" aria-label="footer-nav">
{{yield (hash
link=(component 'rose/footer/nav/link')
)}}
<nav class='rose-footer-nav' aria-label='footer-nav'>
{{yield (hash link=(component 'rose/footer/nav/link'))}}
</nav>
@@ -1,8 +1,9 @@
{{#if @href}}
<a target="_blank"
<a
target='_blank'
href={{@href}}
class="rose-footer-nav-link"
rel="noopener noreferrer"
class='rose-footer-nav-link'
rel='noopener noreferrer'
>
{{yield}}
</a>
@@ -13,8 +14,8 @@
...attributes
@route={{@route}}
@model={{@model}}
class="rose-footer-nav-link"
class='rose-footer-nav-link'
>
{{yield}}
</LinkTo>
{{/if}}
{{/if}}
@@ -1,10 +1,10 @@
<span class="rose-footer-product">
<span class="rose-footer-product-text">
<span class='rose-footer-product'>
<span class='rose-footer-product-text'>
{{@text}}
</span>
{{#if @version}}
<span class="rose-footer-product-version">
<span class='rose-footer-product-version'>
v{{@version}}
</span>
{{/if}}
@@ -1,8 +1,5 @@
<div class="rose-form-actions" ...attributes>
<Rose::Button
@style="secondary"
{{on "click" @enableEdit}}
>
<div class='rose-form-actions' ...attributes>
<Rose::Button @style='secondary' {{on 'click' @enableEdit}}>
{{@enableEditText}}
</Rose::Button>
</div>
</div>
@@ -1,19 +1,15 @@
<div class="rose-form-actions" ...attributes>
<Rose::Button
@disabled={{@submitDisabled}}
@submit={{true}}
@style="primary"
>
<div class='rose-form-actions' ...attributes>
<Rose::Button @disabled={{@submitDisabled}} @submit={{true}} @style='primary'>
{{@submitText}}
</Rose::Button>
{{#if this.showCancel}}
<Rose::Button
@disabled={{@cancelDisabled}}
@style="secondary"
{{on "click" @cancel}}
@style='secondary'
{{on 'click' @cancel}}
>
{{@cancelText}}
</Rose::Button>
{{/if}}
</div>
</div>
@@ -1,12 +1,15 @@
{{#each @items as |item|}}
{{yield (hash
item=item
checkbox=(component 'rose/form/checkbox'
name=@name
disabled=@disabled
inline=@inline
checked=(includes item @selectedItems)
onChange=(fn this.toggleItem item)
{{yield
(hash
item=item
checkbox=(component
'rose/form/checkbox'
name=@name
disabled=@disabled
inline=@inline
checked=(includes item @selectedItems)
onChange=(fn this.toggleItem item)
)
)
)}}
{{/each}}
}}
{{/each}}
@@ -1,31 +1,35 @@
<div class="rose-form-checkbox{{if @error " error"}} {{if @inline " inline"}}">
<div class='rose-form-checkbox{{if @error ' error'}} {{if @inline ' inline'}}'>
<Input
...attributes
class="rose-form-checkbox-field"
class='rose-form-checkbox-field'
id={{this.id}}
name={{@name}}
disabled={{@disabled}}
onChange={{@onChange}}
@type="checkbox"
@type='checkbox'
@checked={{if @checked true false}}
aria-describedby="{{if @helperText (concat 'helper-text-' this.id)}} {{if @error (concat 'errors-' this.id)}}" />
aria-describedby='{{if @helperText (concat 'helper-text-' this.id)}} {{if
@error
(concat 'errors-' this.id)
}}'
/>
<label class="rose-form-checkbox-label" for={{this.id}}>
<span class="rose-form-checkbox-label-text">{{@label}}</span>
<label class='rose-form-checkbox-label' for={{this.id}}>
<span class='rose-form-checkbox-label-text'>{{@label}}</span>
{{#if @description}}
<p class="rose-form-checkbox-label-description">{{@description}}</p>
<p class='rose-form-checkbox-label-description'>{{@description}}</p>
{{/if}}
</label>
{{#if @helperText}}
<Rose::Form::HelperText @id="helper-text-{{this.id}}" @error={{@error}}>
<Rose::Form::HelperText @id='helper-text-{{this.id}}' @error={{@error}}>
{{@helperText}}
</Rose::Form::HelperText>
{{/if}}
{{yield (hash
errors=(component 'rose/form/errors' id=(concat 'errors-' this.id))
)}}
{{yield
(hash errors=(component 'rose/form/errors' id=(concat 'errors-' this.id)))
}}
</div>
</div>
@@ -1,5 +1,3 @@
<div class="rose-form-errors" id={{@id}} ...attributes>
{{yield (hash
message=(component 'rose/form/errors/message')
)}}
</div>
<div class='rose-form-errors' id={{@id}} ...attributes>
{{yield (hash message=(component 'rose/form/errors/message'))}}
</div>
@@ -1,4 +1,4 @@
<p class="rose-form-error-message" ...attributes>
<Rose::Icon @name="flight-icons/svg/x-square-16" @size="medium" />
<p class='rose-form-error-message' ...attributes>
<Rose::Icon @name='flight-icons/svg/x-square-16' @size='medium' />
{{yield}}
</p>
</p>
@@ -1,21 +1,25 @@
<fieldset ...attributes class='rose-form-fieldset' aria-describedby={{if (has-block "description") (concat 'description-' this.id)}}>
<legend
id={{concat 'title-' this.id}}
class='rose-form-fieldset-title'
<fieldset
...attributes
class='rose-form-fieldset'
aria-describedby={{if
(has-block 'description')
(concat 'description-' this.id)
}}
>
<legend id={{concat 'title-' this.id}} class='rose-form-fieldset-title'>
{{yield to='title'}}
</legend>
{{#if (has-block 'description')}}
<div
id={{concat 'description-' this.id}}
class='rose-form-fieldset-description'
>
{{yield to='title'}}
</legend>
{{#if (has-block "description")}}
<div
id={{concat 'description-' this.id}}
class='rose-form-fieldset-description'
>
{{yield to='description'}}
</div>
{{/if}}
<div class='rose-form-fieldset-body'>
{{yield to='body'}}
{{yield to='description'}}
</div>
{{/if}}
<div class='rose-form-fieldset-body'>
{{yield to='body'}}
</div>
</fieldset>
@@ -1,12 +1,16 @@
<span
class="rose-form-helper-text{{if @error " error"}}"
class='rose-form-helper-text{{if @error ' error'}}'
id={{@id}}
...attributes
>
{{yield}}
{{#if @link}}
{{#if @link}}
{{#if @linkText}}
<a href={{@link}} target='_blank' rel='noreferrer noopener'>{{@linkText}}</a>
<a
href={{@link}}
target='_blank'
rel='noreferrer noopener'
>{{@linkText}}</a>
{{/if}}
{{/if}}
</span>
</span>
@@ -1,37 +1,42 @@
<form
...attributes
novalidate
method="post"
class="rose-form"
autocomplete="off"
{{on "submit" this.handleSubmit}}
method='post'
class='rose-form'
autocomplete='off'
{{on 'submit' this.handleSubmit}}
>
{{!--
{{!
Only show the edit toggle button if the toggle is enabled in the first place
AND the form is not already in editable mode.
The cancel button's disabled state depends on the mode. In edit mode,
the cancel button is only disabled if the disabled argument is true,
otherwise it is disabled based on the computed property this.disabled.
--}}
{{yield (hash
radioGroup=(component 'rose/form/radio/group' disabled=this.disabled)
checkbox=(component 'rose/form/checkbox' disabled=this.disabled)
checkboxGroup=(component 'rose/form/checkbox/group' disabled=this.disabled)
input=(component 'rose/form/input' disabled=this.disabled)
select=(component 'rose/form/select' disabled=this.disabled)
textarea=(component 'rose/form/textarea' disabled=this.disabled)
fieldset=(component 'rose/form/fieldset')
actions=(component
(if this.showEditToggleButton
'rose/form/actions/edit-toggle'
'rose/form/actions'
}}
{{yield
(hash
radioGroup=(component 'rose/form/radio/group' disabled=this.disabled)
checkbox=(component 'rose/form/checkbox' disabled=this.disabled)
checkboxGroup=(component
'rose/form/checkbox/group' disabled=this.disabled
)
submitDisabled=this.disabled
cancelDisabled=(if @showEditToggle @disabled this.disabled)
cancel=this.handleCancel
enableEdit=this.enableEdit
input=(component 'rose/form/input' disabled=this.disabled)
select=(component 'rose/form/select' disabled=this.disabled)
textarea=(component 'rose/form/textarea' disabled=this.disabled)
fieldset=(component 'rose/form/fieldset')
actions=(component
(if
this.showEditToggleButton
'rose/form/actions/edit-toggle'
'rose/form/actions'
)
submitDisabled=this.disabled
cancelDisabled=(if @showEditToggle @disabled this.disabled)
cancel=this.handleCancel
enableEdit=this.enableEdit
)
isEditable=this.isEditable
)
isEditable=this.isEditable
)}}
</form>
}}
</form>
@@ -1,44 +1,47 @@
{{#if @contextual}}
{{yield (hash
label=(component 'rose/form/label'
for=this.id
error=@error
{{yield
(hash
label=(component 'rose/form/label' for=this.id error=@error)
helperText=(component
'rose/form/helper-text' id=(concat 'helper-text-' this.id) error=@error
)
field=(component
'rose/form/input/input'
id=this.id
name=@name
value=@value
type=@type
disabled=@disabled
error=@error
aria-describedby=(concat
(if @helperText (concat 'helper-text-' this.id))
(if @error (concat ' errors-' this.id))
)
)
errors=(component 'rose/form/errors' id=(concat 'errors-' this.id))
)
helperText=(component 'rose/form/helper-text'
id=(concat 'helper-text-' this.id)
error=@error
)
field=(component 'rose/form/input/input'
id=this.id
name=@name
value=@value
type=@type
disabled=@disabled
error=@error
aria-describedby=(concat (if @helperText (concat 'helper-text-' this.id)) (if @error (concat ' errors-' this.id)))
)
errors=(component 'rose/form/errors'
id=(concat 'errors-' this.id)
)
)}}
}}
{{else}}
<div class="rose-form-input">
<div class='rose-form-input'>
<Rose::Form::Label @for={{this.id}} @error={{@error}}>
{{@label}}
</Rose::Form::Label>
{{#if @helperText}}
<Rose::Form::HelperText @id="helper-text-{{this.id}}" @error={{@error}} @link={{@link}} @linkText={{@linkText}}>
<Rose::Form::HelperText
@id='helper-text-{{this.id}}'
@error={{@error}}
@link={{@link}}
@linkText={{@linkText}}
>
{{@helperText}}
</Rose::Form::HelperText>
{{/if}}
<div class="rose-input-wrapper">
<div class='rose-input-wrapper'>
{{#if @icon}}
<Rose::Icon
@name={{@icon}}
@size="medium" />
<Rose::Icon @name={{@icon}} @size='medium' />
{{/if}}
<Rose::Form::Input::Input
...attributes
@@ -48,13 +51,15 @@
@type={{@type}}
@disabled={{@disabled}}
@error={{@error}}
@aria-describedby="{{if @helperText (concat 'helper-text-' this.id)}} {{if @error (concat 'errors-' this.id)}}" />
@aria-describedby='{{if
@helperText
(concat 'helper-text-' this.id)
}} {{if @error (concat 'errors-' this.id)}}'
/>
</div>
{{yield (hash
errors=(component 'rose/form/errors'
id=(concat 'errors-' this.id)
)
)}}
{{yield
(hash errors=(component 'rose/form/errors' id=(concat 'errors-' this.id)))
}}
</div>
{{/if}}
{{/if}}
@@ -1,9 +1,10 @@
<Input
...attributes
class="rose-form-input-field{{if @error " error"}}"
class='rose-form-input-field{{if @error ' error'}}'
id={{@id}}
disabled={{@disabled}}
name={{@name}}
@type={{@type}}
@value={{@value}}
aria-describedby={{@aria-describedby}} />
aria-describedby={{@aria-describedby}}
/>
@@ -1,7 +1,3 @@
<label
class="rose-form-label{{if @error " error"}}"
for={{@for}}
...attributes
>
<label class='rose-form-label{{if @error ' error'}}' for={{@for}} ...attributes>
{{yield}}
</label>
</label>
@@ -1,4 +1,20 @@
{{yield (hash
radio=(component 'rose/form/radio/radio' name=@name selectedValue=@selectedValue disabled=@disabled changed=@changed inline=@inline)
card=(component 'rose/form/radio/card' name=@name selectedValue=@selectedValue disabled=@disabled changed=@changed layout=@layout)
)}}
{{yield
(hash
radio=(component
'rose/form/radio/radio'
name=@name
selectedValue=@selectedValue
disabled=@disabled
changed=@changed
inline=@inline
)
card=(component
'rose/form/radio/card'
name=@name
selectedValue=@selectedValue
disabled=@disabled
changed=@changed
layout=@layout
)
)
}}
@@ -1,30 +1,33 @@
<div class="{{this.className}} {{if @error " error"}} {{if @inline "inline"}}">
<div class='{{this.className}} {{if @error ' error'}} {{if @inline 'inline'}}'>
<RadioButton
...attributes
@radioClass="rose-form-radio-field"
@radioClass='rose-form-radio-field'
@radioId={{this.id}}
type="radio"
type='radio'
disabled={{@disabled}}
@name={{@name}}
@value={{@value}}
@groupValue={{@selectedValue}}
@disabled={{@disabled}}
@changed={{@changed}} />
@changed={{@changed}}
/>
<label class="rose-form-radio-label" for={{this.id}}>
<label class='rose-form-radio-label' for={{this.id}}>
{{#if @icon}}
<Rose::Icon
@name={{@icon}}
@size="medium"
/>
<Rose::Icon @name={{@icon}} @size='medium' />
{{/if}}
{{@label}}
<span class="radio-card-overlay"></span>
{{#if @helperText}}
<Rose::Form::HelperText @id="helper-text-{{this.id}}" @error={{@error}} @link={{@link}} @linkText={{@linkText}}>
<span class='radio-card-overlay'></span>
{{#if @helperText}}
<Rose::Form::HelperText
@id='helper-text-{{this.id}}'
@error={{@error}}
@link={{@link}}
@linkText={{@linkText}}
>
{{@helperText}}
</Rose::Form::HelperText>
{{/if}}
@@ -32,4 +35,4 @@
{{yield}}
</div>
</div>
@@ -1,51 +1,57 @@
{{#if @contextual}}
{{yield (hash
label=(component 'rose/form/label'
for=this.id
error=@error
)
helperText=(component 'rose/form/helper-text'
id=(concat 'helper-text-' this.id)
error=@error
)
field=(component 'rose/form/select/select'
id=this.id
name=@name
value=@value
onChange=@onChange
disabled=@disabled
error=@error
aria-describedby=(concat (if @helperText (concat 'helper-text-' this.id)) (if @error (concat ' errors-' this.id)))
)
errors=(component 'rose/form/errors'
id=(concat 'errors-' this.id)
)
)}}
{{else}}
<div class="rose-form-select">
<Rose::Form::Label @for={{this.id}} @error={{@error}}>
{{@label}}
</Rose::Form::Label>
{{#if @helperText}}
<Rose::Form::HelperText @id="helper-text-{{this.id}}" @error={{@error}}>
{{@helperText}}
</Rose::Form::HelperText>
{{/if}}
{{yield (hash
field=(component 'rose/form/select/select'
{{yield
(hash
label=(component 'rose/form/label' for=this.id error=@error)
helperText=(component
'rose/form/helper-text' id=(concat 'helper-text-' this.id) error=@error
)
field=(component
'rose/form/select/select'
id=this.id
name=@name
value=@value
onChange=@onChange
disabled=@disabled
error=@error
aria-describedby=(concat (if @helperText (concat 'helper-text-' this.id)) (if @error (concat ' errors-' this.id)))
aria-describedby=(concat
(if @helperText (concat 'helper-text-' this.id))
(if @error (concat ' errors-' this.id))
)
)
errors=(component 'rose/form/errors' id=(concat 'errors-' this.id))
)}}
)
}}
{{else}}
<div class='rose-form-select'>
<Rose::Form::Label @for={{this.id}} @error={{@error}}>
{{@label}}
</Rose::Form::Label>
{{#if @helperText}}
<Rose::Form::HelperText @id='helper-text-{{this.id}}' @error={{@error}}>
{{@helperText}}
</Rose::Form::HelperText>
{{/if}}
{{yield
(hash
field=(component
'rose/form/select/select'
id=this.id
name=@name
value=@value
onChange=@onChange
disabled=@disabled
error=@error
aria-describedby=(concat
(if @helperText (concat 'helper-text-' this.id))
(if @error (concat ' errors-' this.id))
)
)
errors=(component 'rose/form/errors' id=(concat 'errors-' this.id))
)
}}
</div>
{{/if}}
{{/if}}
@@ -1,6 +1,6 @@
<XSelect
...attributes
class="rose-form-select-field{{if @error " error"}}"
class='rose-form-select-field{{if @error ' error'}}'
id={{@id}}
name={{@name}}
disabled={{@disabled}}
@@ -10,4 +10,4 @@
as |xs|
>
{{yield xs}}
</XSelect>
</XSelect>
@@ -1,34 +1,39 @@
{{#if @contextual}}
{{yield (hash
label=(component 'rose/form/label'
for=this.id
error=@error
{{yield
(hash
label=(component 'rose/form/label' for=this.id error=@error)
helperText=(component
'rose/form/helper-text' id=(concat 'helper-text-' this.id) error=@error
)
field=(component
'rose/form/textarea/textarea'
id=this.id
name=@name
value=@value
disabled=@disabled
error=@error
aria-describedby=(concat
(if @helperText (concat 'helper-text-' this.id))
(if @error (concat ' errors-' this.id))
)
)
errors=(component 'rose/form/errors' id=(concat 'errors-' this.id))
)
helperText=(component 'rose/form/helper-text'
id=(concat 'helper-text-' this.id)
error=@error
)
field=(component 'rose/form/textarea/textarea'
id=this.id
name=@name
value=@value
disabled=@disabled
error=@error
aria-describedby=(concat (if @helperText (concat 'helper-text-' this.id)) (if @error (concat ' errors-' this.id)))
)
errors=(component 'rose/form/errors'
id=(concat 'errors-' this.id)
)
)}}
}}
{{else}}
<div class="rose-form-input">
<div class='rose-form-input'>
<Rose::Form::Label @for={{this.id}} @error={{@error}}>
{{@label}}
</Rose::Form::Label>
{{#if @helperText}}
<Rose::Form::HelperText @id="helper-text-{{this.id}}" @error={{@error}} @link={{@link}} @linkText={{@linkText}}>
<Rose::Form::HelperText
@id='helper-text-{{this.id}}'
@error={{@error}}
@link={{@link}}
@linkText={{@linkText}}
>
{{@helperText}}
</Rose::Form::HelperText>
{{/if}}
@@ -40,11 +45,15 @@
@value={{@value}}
@disabled={{@disabled}}
@error={{@error}}
@aria-describedby="{{if @helperText (concat 'helper-text-' this.id)}} {{if @error (concat 'errors-' this.id)}}" />
@aria-describedby='{{if @helperText (concat 'helper-text-' this.id)}} {{if
@error
(concat 'errors-' this.id)
}}'
/>
{{yield (hash
errors=(component 'rose/form/errors' id=(concat 'errors-' this.id))
)}}
{{yield
(hash errors=(component 'rose/form/errors' id=(concat 'errors-' this.id)))
}}
</div>
{{/if}}
{{/if}}
@@ -1,8 +1,9 @@
<Textarea
...attributes
class="rose-form-input-field{{if @error " error"}}"
class='rose-form-input-field{{if @error ' error'}}'
id={{@id}}
name={{@name}}
disabled={{@disabled}}
@value={{@value}}
aria-describedby={{@aria-describedby}} />
aria-describedby={{@aria-describedby}}
/>
@@ -1,11 +1,11 @@
<section ...attributes class="rose-frame">
<section ...attributes class='rose-frame'>
<header class="rose-frame-header">
{{yield to="header"}}
<header class='rose-frame-header'>
{{yield to='header'}}
</header>
<div class="rose-frame-body">
{{yield to="body"}}
<div class='rose-frame-body'>
{{yield to='body'}}
</div>
</section>
</section>
@@ -1,8 +1,8 @@
<LinkTo
...attributes
class="rose-header-brand"
class='rose-header-brand'
title={{@text}}
@route={{if @route @route "index"}}
@route={{if @route @route 'index'}}
>
{{#if @logo}}
@@ -10,7 +10,7 @@
{{/if}}
{{#if @text}}
<h1 class="rose-header-brand-text">{{@text}}</h1>
<h1 class='rose-header-brand-text'>{{@text}}</h1>
{{/if}}
</LinkTo>
</LinkTo>
@@ -1,10 +1,9 @@
<div
...attributes
class="rose-header"
>
{{yield (hash
brand=(component 'rose/header/brand')
utilities=(component 'rose/header/utilities')
nav=(component 'rose/header/nav')
)}}
</div>
<div ...attributes class='rose-header'>
{{yield
(hash
brand=(component 'rose/header/brand')
utilities=(component 'rose/header/utilities')
nav=(component 'rose/header/nav')
)
}}
</div>
@@ -1,6 +1,8 @@
<nav class="rose-header-nav" aria-label="header-nav">
{{yield (hash
link=(component 'link-to' class="rose-header-nav-link")
dropdown=(component 'rose/dropdown')
)}}
</nav>
<nav class='rose-header-nav' aria-label='header-nav'>
{{yield
(hash
link=(component 'link-to' class='rose-header-nav-link')
dropdown=(component 'rose/dropdown')
)
}}
</nav>
@@ -1,5 +1,3 @@
<div class="rose-header-utilities">
{{yield (hash
dropdown=(component 'rose/dropdown' dropdownRight=true)
)}}
</div>
<div class='rose-header-utilities'>
{{yield (hash dropdown=(component 'rose/dropdown' dropdownRight=true))}}
</div>
@@ -1,3 +1,3 @@
<span ...attributes class="rose-icon {{@size}}">
<span ...attributes class='rose-icon {{@size}}'>
{{inline-svg @name}}
</span>
</span>
@@ -1,3 +1,3 @@
<section ...attributes class="rose-layout-centered">
<section ...attributes class='rose-layout-centered'>
{{yield}}
</section>
</section>
@@ -1,7 +1,11 @@
<section ...attributes class="rose-layout-global">
{{yield (hash
header=(component "rose/anonymous" tagName="header" class="rose-layout-global-header")
body=(component "rose/anonymous" class="rose-layout-global-body")
footer=(component "rose/anonymous" class="rose-layout-global-footer")
)}}
</section>
<section ...attributes class='rose-layout-global'>
{{yield
(hash
header=(component
'rose/anonymous' tagName='header' class='rose-layout-global-header'
)
body=(component 'rose/anonymous' class='rose-layout-global-body')
footer=(component 'rose/anonymous' class='rose-layout-global-footer')
)
}}
</section>
@@ -1,9 +1,15 @@
<div ...attributes class="rose-layout-page">
{{yield (hash
breadcrumbs=(component "rose/anonymous" class="rose-layout-page-breadcrumbs")
header=(component "rose/anonymous" class="rose-layout-page-header")
actions=(component "rose/anonymous" class="rose-layout-page-actions")
navigation=(component "rose/anonymous" class="rose-layout-page-navigation")
body=(component "rose/anonymous" class="rose-layout-page-body")
)}}
</div>
<div ...attributes class='rose-layout-page'>
{{yield
(hash
breadcrumbs=(component
'rose/anonymous' class='rose-layout-page-breadcrumbs'
)
header=(component 'rose/anonymous' class='rose-layout-page-header')
actions=(component 'rose/anonymous' class='rose-layout-page-actions')
navigation=(component
'rose/anonymous' class='rose-layout-page-navigation'
)
body=(component 'rose/anonymous' class='rose-layout-page-body')
)
}}
</div>
@@ -1,6 +1,10 @@
<div ...attributes class="rose-layout-sidebar">
{{yield (hash
body=(component "rose/anonymous" class="rose-layout-sidebar-body")
sidebar=(component "rose/anonymous" tagName="aside" class="rose-layout-sidebar-sidebar")
)}}
</div>
<div ...attributes class='rose-layout-sidebar'>
{{yield
(hash
body=(component 'rose/anonymous' class='rose-layout-sidebar-body')
sidebar=(component
'rose/anonymous' tagName='aside' class='rose-layout-sidebar-sidebar'
)
)
}}
</div>
@@ -1,31 +1,27 @@
<LinkTo
class="rose-link-button {{if @style (concat "rose-button-" @style)}} {{if @iconOnly 'has-icon-only'}} {{if @iconLeft 'has-icon-left'}} {{if @iconRight 'has-icon-right'}}"
class='rose-link-button
{{if @style (concat 'rose-button-' @style)}}
{{if @iconOnly 'has-icon-only'}}
{{if @iconLeft 'has-icon-left'}}
{{if @iconRight 'has-icon-right'}}'
@route={{@route}}
...attributes>
<span class="rose-button-wrapper">
...attributes
>
<span class='rose-button-wrapper'>
{{#if @iconLeft}}
<Rose::Icon
@name={{@iconLeft}}
@size="medium"
/>
<Rose::Icon @name={{@iconLeft}} @size='medium' />
{{/if}}
<span class="rose-button-body">
<span class='rose-button-body'>
{{yield}}
</span>
{{#if @iconOnly}}
<Rose::Icon
@name={{@iconOnly}}
@size="medium"
/>
<Rose::Icon @name={{@iconOnly}} @size='medium' />
{{/if}}
{{#if @iconRight}}
<Rose::Icon
@name={{@iconRight}}
@size="medium"
/>
<Rose::Icon @name={{@iconRight}} @size='medium' />
{{/if}}
</span>
</LinkTo>
</LinkTo>
@@ -1,5 +1,3 @@
<ul class="rose-list-key-value">
{{yield (hash
item=(component 'rose/list/key-value/item')
)}}
</ul>
<ul class='rose-list-key-value'>
{{yield (hash item=(component 'rose/list/key-value/item'))}}
</ul>
Loaded 100 of 168 files, more files were not shown because too many files have changed in this diff. Show more