Compare commits

..
2 Commits
168 changed files with 1347 additions and 2668 deletions

No files matched your search

-17
View File
@@ -1,17 +0,0 @@
: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
@@ -1,46 +0,0 @@
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@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@v3
- uses: actions/setup-node@v2
with:
node-version: '16.x'
- run: yarn install
@@ -24,15 +24,15 @@ jobs:
needs: [dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@v3
- uses: actions/setup-node@v2
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@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@v3
- uses: actions/setup-node@v2
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@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
- uses: actions/setup-node@v3
- uses: actions/setup-node@v2
with:
node-version: '16.x'
if: steps.node-modules-cache.outputs.cache-hit != 'true'
-3
View File
@@ -1,3 +0,0 @@
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]
* Supported versions:`v12`, `v14` and `v16`.
* v10–v15
* **Apple Silicon Users**: if you experience problems building or running
Boundary UIs, try Node v14.
Boundary UIs, try Node v15.
* [Yarn][yarn] installed globally
* [Google Chrome][chrome]
* [Firefox][firefox]
+3 -6
View File
@@ -2,16 +2,13 @@
module.exports = {
root: true,
parser: '@babel/eslint-parser',
parser: 'babel-eslint',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
// This is specific babel-config. If grows consider creating a babel config file
requireConfigFile: false,
babelOptions: {
plugins: [['@babel/plugin-proposal-decorators', { legacy: true }]],
ecmaFeatures: {
legacyDecorators: true,
},
// end of babel-config
},
plugins: ['ember'],
extends: [
@@ -34,12 +34,6 @@ 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,7 +25,6 @@ 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,7 +9,6 @@ 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(),
+1 -2
View File
@@ -1,5 +1,4 @@
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
+1 -2
View File
@@ -1,5 +1,4 @@
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
-20
View File
@@ -1,20 +0,0 @@
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,5 +1,4 @@
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
+1 -2
View File
@@ -1,5 +1,4 @@
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
+1 -2
View File
@@ -1,5 +1,4 @@
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
+1 -2
View File
@@ -1,5 +1,4 @@
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
+1 -2
View File
@@ -1,5 +1,4 @@
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
+1 -2
View File
@@ -1,5 +1,4 @@
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
+1 -2
View File
@@ -1,5 +1,4 @@
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
+1 -2
View File
@@ -1,5 +1,4 @@
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
+1 -2
View File
@@ -1,5 +1,4 @@
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
+1 -2
View File
@@ -1,5 +1,4 @@
import Model from './base';
import { belongsTo, hasMany } from 'ember-cli-mirage';
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
+1 -2
View File
@@ -1,5 +1,4 @@
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
+4 -5
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,13 +58,12 @@
"ember-resolver": "^8.0.3",
"ember-source": "~3.28.4",
"ember-template-lint": "^3.7.0",
"eslint": "^8.12.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ember": "^10.5.9",
"eslint-plugin-ember": "^10.5.4",
"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,7 +35,6 @@ 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,
},
@@ -87,38 +86,6 @@ 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');
@@ -222,36 +189,4 @@ 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: {},
},
});
});
});
+3 -6
View File
@@ -2,16 +2,13 @@
module.exports = {
root: true,
parser: '@babel/eslint-parser',
parser: 'babel-eslint',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
// This is specific babel-config. If grows consider creating a babel config file
requireConfigFile: false,
babelOptions: {
plugins: [['@babel/plugin-proposal-decorators', { legacy: true }]],
ecmaFeatures: {
legacyDecorators: true,
},
// end of babel-config
},
plugins: ['ember'],
extends: [
+3 -4
View File
@@ -27,12 +27,11 @@
"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",
@@ -52,9 +51,9 @@
"ember-resolver": "^8.0.3",
"ember-source": "~3.28.4",
"ember-template-lint": "^3.7.0",
"eslint": "^8.12.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ember": "^10.5.9",
"eslint-plugin-ember": "^10.5.4",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-qunit": "^6.2.0",
+3 -6
View File
@@ -2,16 +2,13 @@
module.exports = {
root: true,
parser: '@babel/eslint-parser',
parser: 'babel-eslint',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
// This is specific babel-config. If grows consider creating a babel config file
requireConfigFile: false,
babelOptions: {
plugins: [['@babel/plugin-proposal-decorators', { legacy: true }]],
ecmaFeatures: {
legacyDecorators: true,
},
// end of babel-config
},
plugins: ['ember'],
extends: [
@@ -1,18 +0,0 @@
<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>
@@ -1,20 +0,0 @@
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);
}
}
@@ -1 +0,0 @@
{{this.formatted}}
@@ -1,103 +0,0 @@
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',
});
}
}
@@ -1,9 +0,0 @@
{{#if this.lastRefreshed}}
<Rose::Toolbar::Info>
<RelativeDatetimeLive @date={{this.lastRefreshed}} />
</Rose::Toolbar::Info>
{{/if}}
<LoadingButton @onClick={{this.onClick}}>
{{t 'actions.refresh'}}
</LoadingButton>
@@ -1,20 +0,0 @@
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
@@ -1,78 +0,0 @@
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()));
}
}
@@ -1 +0,0 @@
export { default } from 'core/components/loading-button';
@@ -1 +0,0 @@
export { default } from 'core/components/relative-datetime-live';
@@ -1 +0,0 @@
export { default } from 'core/components/toolbar-refresher';
-1
View File
@@ -1 +0,0 @@
export { default } from 'core/services/clock-tick';
+3 -4
View File
@@ -41,12 +41,11 @@
"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",
@@ -65,9 +64,9 @@
"ember-resolver": "^8.0.3",
"ember-source": "~3.28.4",
"ember-template-lint": "^3.7.0",
"eslint": "^8.12.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ember": "^10.5.9",
"eslint-plugin-ember": "^10.5.4",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-qunit": "^6.2.0",
@@ -1,12 +0,0 @@
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>
<RelativeDatetimeLive @date={{this.now}} />
{{t "errors.401.title"}}
@@ -1,20 +0,0 @@
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');
});
});
@@ -1,38 +0,0 @@
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');
});
});
@@ -1,12 +0,0 @@
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);
});
});
+1 -2
View File
@@ -36,5 +36,4 @@ toggle-secret: Toggle secret visibility
minimize: Minimize
fullscreen: Fullscreen
clear-all-filters: Clear all filters
learn-more: Learn more
refresh: Refresh
learn-more: Learn more
-6
View File
@@ -41,9 +41,6 @@ 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:
@@ -146,6 +143,3 @@ 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,9 +278,6 @@ 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
+3 -6
View File
@@ -2,16 +2,13 @@
module.exports = {
root: true,
parser: '@babel/eslint-parser',
parser: 'babel-eslint',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
// This is specific babel-config. If grows consider creating a babel config file
requireConfigFile: false,
babelOptions: {
plugins: [['@babel/plugin-proposal-decorators', { legacy: true }]],
ecmaFeatures: {
legacyDecorators: true,
},
// end of babel-config
},
plugins: ['ember'],
extends: [
+1 -2
View File
@@ -1,8 +1,7 @@
'use strict';
module.exports = {
plugins: ['ember-template-lint-plugin-prettier'],
extends: ['octane', 'ember-template-lint-plugin-prettier:recommended'],
extends: 'octane',
overrides: [
{
files: [
@@ -1,12 +1,14 @@
<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,29 +1,34 @@
<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>
@@ -1,5 +0,0 @@
import Component from '@glimmer/component';
export default class RoseButtonComponent extends Component {
// =attributes
}
@@ -1,32 +1,34 @@
<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,3 +1,8 @@
<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,44 +1,41 @@
{{#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>
@@ -46,42 +43,36 @@
<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,18 +1,19 @@
<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,23 +1,22 @@
<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>
@@ -27,35 +26,27 @@
</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,8 +10,7 @@
@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>
@@ -20,8 +19,7 @@
...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>
@@ -32,8 +30,7 @@
...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>
@@ -41,10 +38,9 @@
<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,15 +1,12 @@
<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,9 +1,10 @@
<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,3 +1,5 @@
<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,9 +1,8 @@
{{#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>
@@ -14,8 +13,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,5 +1,8 @@
<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,15 +1,19 @@
<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,15 +1,12 @@
{{#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,35 +1,31 @@
<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,3 +1,5 @@
<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,25 +1,21 @@
<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'
<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='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'}}
</div>
{{/if}}
<div class='rose-form-fieldset-body'>
{{yield to='body'}}
</div>
</fieldset>
@@ -1,16 +1,12 @@
<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,42 +1,37 @@
<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
--}}
{{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'
)
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
submitDisabled=this.disabled
cancelDisabled=(if @showEditToggle @disabled this.disabled)
cancel=this.handleCancel
enableEdit=this.enableEdit
)
}}
</form>
isEditable=this.isEditable
)}}
</form>
@@ -1,47 +1,44 @@
{{#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/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))
{{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)
)
)}}
{{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
@@ -51,15 +48,13 @@
@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,10 +1,9 @@
<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,3 +1,7 @@
<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,20 +1,4 @@
{{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,33 +1,30 @@
<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}}
@@ -35,4 +32,4 @@
{{yield}}
</div>
</div>
@@ -1,57 +1,51 @@
{{#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))
{{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'>
<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}}>
<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))
{{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,39 +1,34 @@
{{#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/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))
{{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)
)
)}}
{{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}}
@@ -45,15 +40,11 @@
@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,9 +1,8 @@
<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,9 +1,10 @@
<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,8 +1,6 @@
<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,3 +1,5 @@
<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,11 +1,7 @@
<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,15 +1,9 @@
<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,10 +1,6 @@
<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,27 +1,31 @@
<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,3 +1,5 @@
<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