Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb36cde137 | ||
|
|
ccb266ea7c | ||
|
|
8545697b43 | ||
|
|
a8ae8d28df | ||
|
|
952b894a32 | ||
|
|
6f449b3b9b | ||
|
|
0f3c2f043b | ||
|
|
82c94518d9 | ||
|
|
68a269efac | ||
|
|
75ef323e6d | ||
|
|
ccde5e88da | ||
|
|
1071241604 | ||
|
|
316f0907fc | ||
|
|
3bdae6dce8 | ||
|
|
367545fd4d | ||
|
|
702ad64716 | ||
|
|
043dbc3736 | ||
|
|
01e4ec0a07 | ||
|
|
a7b3da2231 | ||
|
|
de6416efbd | ||
|
|
76befc0c1d | ||
|
|
f71d01902a | ||
|
|
56d84d652b | ||
|
|
9cf216179a | ||
|
|
050cfdd056 | ||
|
|
79fb0db882 | ||
|
|
a2c6bc643d | ||
|
|
07ed40ce03 | ||
|
|
e0cbbefb41 | ||
|
|
2a1e4858fa | ||
|
|
7b154b223a | ||
|
|
550cadf612 | ||
|
|
95cece1481 | ||
|
|
94a3c1fcf1 | ||
|
|
f2b53d2f45 | ||
|
|
6249e945b8 | ||
|
|
26e074dbef | ||
|
|
90c9fa8b73 | ||
|
|
215bf00407 | ||
|
|
d8efefc2b3 | ||
|
|
95ed2c0fda | ||
|
|
8776b46277 | ||
|
|
670f38df74 | ||
|
|
226475a47d | ||
|
|
1072be1eff | ||
|
|
22d8af72ae | ||
|
|
79596010e9 | ||
|
|
8e884d53ae | ||
|
|
505820eb6c | ||
|
|
4b09c7014b | ||
|
|
f4535c8307 | ||
|
|
9fae8f2a9f | ||
|
|
a7bcc0c332 | ||
|
|
f877477cd7 | ||
|
|
335df22a38 | ||
|
|
ca09b538f7 | ||
|
|
68ba653984 | ||
|
|
5a90533a2e | ||
|
|
3d7b8537e1 | ||
|
|
8d6669c8a1 | ||
|
|
7c3f57c7fa | ||
|
|
2543d14c5a | ||
|
|
fe7cb014a0 | ||
|
|
adcfb00131 |
No files matched your search
@@ -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):
|
||||
@@ -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/
|
||||
@@ -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'
|
||||
|
||||
@@ -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"
|
||||
@@ -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]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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: {},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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: [
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'core/services/clock-tick';
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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'>
|
||||
©
|
||||
</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
Reference in new issue
Block a user