Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5edd4dd52 | ||
|
|
f102e7fca2 | ||
|
|
f593e6a8b1 | ||
|
|
f54d48c380 | ||
|
|
0129784322 | ||
|
|
7317ca2ff5 | ||
|
|
1ddabf4980 | ||
|
|
a574023c05 | ||
|
|
861562201b | ||
|
|
4cdcaefe15 | ||
|
|
e2487b7e98 | ||
|
|
f879bbb1ec | ||
|
|
933e272764 | ||
|
|
2953635aeb | ||
|
|
194561e1f8 | ||
|
|
4a3d8eee63 | ||
|
|
7d6f3df140 | ||
|
|
722acdc1fc | ||
|
|
3f8e39d0e1 | ||
|
|
9e7852f18d | ||
|
|
c548c381bf | ||
|
|
63be0f3aec | ||
|
|
8e4fac5ce2 | ||
|
|
2a9666285a | ||
|
|
bff94d6b4d | ||
|
|
5b8fc06e21 | ||
|
|
a20483d1af | ||
|
|
0bf5221389 | ||
|
|
297db470bd | ||
|
|
91a6023145 | ||
|
|
7b96dd1f81 | ||
|
|
aee55cb171 | ||
|
|
370b3ea1fb | ||
|
|
4f972a82d6 |
No files matched your search
@@ -3,21 +3,23 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "release/**"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
dependencies:
|
||||
name: Install dependencies
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
||||
id: node-modules-cache
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
path: "**/node_modules"
|
||||
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
node-modules-
|
||||
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
|
||||
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
||||
with:
|
||||
node-version: 16
|
||||
- run: yarn install
|
||||
@@ -26,16 +28,16 @@ jobs:
|
||||
needs: [dependencies]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
||||
id: node-modules-cache
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
path: "**/node_modules"
|
||||
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
node-modules-
|
||||
- name: Build
|
||||
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
|
||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
||||
with:
|
||||
node-version: 16
|
||||
- run: yarn run build:ui:admin:oss
|
||||
@@ -54,16 +56,16 @@ jobs:
|
||||
needs: [dependencies]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
||||
id: node-modules-cache
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
path: "**/node_modules"
|
||||
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
node-modules-
|
||||
- name: Build
|
||||
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
|
||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
||||
with:
|
||||
node-version: 16
|
||||
- run: yarn run build:ui:admin:enterprise
|
||||
@@ -77,16 +79,16 @@ jobs:
|
||||
needs: [dependencies]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
||||
id: node-modules-cache
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
path: "**/node_modules"
|
||||
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
node-modules-
|
||||
- name: Build
|
||||
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
|
||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
||||
with:
|
||||
node-version: 16
|
||||
- run: yarn run build:ui:admin:hcp
|
||||
|
||||
@@ -30,11 +30,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@8e0b1c74b1d5a0077b04d064c76ee714d3da7637 # codeql-bundle-v2.14.6
|
||||
uses: github/codeql-action/init@bad341350a2f5616f9e048e51360cedc49181ce8 # codeql-bundle-v2.15.1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -54,4 +54,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@8e0b1c74b1d5a0077b04d064c76ee714d3da7637 # codeql-bundle-v2.14.6
|
||||
uses: github/codeql-action/analyze@bad341350a2f5616f9e048e51360cedc49181ce8 # codeql-bundle-v2.15.1
|
||||
@@ -6,7 +6,7 @@ jobs:
|
||||
name: Install dependencies
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
||||
id: node-modules-cache
|
||||
with:
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
node-modules-
|
||||
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
|
||||
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
||||
with:
|
||||
node-version: 16
|
||||
- run: yarn install
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
needs: [dependencies]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
||||
id: node-modules-cache
|
||||
with:
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
node-modules-
|
||||
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
|
||||
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
||||
with:
|
||||
node-version: 16
|
||||
- run: yarn run compliance:licenses
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
||||
id: node-modules-cache
|
||||
with:
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
node-modules-
|
||||
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
|
||||
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
||||
with:
|
||||
node-version: 16
|
||||
- run: yarn lint
|
||||
@@ -62,13 +62,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
||||
id: node-modules-cache
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
|
||||
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
||||
with:
|
||||
node-version: 16
|
||||
- run: yarn test
|
||||
@@ -7,7 +7,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
|
||||
- run: |
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
trigger-gha-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- name: Release description
|
||||
run: |
|
||||
echo "Triggering release with a TAG ${GITHUB_REF#refs/tags/}"
|
||||
|
||||
@@ -6,11 +6,22 @@ COMMIT_SOURCE=$2
|
||||
SHA1=$3
|
||||
# Gets the current branch name but if we're in a detached head state, return "HEAD"
|
||||
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
|
||||
# Regex to match the ICU-#### branch name pattern we use
|
||||
ISSUE_REGEX="^(ICU-[0-9]+)"
|
||||
|
||||
# Don't run commitizen for merge or squash commits, as well as when rebasing
|
||||
if [ "${COMMIT_SOURCE}" = merge ] || [ "${COMMIT_SOURCE}" = squash ] || [ "${COMMIT_SOURCE}" = "message" -a "${BRANCH_NAME}" = "HEAD" ];then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# This is to allow interaction with the terminal for commitizen
|
||||
exec < /dev/tty && npx git-cz --hook || true
|
||||
# If the branch name matches, set the JIRA link automatically
|
||||
if [[ $BRANCH_NAME =~ $ISSUE_REGEX ]]
|
||||
then
|
||||
issue="${BASH_REMATCH[1]}"
|
||||
url="https://hashicorp.atlassian.net/browse/${issue}"
|
||||
exec < /dev/tty && npx git-cz --issues="$url" --hook || true
|
||||
else
|
||||
# This is to allow interaction with the terminal for commitizen
|
||||
exec < /dev/tty && npx git-cz --hook || true
|
||||
fi
|
||||
|
||||
@@ -38,7 +38,6 @@ module.exports = {
|
||||
files: [
|
||||
'./.eslintrc.js',
|
||||
'./.prettierrc.js',
|
||||
'./.stylelintrc.js',
|
||||
'./.template-lintrc.js',
|
||||
'./ember-cli-build.js',
|
||||
'./index.js',
|
||||
|
||||
@@ -14,10 +14,25 @@ export default class SessionAbility extends ModelAbility {
|
||||
// =permissions
|
||||
|
||||
/**
|
||||
* Only "active" or "pending" sessions may be read.
|
||||
* Only available sessions may be read.
|
||||
* @type {boolean}
|
||||
*/
|
||||
get canRead() {
|
||||
return (this.model.isActive || this.model.isPending) && super.canRead;
|
||||
return (
|
||||
this.model.isAvailable &&
|
||||
(this.hasAuthorizedAction('read:self') || super.canRead)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only available sessions may be canceled.
|
||||
* @type {boolean}
|
||||
*/
|
||||
get canCancel() {
|
||||
return (
|
||||
this.model.isAvailable &&
|
||||
(this.hasAuthorizedAction('cancel:self') ||
|
||||
this.hasAuthorizedAction('cancel'))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -54,4 +54,10 @@ export default class GeneratedHostModel extends BaseModel {
|
||||
readOnly: true,
|
||||
})
|
||||
plugin;
|
||||
|
||||
@attr({
|
||||
emptyArrayIfMissing: true,
|
||||
readOnly: true,
|
||||
})
|
||||
host_set_ids;
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
|
||||
import GeneratedSessionModel from '../generated/models/session';
|
||||
import { computed } from '@ember/object';
|
||||
import { equal } from '@ember/object/computed';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { A } from '@ember/array';
|
||||
@@ -127,8 +126,7 @@ export default class SessionModel extends GeneratedSessionModel {
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
@computed('isActive', 'isPending')
|
||||
get isCancelable() {
|
||||
get isAvailable() {
|
||||
return this.isActive || this.isPending;
|
||||
}
|
||||
|
||||
@@ -136,7 +134,6 @@ export default class SessionModel extends GeneratedSessionModel {
|
||||
* The full proxy address and port if address exists, otherwise null.
|
||||
* @type {?string}
|
||||
*/
|
||||
@computed('proxy_address', 'proxy_port')
|
||||
get proxy() {
|
||||
return this.proxy_address
|
||||
? `${this.proxy_address}:${this.proxy_port}`
|
||||
@@ -148,6 +145,9 @@ export default class SessionModel extends GeneratedSessionModel {
|
||||
* @type {TargetModel}
|
||||
*/
|
||||
get target() {
|
||||
if (!this.target_id) {
|
||||
return null;
|
||||
}
|
||||
return this.store.peekRecord('target', this.target_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -431,9 +431,17 @@ function routes() {
|
||||
return hostSets.where({ hostCatalogId });
|
||||
}
|
||||
);
|
||||
|
||||
this.post('/host-sets', function ({ hostCatalogs, hostSets }) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const hostCatalog = hostCatalogs.find(attrs.hostCatalogId);
|
||||
//this needs to be attached while creating a plugin type host set to mimic API
|
||||
if (hostCatalog.plugin) {
|
||||
attrs.type = 'plugin';
|
||||
attrs.plugin = {
|
||||
name: hostCatalog.plugin.name,
|
||||
};
|
||||
}
|
||||
attrs.scopeId = hostCatalog.scope.id;
|
||||
return hostSets.create(attrs);
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
|
||||
import {
|
||||
TYPE_AUTH_METHOD_PASSWORD,
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
TYPES_AUTH_METHOD,
|
||||
@@ -23,11 +24,17 @@ export default factory.extend({
|
||||
'delete',
|
||||
'authenticate',
|
||||
],
|
||||
authorized_collection_actions: () => {
|
||||
return {
|
||||
accounts: ['create', 'list'],
|
||||
'managed-groups': ['create', 'list'],
|
||||
};
|
||||
authorized_collection_actions() {
|
||||
switch (this.type) {
|
||||
case TYPE_AUTH_METHOD_PASSWORD:
|
||||
return { accounts: ['create', 'list'] };
|
||||
case TYPE_AUTH_METHOD_LDAP:
|
||||
case TYPE_AUTH_METHOD_OIDC:
|
||||
return {
|
||||
accounts: ['create', 'list'],
|
||||
'managed-groups': ['create', 'list'],
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
id: () => generateId('am_'),
|
||||
|
||||
@@ -85,7 +85,16 @@ export default factory.extend({
|
||||
afterCreate(hostCatalog, server) {
|
||||
const { scope, type } = hostCatalog;
|
||||
const hosts = server.createList('host', 10, { scope, hostCatalog, type });
|
||||
server.createList('host-set', 3, { scope, hostCatalog, hosts, type });
|
||||
const hostSets = server.createList('host-set', 3, {
|
||||
scope,
|
||||
hostCatalog,
|
||||
hosts,
|
||||
type,
|
||||
});
|
||||
const hostSetIds = hostSets.map((hostSet) => hostSet.id);
|
||||
hosts.forEach((host) => {
|
||||
host.update({ hostSetIds });
|
||||
});
|
||||
},
|
||||
}),
|
||||
});
|
||||
@@ -22,14 +22,8 @@ export default factory.extend({
|
||||
authorized_collection_actions() {
|
||||
const collectionActions = {
|
||||
scopes: ['create', 'list'],
|
||||
users: ['create', 'list'],
|
||||
sessions: ['list'],
|
||||
groups: ['create', 'list'],
|
||||
roles: ['create', 'list'],
|
||||
targets: ['create', 'list'],
|
||||
'credential-stores': ['create', 'list'],
|
||||
'auth-methods': ['create', 'list'],
|
||||
'host-catalogs': ['create', 'list'],
|
||||
};
|
||||
|
||||
// Worker permissions only available on the global scope
|
||||
@@ -41,6 +35,15 @@ export default factory.extend({
|
||||
if (this.type === 'global' || this.type === 'org') {
|
||||
collectionActions['storage-buckets'] = ['create', 'list'];
|
||||
collectionActions['session-recordings'] = ['list'];
|
||||
collectionActions.users = ['create', 'list'];
|
||||
collectionActions['auth-methods'] = ['create', 'list'];
|
||||
}
|
||||
|
||||
if (this.type === 'project') {
|
||||
collectionActions['credential-stores'] = ['create', 'list'];
|
||||
collectionActions['host-catalogs'] = ['create', 'list'];
|
||||
collectionActions.sessions = ['list'];
|
||||
collectionActions.targets = ['create', 'list'];
|
||||
}
|
||||
|
||||
return collectionActions;
|
||||
|
||||
@@ -7,6 +7,7 @@ import factory from '../generated/factories/session';
|
||||
import { trait } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import generateId from '../helpers/id';
|
||||
import permissions from '../helpers/permissions';
|
||||
|
||||
const statusStrings = ['pending', 'active', 'canceling', 'terminated'];
|
||||
|
||||
@@ -15,7 +16,8 @@ export const pickRandomStatusString = () =>
|
||||
|
||||
export default factory.extend({
|
||||
id: () => generateId('ss_'),
|
||||
|
||||
authorized_actions: () =>
|
||||
permissions.authorizedActionsFor('session') || ['read', 'cancel'],
|
||||
status: pickRandomStatusString(),
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,4 +7,13 @@ import ApplicationSerializer from './application';
|
||||
|
||||
export default ApplicationSerializer.extend({
|
||||
modelName: 'host',
|
||||
|
||||
_hashForModel(model) {
|
||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
json.host_catalog_id = model.hostCatalogId;
|
||||
return json;
|
||||
},
|
||||
});
|
||||
@@ -14,7 +14,7 @@
|
||||
"lint:fix": "concurrently \"npm:lint:*:fix\" --names \"fix:\"",
|
||||
"lint:js": "eslint .",
|
||||
"lint:js:fix": "eslint . --fix",
|
||||
"format": "yarn run format:js",
|
||||
"format": "concurrently \"npm:format:*\" --names \"format:\"",
|
||||
"format:js": "prettier --write '{addon,app,config,stories,tests,mirage}/**/*.js' *.js",
|
||||
"start": "ember serve",
|
||||
"test": "ember exam --test-port 0 --split=4 --parallel=1 --random",
|
||||
@@ -31,8 +31,8 @@
|
||||
"ember-fetch": "^8.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.18.5",
|
||||
"@babel/eslint-parser": "^7.21.3",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.18.2",
|
||||
"@babel/plugin-proposal-decorators": "^7.21.0",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/string": "^3.0.1",
|
||||
|
||||
@@ -97,4 +97,96 @@ module('Unit | Ability | session', function (hooks) {
|
||||
|
||||
assert.false(canService.can('read session', session));
|
||||
});
|
||||
|
||||
test('can read a session that has read:self', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const session = store.createRecord('session', {
|
||||
authorized_actions: ['read:self'],
|
||||
status: STATUS_SESSION_ACTIVE,
|
||||
});
|
||||
|
||||
assert.true(canService.can('read session', session));
|
||||
});
|
||||
|
||||
test('can cancel a session that is active', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const session = store.createRecord('session', {
|
||||
authorized_actions: ['cancel'],
|
||||
status: STATUS_SESSION_ACTIVE,
|
||||
});
|
||||
|
||||
assert.true(canService.can('cancel session', session));
|
||||
});
|
||||
|
||||
test('can cancel a session that has cancel:self', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const session = store.createRecord('session', {
|
||||
authorized_actions: ['cancel:self'],
|
||||
status: STATUS_SESSION_ACTIVE,
|
||||
});
|
||||
|
||||
assert.true(canService.can('cancel session', session));
|
||||
});
|
||||
|
||||
test('can cancel a session that is pending', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const session = store.createRecord('session', {
|
||||
authorized_actions: ['cancel'],
|
||||
status: STATUS_SESSION_PENDING,
|
||||
});
|
||||
|
||||
assert.true(canService.can('cancel session', session));
|
||||
});
|
||||
|
||||
test('cannot cancel a session that is canceling', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const session = store.createRecord('session', {
|
||||
authorized_actions: ['cancel'],
|
||||
status: STATUS_SESSION_CANCELING,
|
||||
});
|
||||
|
||||
assert.false(canService.can('cancel session', session));
|
||||
});
|
||||
|
||||
test('cannot cancel a session that is terminated', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const session = store.createRecord('session', {
|
||||
authorized_actions: ['cancel'],
|
||||
status: STATUS_SESSION_TERMINATED,
|
||||
});
|
||||
|
||||
assert.false(canService.can('cancel session', session));
|
||||
});
|
||||
|
||||
test('cannot cancel a session that is not authorized', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
const activeSession = store.createRecord('session', {
|
||||
authorized_actions: [],
|
||||
status: STATUS_SESSION_ACTIVE,
|
||||
});
|
||||
const pendingSession = store.createRecord('session', {
|
||||
authorized_actions: [],
|
||||
status: STATUS_SESSION_PENDING,
|
||||
});
|
||||
const cancelingSession = store.createRecord('session', {
|
||||
authorized_actions: [],
|
||||
status: STATUS_SESSION_CANCELING,
|
||||
});
|
||||
const terminatedSession = store.createRecord('session', {
|
||||
authorized_actions: [],
|
||||
status: STATUS_SESSION_TERMINATED,
|
||||
});
|
||||
|
||||
assert.false(canService.can('cancel session', activeSession));
|
||||
assert.false(canService.can('cancel session', pendingSession));
|
||||
assert.false(canService.can('cancel session', cancelingSession));
|
||||
assert.false(canService.can('cancel session', terminatedSession));
|
||||
});
|
||||
});
|
||||
@@ -13,7 +13,7 @@ module('Unit | Model | session', function (hooks) {
|
||||
let store = this.owner.lookup('service:store');
|
||||
let model = store.createRecord('session', {});
|
||||
assert.ok(model);
|
||||
assert.notOk(model.isCancelable);
|
||||
assert.notOk(model.isAvailable);
|
||||
});
|
||||
|
||||
test('it allows cancellation of an active session', function (assert) {
|
||||
@@ -21,7 +21,7 @@ module('Unit | Model | session', function (hooks) {
|
||||
let model = store.createRecord('session', {
|
||||
status: 'active',
|
||||
});
|
||||
assert.ok(model.isCancelable);
|
||||
assert.ok(model.isAvailable);
|
||||
});
|
||||
|
||||
test('it allows cancellation of a pending session', function (assert) {
|
||||
@@ -29,7 +29,7 @@ module('Unit | Model | session', function (hooks) {
|
||||
let model = store.createRecord('session', {
|
||||
status: 'pending',
|
||||
});
|
||||
assert.ok(model.isCancelable);
|
||||
assert.ok(model.isAvailable);
|
||||
});
|
||||
|
||||
test('it computes isActive', function (assert) {
|
||||
|
||||
@@ -57,6 +57,7 @@ module('Unit | Serializer | host', function (hooks) {
|
||||
address: '10.0.0.1',
|
||||
dns_names: [],
|
||||
ip_addresses: [],
|
||||
host_set_ids: [],
|
||||
},
|
||||
relationships: {},
|
||||
},
|
||||
@@ -78,6 +79,7 @@ module('Unit | Serializer | host', function (hooks) {
|
||||
authorized_actions: ['no-op', 'read'],
|
||||
ip_addresses: ['10.0.0.1', '10.0.0.2', '10.0.0.3'],
|
||||
dns_names: ['test.example.internal', 'test.example.external'],
|
||||
host_set_ids: ['hst_12345'],
|
||||
};
|
||||
const normalized = serializer.normalizeSingleResponse(store, host, payload);
|
||||
assert.deepEqual(normalized, {
|
||||
@@ -92,6 +94,7 @@ module('Unit | Serializer | host', function (hooks) {
|
||||
ip_addresses: ['10.0.0.1', '10.0.0.2', '10.0.0.3'],
|
||||
dns_names: ['test.example.internal', 'test.example.external'],
|
||||
plugin: { name: 'aws' },
|
||||
host_set_ids: ['hst_12345'],
|
||||
},
|
||||
relationships: {},
|
||||
},
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
"disableAnalytics": false,
|
||||
|
||||
/**
|
||||
Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript
|
||||
rather than JavaScript by default, when a TypeScript version of a given blueprint is available.
|
||||
Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript
|
||||
rather than JavaScript by default, when a TypeScript version of a given blueprint is available.
|
||||
*/
|
||||
"isTypeScriptProject": false
|
||||
}
|
||||
@@ -9,12 +9,14 @@ module.exports = {
|
||||
root: true,
|
||||
parser: '@babel/eslint-parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
ecmaVersion: 'latest',
|
||||
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 }]],
|
||||
plugins: [
|
||||
['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }],
|
||||
],
|
||||
},
|
||||
// end of babel-config
|
||||
},
|
||||
@@ -51,8 +53,7 @@ module.exports = {
|
||||
browser: false,
|
||||
node: true,
|
||||
},
|
||||
plugins: ['node'],
|
||||
extends: ['plugin:node/recommended'],
|
||||
extends: ['plugin:n/recommended'],
|
||||
},
|
||||
{
|
||||
// Test files:
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
/.travis.yml
|
||||
/.watchmanconfig
|
||||
/bower.json
|
||||
/config/ember-try.js
|
||||
/CONTRIBUTING.md
|
||||
/ember-cli-build.js
|
||||
/testem.js
|
||||
|
||||
@@ -9,7 +9,7 @@ const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
|
||||
const { maybeEmbroider } = require('@embroider/test-setup');
|
||||
|
||||
module.exports = function (defaults) {
|
||||
let app = new EmberAddon(defaults, {
|
||||
const app = new EmberAddon(defaults, {
|
||||
'ember-simple-auth': {
|
||||
// https://github.com/mainmatter/ember-simple-auth/blob/master/guides/upgrade-to-v4.md#call-sessionsetup-method-in-your-applicationroute
|
||||
useSessionSetupMethod: true,
|
||||
|
||||
+21
-20
@@ -8,8 +8,8 @@
|
||||
"ember-addon"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "npm-run-all --aggregate-output --continue-on-error --parallel \"lint:!(fix)\"",
|
||||
"lint:fix": "npm-run-all --aggregate-output --continue-on-error --parallel lint:*:fix",
|
||||
"lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
|
||||
"lint:fix": "concurrently \"npm:lint:*:fix\" --names \"fix:\"",
|
||||
"lint:js": "eslint .",
|
||||
"lint:js:fix": "eslint . --fix",
|
||||
"format": "yarn run format:js",
|
||||
@@ -22,22 +22,24 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"ember-cli-babel": "^7.26.11",
|
||||
"ember-cli-htmlbars": "^6.1.0",
|
||||
"ember-cli-htmlbars": "^6.2.0",
|
||||
"ember-fetch": "^8.1.1",
|
||||
"ember-simple-auth": "^4.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.18.2",
|
||||
"@babel/plugin-proposal-decorators": "^7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.21.0",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/test-helpers": "^2.8.1",
|
||||
"@ember/string": "^3.0.1",
|
||||
"@ember/test-helpers": "^2.9.3",
|
||||
"@embroider/test-setup": "^2.1.1",
|
||||
"@glimmer/component": "^1.1.2",
|
||||
"@glimmer/tracking": "^1.1.2",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"concurrently": "^8.0.1",
|
||||
"doctoc": "^2.2.0",
|
||||
"ember-auto-import": "^2.4.3",
|
||||
"ember-cli": "^4.4.1",
|
||||
"ember-auto-import": "^2.6.3",
|
||||
"ember-cli": "^4.12.2",
|
||||
"ember-cli-dependency-checker": "^3.3.1",
|
||||
"ember-cli-inject-live-reload": "^2.1.0",
|
||||
"ember-cli-sri": "^2.1.1",
|
||||
@@ -47,23 +49,22 @@
|
||||
"ember-export-application-global": "^2.0.1",
|
||||
"ember-load-initializers": "^2.1.2",
|
||||
"ember-page-title": "^7.0.0",
|
||||
"ember-qunit": "^6.0.0",
|
||||
"ember-resolver": "^8.0.3",
|
||||
"ember-source": "~4.4.0",
|
||||
"ember-qunit": "^6.2.0",
|
||||
"ember-resolver": "^10.0.0",
|
||||
"ember-source": "~4.12.0",
|
||||
"ember-source-channel-url": "^3.0.0",
|
||||
"ember-template-lint": "^4.14.0",
|
||||
"eslint": "^8.18.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-ember": "^10.6.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-qunit": "^7.3.0",
|
||||
"ember-template-lint": "^5.7.2",
|
||||
"eslint": "^8.37.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-ember": "^11.5.0",
|
||||
"eslint-plugin-n": "^15.7.0",
|
||||
"eslint-plugin-qunit": "^7.3.4",
|
||||
"loader.js": "^4.7.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"pretender": "^3.4.3",
|
||||
"prettier": "^2.6.2",
|
||||
"qunit": "^2.19.1",
|
||||
"prettier": "^2.8.7",
|
||||
"qunit": "^2.19.4",
|
||||
"qunit-dom": "^2.0.0",
|
||||
"webpack": "^5.76.0"
|
||||
"webpack": "^5.78.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "16.* || 18.*"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"packages": [
|
||||
{
|
||||
"name": "ember-cli",
|
||||
"version": "4.4.1",
|
||||
"version": "4.12.2",
|
||||
"blueprints": [
|
||||
{
|
||||
"name": "addon",
|
||||
|
||||
@@ -11,14 +11,6 @@ const { embroiderSafe, embroiderOptimized } = require('@embroider/test-setup');
|
||||
module.exports = async function () {
|
||||
return {
|
||||
scenarios: [
|
||||
{
|
||||
name: 'ember-lts-3.28',
|
||||
npm: {
|
||||
devDependencies: {
|
||||
'ember-source': '~3.28.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ember-lts-4.4',
|
||||
npm: {
|
||||
@@ -27,6 +19,14 @@ module.exports = async function () {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ember-lts-4.8',
|
||||
npm: {
|
||||
devDependencies: {
|
||||
'ember-source': '~4.8.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ember-release',
|
||||
npm: {
|
||||
@@ -6,20 +6,17 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (environment) {
|
||||
let ENV = {
|
||||
const ENV = {
|
||||
modulePrefix: 'dummy',
|
||||
environment,
|
||||
rootURL: '/',
|
||||
locationType: 'history',
|
||||
EmberENV: {
|
||||
EXTEND_PROTOTYPES: false,
|
||||
FEATURES: {
|
||||
// Here you can enable experimental features on an ember canary build
|
||||
// e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true
|
||||
},
|
||||
EXTEND_PROTOTYPES: {
|
||||
// Prevent Ember Data from overriding Date.parse.
|
||||
Date: false,
|
||||
},
|
||||
},
|
||||
|
||||
APP: {
|
||||
|
||||
Vendored
Whitespace-only changes.
@@ -8,8 +8,8 @@
|
||||
"disableAnalytics": false,
|
||||
|
||||
/**
|
||||
Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript
|
||||
rather than JavaScript by default, when a TypeScript version of a given blueprint is available.
|
||||
Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript
|
||||
rather than JavaScript by default, when a TypeScript version of a given blueprint is available.
|
||||
*/
|
||||
"isTypeScriptProject": false
|
||||
}
|
||||
@@ -9,12 +9,14 @@ module.exports = {
|
||||
root: true,
|
||||
parser: '@babel/eslint-parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
ecmaVersion: 'latest',
|
||||
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 }]],
|
||||
plugins: [
|
||||
['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }],
|
||||
],
|
||||
},
|
||||
// end of babel-config
|
||||
},
|
||||
@@ -51,8 +53,7 @@ module.exports = {
|
||||
browser: false,
|
||||
node: true,
|
||||
},
|
||||
plugins: ['node'],
|
||||
extends: ['plugin:node/recommended'],
|
||||
extends: ['plugin:n/recommended'],
|
||||
},
|
||||
{
|
||||
// Test files:
|
||||
|
||||
@@ -8,4 +8,9 @@
|
||||
module.exports = {
|
||||
plugins: ['ember-template-lint-plugin-prettier'],
|
||||
extends: ['recommended', 'ember-template-lint-plugin-prettier:recommended'],
|
||||
rules: {
|
||||
'no-curly-component-invocation': {
|
||||
allow: ['app-name', 'company-name', 'company-copyright'],
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -3,12 +3,10 @@
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
}}
|
||||
|
||||
{{! //TODO fix the issue and delete disabling the rule }}
|
||||
{{! template-lint-disable no-passed-in-event-handlers }}
|
||||
{{#if @model.type}}
|
||||
{{component
|
||||
(concat 'form/authenticate/' @model.type)
|
||||
submit=@submit
|
||||
onSubmit=@submit
|
||||
disabled=@disabled
|
||||
}}
|
||||
{{/if}}
|
||||
@@ -3,4 +3,4 @@
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
}}
|
||||
|
||||
<Form::Authenticate::Details @onSubmit={{@submit}} @disabled={{@disabled}} />
|
||||
<Form::Authenticate::Details @onSubmit={{@onSubmit}} @disabled={{@disabled}} />
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<Rose::Form
|
||||
class='full-width'
|
||||
@onSubmit={{@submit}}
|
||||
@onSubmit={{@onSubmit}}
|
||||
@disabled={{@disabled}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
}}
|
||||
|
||||
<Form::Authenticate::Details @onSubmit={{@submit}} @disabled={{@disabled}} />
|
||||
<Form::Authenticate::Details @onSubmit={{@onSubmit}} @disabled={{@disabled}} />
|
||||
@@ -9,7 +9,7 @@ const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
|
||||
const { maybeEmbroider } = require('@embroider/test-setup');
|
||||
|
||||
module.exports = function (defaults) {
|
||||
let app = new EmberAddon(defaults, {
|
||||
const app = new EmberAddon(defaults, {
|
||||
// Add options here
|
||||
'ember-simple-auth': {
|
||||
useSessionSetupMethod: true,
|
||||
|
||||
+27
-24
@@ -15,13 +15,13 @@
|
||||
"scripts": {
|
||||
"build:development": "ember build",
|
||||
"build": "ember build --environment=production",
|
||||
"lint": "npm-run-all --aggregate-output --continue-on-error --parallel \"lint:!(fix)\"",
|
||||
"lint:fix": "npm-run-all --aggregate-output --continue-on-error --parallel lint:*:fix",
|
||||
"lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
|
||||
"lint:fix": "concurrently \"npm:lint:*:fix\" --names \"fix:\"",
|
||||
"lint:hbs": "ember-template-lint .",
|
||||
"lint:hbs:fix": "ember-template-lint . --fix",
|
||||
"lint:js": "eslint .",
|
||||
"lint:js:fix": "eslint . --fix",
|
||||
"format": "npm-run-all format:*",
|
||||
"format": "concurrently \"npm:format:*\" --names \"format:\"",
|
||||
"format:js": "prettier --write '{addon,app,config,stories,tests}/**/*.js' *.js",
|
||||
"format:hbs": "prettier --write '{addon,app,tests}/**/*.hbs'",
|
||||
"start": "ember serve",
|
||||
@@ -33,10 +33,10 @@
|
||||
"dependencies": {
|
||||
"api": "*",
|
||||
"auth": "*",
|
||||
"ember-auto-import": "^2.4.2",
|
||||
"ember-auto-import": "^2.6.3",
|
||||
"ember-browser-services": "^4.0.3",
|
||||
"ember-cli-babel": "^7.26.11",
|
||||
"ember-cli-htmlbars": "^6.1.0",
|
||||
"ember-cli-htmlbars": "^6.2.0",
|
||||
"ember-feature-flags": "^6.0.0",
|
||||
"ember-intl": "^6.0.0-beta.6",
|
||||
"ember-loading": "^2.0.0",
|
||||
@@ -46,43 +46,46 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.18.2",
|
||||
"@babel/plugin-proposal-decorators": "^7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.21.0",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/test-helpers": "^2.8.1",
|
||||
"@ember/string": "^3.0.1",
|
||||
"@ember/test-helpers": "^2.9.3",
|
||||
"@embroider/test-setup": "^2.1.1",
|
||||
"@faker-js/faker": "^8.0.2",
|
||||
"@glimmer/component": "^1.1.2",
|
||||
"@glimmer/tracking": "^1.1.2",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"concurrently": "^8.0.1",
|
||||
"doctoc": "^2.2.0",
|
||||
"ember-cli": "^4.4.1",
|
||||
"ember-cli": "^4.12.2",
|
||||
"ember-cli-dependency-checker": "^3.3.1",
|
||||
"ember-cli-inject-live-reload": "^2.1.0",
|
||||
"ember-cli-sri": "^2.1.1",
|
||||
"ember-cli-terser": "^4.0.2",
|
||||
"ember-disable-prototype-extensions": "^1.1.3",
|
||||
"ember-export-application-global": "^2.0.1",
|
||||
"ember-inline-svg": "^1.0.1",
|
||||
"ember-load-initializers": "^2.1.2",
|
||||
"ember-page-title": "^7.0.0",
|
||||
"ember-qunit": "^6.0.0",
|
||||
"ember-resolver": "^8.0.3",
|
||||
"ember-source": "~4.4.0",
|
||||
"ember-template-lint": "^4.14.0",
|
||||
"ember-template-lint-plugin-prettier": "^4.0.0",
|
||||
"eslint": "^8.18.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-ember": "^10.6.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-qunit": "^7.3.0",
|
||||
"ember-qunit": "^6.2.0",
|
||||
"ember-resolver": "^10.0.0",
|
||||
"ember-source": "~4.12.0",
|
||||
"ember-source-channel-url": "^3.0.0",
|
||||
"ember-template-lint": "^5.7.2",
|
||||
"ember-template-lint-plugin-prettier": "^5.0.0",
|
||||
"eslint": "^8.37.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-ember": "^11.5.0",
|
||||
"eslint-plugin-n": "^15.7.0",
|
||||
"eslint-plugin-qunit": "^7.3.4",
|
||||
"js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1",
|
||||
"loader.js": "^4.7.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.7.1",
|
||||
"qunit": "^2.19.1",
|
||||
"prettier": "^3.0.0",
|
||||
"qunit": "^2.19.4",
|
||||
"qunit-dom": "^2.0.0",
|
||||
"rose": "*",
|
||||
"webpack": "^5.76.0"
|
||||
"webpack": "^5.78.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ember-source": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "16.* || 18.*"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"packages": [
|
||||
{
|
||||
"name": "ember-cli",
|
||||
"version": "4.4.1",
|
||||
"version": "4.12.2",
|
||||
"blueprints": [
|
||||
{
|
||||
"name": "addon",
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const getChannelURL = require('ember-source-channel-url');
|
||||
const { embroiderSafe, embroiderOptimized } = require('@embroider/test-setup');
|
||||
|
||||
module.exports = async function () {
|
||||
return {
|
||||
scenarios: [
|
||||
{
|
||||
name: 'ember-lts-4.4',
|
||||
npm: {
|
||||
devDependencies: {
|
||||
'ember-source': '~4.4.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ember-lts-4.8',
|
||||
npm: {
|
||||
devDependencies: {
|
||||
'ember-source': '~4.8.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ember-release',
|
||||
npm: {
|
||||
devDependencies: {
|
||||
'ember-source': await getChannelURL('release'),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ember-beta',
|
||||
npm: {
|
||||
devDependencies: {
|
||||
'ember-source': await getChannelURL('beta'),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ember-canary',
|
||||
npm: {
|
||||
devDependencies: {
|
||||
'ember-source': await getChannelURL('canary'),
|
||||
},
|
||||
},
|
||||
},
|
||||
embroiderSafe(),
|
||||
embroiderOptimized(),
|
||||
],
|
||||
};
|
||||
};
|
||||
@@ -6,20 +6,17 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (environment) {
|
||||
let ENV = {
|
||||
const ENV = {
|
||||
modulePrefix: 'dummy',
|
||||
environment,
|
||||
rootURL: '/',
|
||||
locationType: 'history',
|
||||
EmberENV: {
|
||||
EXTEND_PROTOTYPES: false,
|
||||
FEATURES: {
|
||||
// Here you can enable experimental features on an ember canary build
|
||||
// e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true
|
||||
},
|
||||
EXTEND_PROTOTYPES: {
|
||||
// Prevent Ember Data from overriding Date.parse.
|
||||
Date: false,
|
||||
},
|
||||
},
|
||||
|
||||
APP: {
|
||||
|
||||
@@ -13,7 +13,7 @@ module('Integration | Component | doc-link', function (hooks) {
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
assert.expect(1);
|
||||
await render(hbs`<DocLink @doc="account" @iconSize="large" />`);
|
||||
await render(hbs`<DocLink @doc='account' @iconSize='large' />`);
|
||||
assert.ok(find('.doc-link .rose-icon.large'));
|
||||
});
|
||||
});
|
||||
@@ -29,15 +29,16 @@ module('Integration | Component | form | authenticate', function (hooks) {
|
||||
this.submit = () => {};
|
||||
this.disabled = () => {};
|
||||
|
||||
await render(hbs`<Form::Authenticate
|
||||
@model={{this.model}}
|
||||
@submit={{this.submit}}
|
||||
@disabled={{this.disabled}}/>`);
|
||||
await render(hbs`<Form::Authenticate
|
||||
@model={{this.model}}
|
||||
@onSubmit={{this.submit}}
|
||||
@disabled={{this.disabled}}
|
||||
/>`);
|
||||
assert.ok(find('.full-width'));
|
||||
assert.ok(find('.hds-form-text-input'));
|
||||
assert.strictEqual(
|
||||
find('button[type="submit"]').textContent.trim(),
|
||||
'Sign In'
|
||||
'Sign In',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -52,15 +53,16 @@ module('Integration | Component | form | authenticate', function (hooks) {
|
||||
this.submit = () => {};
|
||||
this.disabled = () => {};
|
||||
|
||||
await render(hbs`<Form::Authenticate
|
||||
@model={{this.model}}
|
||||
@submit={{this.submit}}
|
||||
@disabled={{this.disabled}}/>`);
|
||||
await render(hbs`<Form::Authenticate
|
||||
@model={{this.model}}
|
||||
@onSubmit={{this.submit}}
|
||||
@disabled={{this.disabled}}
|
||||
/>`);
|
||||
assert.ok(find('.full-width'));
|
||||
assert.ok(find('.hds-form-text-input'));
|
||||
assert.strictEqual(
|
||||
find('button[type="submit"]').textContent.trim(),
|
||||
'Sign In'
|
||||
'Sign In',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -75,15 +77,16 @@ module('Integration | Component | form | authenticate', function (hooks) {
|
||||
this.submit = () => {};
|
||||
this.disabled = () => {};
|
||||
|
||||
await render(hbs`<Form::Authenticate
|
||||
@model={{this.model}}
|
||||
@submit={{this.submit}}
|
||||
@disabled={{this.disabled}}/>`);
|
||||
await render(hbs`<Form::Authenticate
|
||||
@model={{this.model}}
|
||||
@onSubmit={{this.submit}}
|
||||
@disabled={{this.disabled}}
|
||||
/>`);
|
||||
assert.ok(find('.full-width'));
|
||||
assert.notOk(find('.hds-form-text-input'));
|
||||
assert.strictEqual(
|
||||
find('button[type="submit"]').textContent.trim(),
|
||||
'Sign In'
|
||||
'Sign In',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -13,7 +13,7 @@ module('Integration | Component | Image', function (hooks) {
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
assert.expect(1);
|
||||
await render(hbs`<Image @name="logo-app" />`);
|
||||
await render(hbs`<Image @name='logo-app' />`);
|
||||
assert.ok(find('.image-container'));
|
||||
});
|
||||
});
|
||||
@@ -18,7 +18,7 @@ module('Integration | Component | loading-button', function (hooks) {
|
||||
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}}/>`);
|
||||
await render(hbs`<LoadingButton @onClick={{this.onClick}} />`);
|
||||
assert.ok(find('.loading-button'));
|
||||
await click('button');
|
||||
});
|
||||
|
||||
@@ -15,26 +15,21 @@ module('Integration | Component | pending-confirmations', function (hooks) {
|
||||
assert.expect(2);
|
||||
const service = this.owner.lookup('service:confirm');
|
||||
service.enabled = true;
|
||||
await render(hbs`
|
||||
<PendingConfirmations as |confirmations|>
|
||||
<div class="pending">Pending</div>
|
||||
</PendingConfirmations>
|
||||
`);
|
||||
await render(hbs`<PendingConfirmations as |confirmation|>
|
||||
<div class='pending'>{{confirmation.text}}</div>
|
||||
</PendingConfirmations>`);
|
||||
assert.strictEqual(
|
||||
findAll('.pending').length,
|
||||
0,
|
||||
'No pending confirmations'
|
||||
'No pending confirmations',
|
||||
);
|
||||
service.confirm();
|
||||
await render(hbs`
|
||||
<PendingConfirmations as |confirmations|>
|
||||
<div class="pending">Pending</div>
|
||||
</PendingConfirmations>
|
||||
`);
|
||||
service.confirm('Text', { type: 'pending' });
|
||||
await render(hbs`<PendingConfirmations as |confirmation|>
|
||||
<div class='pending'>{{confirmation.text}}</div></PendingConfirmations>`);
|
||||
assert.strictEqual(
|
||||
findAll('.pending').length,
|
||||
1,
|
||||
'One pending confirmations'
|
||||
'One pending confirmations',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -44,11 +39,9 @@ module('Integration | Component | pending-confirmations', function (hooks) {
|
||||
service.enabled = true;
|
||||
const confirmation = service.confirm();
|
||||
confirmation.then(() => assert.ok(true, 'confirmation.then was called'));
|
||||
await render(hbs`
|
||||
<PendingConfirmations as |confirmations confirm|>
|
||||
<button {{on "click" confirm}}>Confirm</button>
|
||||
</PendingConfirmations>
|
||||
`);
|
||||
await render(hbs`<PendingConfirmations as |confirmations confirm|>
|
||||
<button type='button' {{on 'click' confirm}}>Confirm</button>
|
||||
</PendingConfirmations>`);
|
||||
assert.notOk(confirmation.done, 'Confirmation is not done');
|
||||
await click('button');
|
||||
assert.ok(confirmation.done, 'Confirmation is done');
|
||||
@@ -60,11 +53,9 @@ module('Integration | Component | pending-confirmations', function (hooks) {
|
||||
service.enabled = true;
|
||||
const confirmation = service.confirm();
|
||||
confirmation.catch(() => assert.ok(true, 'confirmation.catch was called'));
|
||||
await render(hbs`
|
||||
<PendingConfirmations as |confirmations confirm dismiss|>
|
||||
<button {{on "click" dismiss}}>Dismiss</button>
|
||||
</PendingConfirmations>
|
||||
`);
|
||||
await render(hbs`<PendingConfirmations as |confirmations confirm dismiss|>
|
||||
<button type='button' {{on 'click' dismiss}}>Dismiss</button>
|
||||
</PendingConfirmations>`);
|
||||
assert.notOk(confirmation.done, 'Confirmation is not done');
|
||||
await click('button');
|
||||
assert.ok(confirmation.done, 'Confirmation is done');
|
||||
|
||||
@@ -24,7 +24,7 @@ module('Integration | Component | session-status', function (hooks) {
|
||||
assert.expect(3);
|
||||
const store = this.owner.lookup('service:store');
|
||||
this.model = store.createRecord('session', { status: 'canceling' });
|
||||
await render(hbs`<SessionStatus @model={{this.model}}/>`);
|
||||
await render(hbs`<SessionStatus @model={{this.model}} />`);
|
||||
assert.ok(find('.flight-icon-alert-triangle'));
|
||||
assert.ok(find('.hds-badge--color-warning'));
|
||||
assert.ok(find('.hds-badge--type-filled'));
|
||||
@@ -34,7 +34,7 @@ module('Integration | Component | session-status', function (hooks) {
|
||||
assert.expect(3);
|
||||
const store = this.owner.lookup('service:store');
|
||||
this.model = store.createRecord('session', { status: 'terminated' });
|
||||
await render(hbs`<SessionStatus @model={{this.model}}/>`);
|
||||
await render(hbs`<SessionStatus @model={{this.model}} />`);
|
||||
assert.ok(find('.flight-icon-x'));
|
||||
assert.ok(find('.hds-badge--color-critical'));
|
||||
assert.ok(find('.hds-badge--type-filled'));
|
||||
@@ -44,7 +44,7 @@ module('Integration | Component | session-status', function (hooks) {
|
||||
assert.expect(3);
|
||||
const store = this.owner.lookup('service:store');
|
||||
this.model = store.createRecord('session', { status: 'pending' });
|
||||
await render(hbs`<SessionStatus @model={{this.model}}/>`);
|
||||
await render(hbs`<SessionStatus @model={{this.model}} />`);
|
||||
assert.ok(find('.flight-icon-delay'));
|
||||
assert.ok(find('.hds-badge--color-neutral'));
|
||||
assert.ok(find('.hds-badge--type-filled'));
|
||||
@@ -54,7 +54,7 @@ module('Integration | Component | session-status', function (hooks) {
|
||||
assert.expect(3);
|
||||
const store = this.owner.lookup('service:store');
|
||||
this.model = store.createRecord('session', { status: 'any string' });
|
||||
await render(hbs`<SessionStatus @model={{this.model}}/>`);
|
||||
await render(hbs`<SessionStatus @model={{this.model}} />`);
|
||||
assert.notOk(find('.flight-icon'));
|
||||
assert.ok(find('.hds-badge--color-neutral'));
|
||||
assert.ok(find('.hds-badge--type-outlined'));
|
||||
|
||||
@@ -14,7 +14,7 @@ module('Integration | Helper | format-date-iso-human', function (hooks) {
|
||||
test('it renders', async function (assert) {
|
||||
this.set('inputValue', new Date('2020-01-01T00:00:00.999Z'));
|
||||
|
||||
await render(hbs`{{format-date-iso-human this.inputValue }}`);
|
||||
await render(hbs`{{format-date-iso-human this.inputValue}}`);
|
||||
|
||||
assert.strictEqual(this.element.textContent.trim(), '2020-01-01 00:00:00');
|
||||
});
|
||||
@@ -22,7 +22,7 @@ module('Integration | Helper | format-date-iso-human', function (hooks) {
|
||||
test('it renders when null', async function (assert) {
|
||||
this.set('inputValue', null);
|
||||
|
||||
await render(hbs`{{format-date-iso-human this.inputValue }}`);
|
||||
await render(hbs`{{format-date-iso-human this.inputValue}}`);
|
||||
|
||||
assert.strictEqual(this.element.textContent.trim(), '');
|
||||
});
|
||||
|
||||
@@ -17,26 +17,26 @@ module('Integration | Helper | reverse-indexed-display-name', function (hooks) {
|
||||
this.set('array', ['Boundary', 'is', 'cool!']);
|
||||
|
||||
await render(hbs`{{reverse-indexed-display-name
|
||||
'resources.session-recording.connection.title_index'
|
||||
this.array
|
||||
'Boundary'
|
||||
}}`);
|
||||
'resources.session-recording.connection.title_index'
|
||||
this.array
|
||||
'Boundary'
|
||||
}}`);
|
||||
|
||||
assert.dom(this.element).hasText('Connection 3');
|
||||
|
||||
await render(hbs`{{reverse-indexed-display-name
|
||||
'resources.session-recording.connection.title_index'
|
||||
this.array
|
||||
'is'
|
||||
}}`);
|
||||
'resources.session-recording.connection.title_index'
|
||||
this.array
|
||||
'is'
|
||||
}}`);
|
||||
|
||||
assert.dom(this.element).hasText('Connection 2');
|
||||
|
||||
await render(hbs`{{reverse-indexed-display-name
|
||||
'resources.session-recording.connection.title_index'
|
||||
this.array
|
||||
'cool!'
|
||||
}}`);
|
||||
'resources.session-recording.connection.title_index'
|
||||
this.array
|
||||
'cool!'
|
||||
}}`);
|
||||
|
||||
assert.dom(this.element).hasText('Connection 1');
|
||||
});
|
||||
@@ -45,10 +45,10 @@ module('Integration | Helper | reverse-indexed-display-name', function (hooks) {
|
||||
this.set('array', ['Boundary', 'is', 'cool!']);
|
||||
|
||||
await render(hbs`{{reverse-indexed-display-name
|
||||
'resources.session-recording.connection.title_index'
|
||||
this.array
|
||||
'Watchtower'
|
||||
}}`);
|
||||
'resources.session-recording.connection.title_index'
|
||||
this.array
|
||||
'Watchtower'
|
||||
}}`);
|
||||
|
||||
assert.dom(this.element).hasText('Connection');
|
||||
});
|
||||
|
||||
@@ -93,7 +93,7 @@ disable_discovered_config_validation:
|
||||
If the Authorization Server's discovered configuration contains values that do not match the configuration set on this auth method, this can be set to force the local configuration to override the discovered values. This is useful in the case of slow-changing or incorrect values announced by the Authorization Server. NOTE: For safety, not providing this value will be treated the same as "false"; that is, every time the method is updated or the state is changed, this value must be set to "true" or it will be disabled.
|
||||
idp_ca_certs:
|
||||
label: Certificates
|
||||
help: Optional PEM-encoded X.509 CA certificates that can be used as trust anchors when connecting to an OIDC provider.
|
||||
help: PEM-encoded X.509 CA certificates that can be used as trust anchors when connecting to an OIDC provider.
|
||||
certificate:
|
||||
label: Certificate
|
||||
allowed_audiences:
|
||||
@@ -103,7 +103,7 @@ claim:
|
||||
label: Claim
|
||||
claims_scopes:
|
||||
label: Claims Scopes
|
||||
help: Optional claims scopes that will be requested during authentication.
|
||||
help: Claims scopes that will be requested during authentication.
|
||||
claims_scope:
|
||||
label: Claims Scope
|
||||
account_claim_maps:
|
||||
|
||||
@@ -233,7 +233,7 @@ host-set:
|
||||
help: Create a filter to select resources using values such as tag name or tag value. The Azure filter format is:tagName eq ‘<tag-name>’ and tagValue eq ‘<tag-value>'. For example:tagName eq 'application' and tagValue eq 'production'
|
||||
preferred_endpoints:
|
||||
label: Preferred Endpoints
|
||||
help: Optional. Preferred address at which the host should be accessed when multiple options are present, in cidr:<valid IPv4/6 CIDR> or dns:<globbed name> format.
|
||||
help: Preferred address at which the host should be accessed when multiple options are present, in cidr:<valid IPv4/6 CIDR> or dns:<globbed name> format.
|
||||
messages:
|
||||
welcome:
|
||||
title: Welcome to Host Sets
|
||||
@@ -551,9 +551,6 @@ target:
|
||||
connect-more-info:
|
||||
title: Connect for more info
|
||||
description: Additional information for this target will be provided here after your session is established.
|
||||
cannot-connect:
|
||||
title: Cannot connect to {targetDisplayName}
|
||||
description: There are no host sources and no address configured for this target.
|
||||
titles:
|
||||
new: New Target
|
||||
actions:
|
||||
@@ -828,6 +825,8 @@ scope:
|
||||
managed-group:
|
||||
title: Managed Group
|
||||
title_plural: Managed Groups
|
||||
titles:
|
||||
new: New Managed Group
|
||||
description: A managed group represents a collection of accounts.
|
||||
actions:
|
||||
delete: Delete Managed Group
|
||||
@@ -848,8 +847,9 @@ managed-group:
|
||||
help: The list of groups that this Managed Group belongs to.
|
||||
worker:
|
||||
title: Worker
|
||||
title_pki: New PKI Worker
|
||||
title_plural: Workers
|
||||
titles:
|
||||
new: New PKI Worker
|
||||
description: Workers are the server components that perform the session handling.
|
||||
actions:
|
||||
register: Register Worker
|
||||
|
||||
Vendored
Whitespace-only changes.
@@ -8,8 +8,8 @@
|
||||
"disableAnalytics": false,
|
||||
|
||||
/**
|
||||
Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript
|
||||
rather than JavaScript by default, when a TypeScript version of a given blueprint is available.
|
||||
Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript
|
||||
rather than JavaScript by default, when a TypeScript version of a given blueprint is available.
|
||||
*/
|
||||
"isTypeScriptProject": false
|
||||
}
|
||||
@@ -9,12 +9,14 @@ module.exports = {
|
||||
root: true,
|
||||
parser: '@babel/eslint-parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
ecmaVersion: 'latest',
|
||||
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 }]],
|
||||
plugins: [
|
||||
['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }],
|
||||
],
|
||||
},
|
||||
// end of babel-config
|
||||
},
|
||||
@@ -60,8 +62,7 @@ module.exports = {
|
||||
browser: false,
|
||||
node: true,
|
||||
},
|
||||
plugins: ['node'],
|
||||
extends: ['plugin:node/recommended'],
|
||||
extends: ['plugin:n/recommended'],
|
||||
},
|
||||
{
|
||||
// Test files:
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
/.gitignore
|
||||
/.prettierignore
|
||||
/.prettierrc.js
|
||||
/.stylelintignore
|
||||
/.stylelintrc.js
|
||||
/.template-lintrc.js
|
||||
/.travis.yml
|
||||
/.watchmanconfig
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# unconventional files
|
||||
/blueprints/*/files/
|
||||
|
||||
# compiled output
|
||||
/dist/
|
||||
|
||||
# addons
|
||||
/.node_modules.ember-try/
|
||||
@@ -31,5 +31,11 @@ module.exports = {
|
||||
'no-passed-in-event-handlers': false,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: '**/tests/**/*.{js,gts,gjs}',
|
||||
rules: {
|
||||
prettier: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<button
|
||||
...attributes
|
||||
type={{if @submit 'submit' 'button'}}
|
||||
type={{if @onSubmit 'submit' 'button'}}
|
||||
disabled={{if @disabled 'disabled'}}
|
||||
class='{{if @style (concat "rose-button-" @style)}}
|
||||
{{if @iconLeft "has-icon-left"}}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<button
|
||||
...attributes
|
||||
type={{if @submit 'submit' 'button'}}
|
||||
type={{if @onSubmit 'submit' 'button'}}
|
||||
disabled={{if @disabled 'disabled'}}
|
||||
class='rose-dropdown-button
|
||||
{{if @style (concat "rose-dropdown-button-" @style)}}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
.rose-layout-body-content {
|
||||
display: grid;
|
||||
grid-template-areas: 'body body sidebar';
|
||||
grid-template-columns: 1fr 1fr 300px;
|
||||
grid-template-columns: 1fr 1fr fit-content(300px);
|
||||
grid-template-rows: auto 1fr;
|
||||
gap: 2rem;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
|
||||
const { maybeEmbroider } = require('@embroider/test-setup');
|
||||
|
||||
module.exports = function (defaults) {
|
||||
let app = new EmberAddon(defaults, {
|
||||
const app = new EmberAddon(defaults, {
|
||||
// Add options here
|
||||
});
|
||||
|
||||
|
||||
+19
-14
@@ -10,15 +10,15 @@
|
||||
"scripts": {
|
||||
"build:development": "ember build",
|
||||
"build": "ember build --environment=production && cp metadata.json dist/metadata.json",
|
||||
"lint": "npm-run-all --aggregate-output --continue-on-error --parallel \"lint:!(fix)\"",
|
||||
"lint:fix": "npm-run-all --aggregate-output --continue-on-error --parallel lint:*:fix",
|
||||
"lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
|
||||
"lint:fix": "concurrently \"npm:lint:*:fix\" --names \"fix:\"",
|
||||
"lint:hbs": "ember-template-lint .",
|
||||
"lint:hbs:fix": "ember-template-lint . --fix",
|
||||
"lint:js": "eslint .",
|
||||
"lint:js:fix": "eslint . --fix",
|
||||
"lint:sass": "stylelint 'app/styles/**/*.scss'",
|
||||
"lint:sass:fix": "stylelint 'app/styles/**/*.scss' --fix",
|
||||
"format": "npm-run-all format:*",
|
||||
"format": "concurrently \"npm:format:*\" --names \"format:\"",
|
||||
"format:hbs": "prettier --write '{addon,tests}/**/*.hbs'",
|
||||
"format:js": "prettier --write '{addon,app,config,stories,tests}/**/*.js' *.js",
|
||||
"format:mdx": "prettier --write 'addon/**/*.mdx'",
|
||||
@@ -31,10 +31,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@embroider/test-setup": "^2.1.1",
|
||||
"@hashicorp/design-system-components": "^2.11.0",
|
||||
"@hashicorp/design-system-components": "^3.0.2",
|
||||
"codemirror": "5.65.7",
|
||||
"ember-auto-import": "^2.6.3",
|
||||
"ember-cli-babel": "^7.26.10",
|
||||
"ember-cli-babel": "^7.26.11",
|
||||
"ember-cli-clipboard": "^1.0.0",
|
||||
"ember-cli-htmlbars": "^6.2.0",
|
||||
"ember-cli-sass": "^11.0.1",
|
||||
@@ -48,9 +48,10 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.18.5",
|
||||
"@babel/eslint-parser": "^7.18.2",
|
||||
"@babel/plugin-proposal-decorators": "^7.18.6",
|
||||
"@babel/eslint-parser": "^7.21.3",
|
||||
"@babel/plugin-proposal-decorators": "^7.21.0",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/string": "^3.0.1",
|
||||
"@ember/test-helpers": "^2.9.3",
|
||||
"@glimmer/component": "^1.1.2",
|
||||
"@glimmer/tracking": "^1.1.2",
|
||||
@@ -58,8 +59,9 @@
|
||||
"babel-plugin-ember-modules-api-polyfill": "^2.12.0",
|
||||
"babel-plugin-htmlbars-inline-precompile": "3",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"concurrently": "^8.0.1",
|
||||
"doctoc": "^2.2.0",
|
||||
"ember-cli": "^4.12.1",
|
||||
"ember-cli": "^4.12.2",
|
||||
"ember-cli-dependency-checker": "^3.3.1",
|
||||
"ember-cli-inject-live-reload": "^2.1.0",
|
||||
"ember-cli-sri": "^2.1.1",
|
||||
@@ -72,21 +74,21 @@
|
||||
"ember-maybe-import-regenerator": "^1.0.0",
|
||||
"ember-modifier": "^3.2.7",
|
||||
"ember-page-title": "^7.0.0",
|
||||
"ember-qunit": "^6.0.0",
|
||||
"ember-qunit": "^6.2.0",
|
||||
"ember-resolver": "^10.0.0",
|
||||
"ember-source": "~4.12.0",
|
||||
"ember-template-lint": "^4.14.0",
|
||||
"ember-template-lint-plugin-prettier": "^4.0.0",
|
||||
"ember-source-channel-url": "^3.0.0",
|
||||
"ember-template-lint": "^5.7.2",
|
||||
"ember-template-lint-plugin-prettier": "^5.0.0",
|
||||
"eslint": "^8.37.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-ember": "^11.5.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-n": "^15.7.0",
|
||||
"eslint-plugin-qunit": "^7.3.4",
|
||||
"jest": "^27.4.7",
|
||||
"loader.js": "^4.7.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^8.4.31",
|
||||
"prettier": "^2.7.1",
|
||||
"prettier": "^3.0.0",
|
||||
"qunit": "^2.19.4",
|
||||
"qunit-dom": "^2.0.0",
|
||||
"react": "^16",
|
||||
@@ -97,6 +99,9 @@
|
||||
"stylelint-config-standard-scss": "^6.0.0",
|
||||
"webpack": "^5.78.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ember-source": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "16.* || 18.*"
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"packages": [
|
||||
{
|
||||
"name": "ember-cli",
|
||||
"version": "4.4.1",
|
||||
"version": "4.12.2",
|
||||
"blueprints": [
|
||||
{
|
||||
"name": "addon",
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const getChannelURL = require('ember-source-channel-url');
|
||||
const { embroiderSafe, embroiderOptimized } = require('@embroider/test-setup');
|
||||
|
||||
module.exports = async function () {
|
||||
return {
|
||||
scenarios: [
|
||||
{
|
||||
name: 'ember-lts-4.4',
|
||||
npm: {
|
||||
devDependencies: {
|
||||
'ember-source': '~4.4.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ember-lts-4.8',
|
||||
npm: {
|
||||
devDependencies: {
|
||||
'ember-source': '~4.8.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ember-release',
|
||||
npm: {
|
||||
devDependencies: {
|
||||
'ember-source': await getChannelURL('release'),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ember-beta',
|
||||
npm: {
|
||||
devDependencies: {
|
||||
'ember-source': await getChannelURL('beta'),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ember-canary',
|
||||
npm: {
|
||||
devDependencies: {
|
||||
'ember-source': await getChannelURL('canary'),
|
||||
},
|
||||
},
|
||||
},
|
||||
embroiderSafe(),
|
||||
embroiderOptimized(),
|
||||
],
|
||||
};
|
||||
};
|
||||
@@ -6,20 +6,17 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (environment) {
|
||||
let ENV = {
|
||||
const ENV = {
|
||||
modulePrefix: 'dummy',
|
||||
environment,
|
||||
rootURL: '/',
|
||||
locationType: 'auto',
|
||||
EmberENV: {
|
||||
EXTEND_PROTOTYPES: false,
|
||||
FEATURES: {
|
||||
// Here you can enable experimental features on an ember canary build
|
||||
// e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true
|
||||
},
|
||||
EXTEND_PROTOTYPES: {
|
||||
// Prevent Ember Data from overriding Date.parse.
|
||||
Date: false,
|
||||
},
|
||||
},
|
||||
|
||||
APP: {
|
||||
|
||||
@@ -13,9 +13,9 @@ module('Integration | Component | rose/anonymous', function (hooks) {
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
await render(hbs`
|
||||
{{#rose/anonymous tagName='main'}}
|
||||
<Rose::Anonymous @tagName="main">
|
||||
template block text
|
||||
{{/rose/anonymous}}
|
||||
</Rose::Anonymous>
|
||||
`);
|
||||
assert.ok(find('main'));
|
||||
assert.strictEqual(this.element.textContent.trim(), 'template block text');
|
||||
|
||||
@@ -21,8 +21,8 @@ module('Integration | Component | rose/button', function (hooks) {
|
||||
assert.strictEqual(find('button').type, 'button');
|
||||
});
|
||||
|
||||
test('it is type="submit" when @submit={{true}}', async function (assert) {
|
||||
await render(hbs`<Rose::Button @submit={{true}} />`);
|
||||
test('it is type="submit" when @onSubmit={{true}}', async function (assert) {
|
||||
await render(hbs`<Rose::Button @onSubmit={{true}} />`);
|
||||
assert.strictEqual(find('button').type, 'submit');
|
||||
});
|
||||
|
||||
@@ -40,18 +40,18 @@ module('Integration | Component | rose/button', function (hooks) {
|
||||
|
||||
test('it supports left and right icons', async function (assert) {
|
||||
await render(
|
||||
hbs`<Rose::Button @iconLeft="flight-icons/svg/chevron-left-16" />`
|
||||
hbs`<Rose::Button @iconLeft="flight-icons/svg/chevron-left-16" />`,
|
||||
);
|
||||
assert.ok(find('.has-icon-left .rose-icon'));
|
||||
await render(
|
||||
hbs`<Rose::Button @iconRight="flight-icons/svg/chevron-left-16" />`
|
||||
hbs`<Rose::Button @iconRight="flight-icons/svg/chevron-left-16" />`,
|
||||
);
|
||||
assert.ok(find('.has-icon-right .rose-icon'));
|
||||
});
|
||||
|
||||
test('it supports an icon-only type', async function (assert) {
|
||||
await render(
|
||||
hbs`<Rose::Button @iconOnly="flight-icons/svg/chevron-left-16" />`
|
||||
hbs`<Rose::Button @iconOnly="flight-icons/svg/chevron-left-16" />`,
|
||||
);
|
||||
assert.ok(find('.has-icon-only .rose-icon'));
|
||||
});
|
||||
|
||||
@@ -25,7 +25,7 @@ module('Integration | Component | rose/card/link', function (hooks) {
|
||||
assert.strictEqual(find('a').title, 'card title');
|
||||
assert.strictEqual(
|
||||
find('.rose-card-link-title').textContent.trim(),
|
||||
'card title'
|
||||
'card title',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -33,7 +33,7 @@ module('Integration | Component | rose/card/link', function (hooks) {
|
||||
await render(hbs`<Rose::Card::Link @description="card description" />`);
|
||||
assert.strictEqual(
|
||||
find('.rose-card-link-body').textContent.trim(),
|
||||
'card description'
|
||||
'card description',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -41,13 +41,13 @@ module('Integration | Component | rose/card/link', function (hooks) {
|
||||
await render(hbs`<Rose::Card::Link @id="card_id" />`);
|
||||
assert.strictEqual(
|
||||
find('.rose-card-link-footer-id').textContent.trim(),
|
||||
'card_id'
|
||||
'card_id',
|
||||
);
|
||||
});
|
||||
|
||||
test('it renders with @icon', async function (assert) {
|
||||
await render(
|
||||
hbs`<Rose::Card::Link @title="foo" @icon="flight-icons/svg/alert-circle-16" />`
|
||||
hbs`<Rose::Card::Link @title="foo" @icon="flight-icons/svg/alert-circle-16" />`,
|
||||
);
|
||||
assert.ok(find('.rose-icon'));
|
||||
});
|
||||
@@ -59,7 +59,7 @@ module('Integration | Component | rose/card/link', function (hooks) {
|
||||
|
||||
test('it renders with content', async function (assert) {
|
||||
await render(hbs`<Rose::Card::Link>
|
||||
<button/>
|
||||
<button type="button" />
|
||||
</Rose::Card::Link>`);
|
||||
assert.ok(find('button'));
|
||||
});
|
||||
|
||||
@@ -21,8 +21,8 @@ module('Integration | Component | rose/dropdown/button', function (hooks) {
|
||||
assert.strictEqual(find('button').type, 'button');
|
||||
});
|
||||
|
||||
test('it is type="submit" when @submit={{true}}', async function (assert) {
|
||||
await render(hbs`<Rose::Dropdown::Button @submit={{true}} />`);
|
||||
test('it is type="submit" when @onSubmit={{true}}', async function (assert) {
|
||||
await render(hbs`<Rose::Dropdown::Button @onSubmit={{true}} />`);
|
||||
assert.strictEqual(find('button').type, 'submit');
|
||||
});
|
||||
|
||||
@@ -38,7 +38,7 @@ module('Integration | Component | rose/dropdown/button', function (hooks) {
|
||||
|
||||
test('it supports an icon-only type', async function (assert) {
|
||||
await render(
|
||||
hbs`<Rose::Dropdown::Button @iconOnly="flight-icons/svg/chevron-left-16" />`
|
||||
hbs`<Rose::Dropdown::Button @iconOnly="flight-icons/svg/chevron-left-16" />`,
|
||||
);
|
||||
assert.ok(find('.has-icon-only .rose-icon'));
|
||||
});
|
||||
|
||||
@@ -15,7 +15,13 @@ module('Integration | Component | rose/form/actions', function (hooks) {
|
||||
assert.expect(2);
|
||||
this.cancel = () => {};
|
||||
await render(
|
||||
hbs`{{rose/form/actions cancel=this.cancel submitText='Save' cancelText='Cancel'}}`
|
||||
hbs`
|
||||
<Rose::Form::Actions
|
||||
@cancel={{this.cancel}}
|
||||
@submitText='Save'
|
||||
@cancelText='Cancel'
|
||||
/>
|
||||
`,
|
||||
);
|
||||
assert.ok(find('[type="submit"]'));
|
||||
assert.ok(find('button:not([type="submit"])'));
|
||||
@@ -25,7 +31,15 @@ module('Integration | Component | rose/form/actions', function (hooks) {
|
||||
assert.expect(2);
|
||||
this.cancel = () => {};
|
||||
await render(
|
||||
hbs`{{rose/form/actions cancel=this.cancel submitDisabled=true cancelDisabled=true submitText='Save' cancelText='Cancel'}}`
|
||||
hbs`
|
||||
<Rose::Form::Actions
|
||||
@cancel={{this.cancel}}
|
||||
@submitText='Save'
|
||||
@cancelText='Cancel'
|
||||
@submitDisabled={{true}}
|
||||
@cancelDisabled={{true}}
|
||||
/>
|
||||
`,
|
||||
);
|
||||
assert.ok(find('[type="submit"]:disabled'));
|
||||
assert.ok(find('button:not([type="submit"]):disabled'));
|
||||
@@ -33,7 +47,9 @@ module('Integration | Component | rose/form/actions', function (hooks) {
|
||||
|
||||
test('it optionally does not render the cancel button', async function (assert) {
|
||||
assert.expect(2);
|
||||
await render(hbs`{{rose/form/actions submitText='Save' showCancel=false}}`);
|
||||
await render(hbs`
|
||||
<Rose::Form::Actions @submitText='Save' @showCancel={{false}} />
|
||||
`);
|
||||
assert.ok(find('[type="submit"]'));
|
||||
assert.notOk(find('button:not([type="submit"])'));
|
||||
});
|
||||
@@ -42,7 +58,13 @@ module('Integration | Component | rose/form/actions', function (hooks) {
|
||||
assert.expect(1);
|
||||
this.cancel = () => assert.ok(true, 'cancel was clicked');
|
||||
await render(
|
||||
hbs`{{rose/form/actions cancel=this.cancel submitText='Save' cancelText='Cancel'}}`
|
||||
hbs`
|
||||
<Rose::Form::Actions
|
||||
@cancel={{this.cancel}}
|
||||
@submitText='Save'
|
||||
@cancelText='Cancel'
|
||||
/>
|
||||
`,
|
||||
);
|
||||
await click('button:not([type="submit"])');
|
||||
});
|
||||
|
||||
@@ -17,7 +17,12 @@ module(
|
||||
assert.expect(1);
|
||||
this.enableEdit = () => {};
|
||||
await render(
|
||||
hbs`{{rose/form/actions/edit-toggle enableEdit=this.enableEdit enableEditText='Edit'}}`
|
||||
hbs`
|
||||
<Rose::Form::Actions::EditToggle
|
||||
@enableEdit={{this.enableEdit}}
|
||||
@enableEditText='Edit'
|
||||
/>
|
||||
`,
|
||||
);
|
||||
assert.ok(find('button'));
|
||||
});
|
||||
@@ -26,9 +31,14 @@ module(
|
||||
assert.expect(1);
|
||||
this.enableEdit = () => assert.ok(true, 'edit was clicked');
|
||||
await render(
|
||||
hbs`{{rose/form/actions/edit-toggle enableEdit=this.enableEdit enableEditText='Edit'}}`
|
||||
hbs`
|
||||
<Rose::Form::Actions::EditToggle
|
||||
@enableEdit={{this.enableEdit}}
|
||||
@enableEditText='Edit'
|
||||
/>
|
||||
`,
|
||||
);
|
||||
await click('button');
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -26,7 +26,7 @@ module('Integration | Component | rose/layout/body-content', function (hooks) {
|
||||
|
||||
test('it renders with content', async function (assert) {
|
||||
await render(hbs`<Rose::Layout::BodyContent as |bc|>
|
||||
<bc.Body><button id="button" /></bc.Body>
|
||||
<bc.Body><button id="button" type="button" /></bc.Body>
|
||||
<bc.Sidebar><p id="details">Resource Details</p></bc.Sidebar>
|
||||
</Rose::Layout::BodyContent>`);
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ module('Integration | Component | rose/layout/page', function (hooks) {
|
||||
|
||||
test('it renders with content', async function (assert) {
|
||||
await render(hbs`<Rose::Layout::Page>
|
||||
<button id="content" />
|
||||
<button id="content" type="button" />
|
||||
</Rose::Layout::Page>`);
|
||||
assert.ok(find('#content'));
|
||||
});
|
||||
|
||||
@@ -44,7 +44,7 @@ module('Integration | Component | rose/table/row', function (hooks) {
|
||||
|
||||
test('it can be hidden', async function (assert) {
|
||||
assert.expect(1);
|
||||
await render(hbs`<Rose::Table::Row @hidden=true />`);
|
||||
await render(hbs`<Rose::Table::Row @hidden={{true}} />`);
|
||||
assert.ok(find('.rose-table-row-visually-hidden'));
|
||||
});
|
||||
});
|
||||
@@ -50,7 +50,7 @@ module('Integration | Component | rose/table/row/cell', function (hooks) {
|
||||
test('it renders with align center in a header cell', async function (assert) {
|
||||
assert.expect(2);
|
||||
await render(
|
||||
hbs`<Rose::Table::Row::Cell @tagName='th' @alignCenter=true />`
|
||||
hbs`<Rose::Table::Row::Cell @tagName='th' @alignCenter={{true}} />`,
|
||||
);
|
||||
assert.ok(find('.rose-table-header-cell'));
|
||||
assert.ok(find('.align-center'));
|
||||
@@ -58,7 +58,7 @@ module('Integration | Component | rose/table/row/cell', function (hooks) {
|
||||
|
||||
test('it renders with align center in a body', async function (assert) {
|
||||
assert.expect(2);
|
||||
await render(hbs`<Rose::Table::Row::Cell @alignCenter=true />`);
|
||||
await render(hbs`<Rose::Table::Row::Cell @alignCenter={{true}} />`);
|
||||
assert.ok(find('.rose-table-cell'));
|
||||
assert.ok(find('.align-center'));
|
||||
});
|
||||
@@ -66,7 +66,7 @@ module('Integration | Component | rose/table/row/cell', function (hooks) {
|
||||
test('it renders with align right in a header cell', async function (assert) {
|
||||
assert.expect(2);
|
||||
await render(
|
||||
hbs`<Rose::Table::Row::Cell @tagName='th' @alignRight=true />`
|
||||
hbs`<Rose::Table::Row::Cell @tagName='th' @alignRight={{true}} />`,
|
||||
);
|
||||
assert.ok(find('.rose-table-header-cell'));
|
||||
assert.ok(find('.align-right'));
|
||||
@@ -74,7 +74,7 @@ module('Integration | Component | rose/table/row/cell', function (hooks) {
|
||||
|
||||
test('it renders with align right', async function (assert) {
|
||||
assert.expect(2);
|
||||
await render(hbs`<Rose::Table::Row::Cell @alignRight=true />`);
|
||||
await render(hbs`<Rose::Table::Row::Cell @alignRight={{true}} />`);
|
||||
assert.ok(find('.rose-table-cell'));
|
||||
assert.ok(find('.align-right'));
|
||||
});
|
||||
|
||||
@@ -25,7 +25,7 @@ module('Integration | Helper | set-from-event', function (hooks) {
|
||||
assert.expect(2);
|
||||
this.set('inputValue', '1234');
|
||||
await render(
|
||||
hbs`<button value="foobar" {{on 'click' (set-from-event this 'inputValue')}} />`
|
||||
hbs`<button value="foobar" type="button" {{on 'click' (set-from-event this 'inputValue')}} />`,
|
||||
);
|
||||
assert.deepEqual(this.inputValue, '1234');
|
||||
await click('button');
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
questions: ["type", "subject", "body", "issues"],
|
||||
};
|
||||
+4
-7
@@ -50,12 +50,6 @@
|
||||
},
|
||||
"resolutions": {
|
||||
"request": "^2.88.0",
|
||||
"ansi-html": "^0.0.8",
|
||||
"shell-quote": "^1.7.3",
|
||||
"hawk": "^9.0.1",
|
||||
"async": "^2.6.4",
|
||||
"terser": "^5.14.2",
|
||||
"jpeg-js": "^0.4.4",
|
||||
"loader-utils": "^2.0.4",
|
||||
"**/ember-electron/**/minimatch": "^3.0.5",
|
||||
"**/babel-core/json5": "^2.2.2",
|
||||
@@ -74,7 +68,10 @@
|
||||
"**/jsprim/json-schema": "^0.4.0",
|
||||
"**/ember-cli/markdown-it-terminal/markdown-it": "^12.3.2",
|
||||
"**/ember-cli-mirage/@embroider/macros": "^1.0.0",
|
||||
"**/ember-electron/**/got": "^11.8.6"
|
||||
"**/ember-electron/**/got": "^11.8.6",
|
||||
"**/ember-cli/**/ansi-html": "^0.0.9",
|
||||
"**/ember-cli/testem/fireworm/async": "^2.6.4",
|
||||
"**/desktop/@doyensec/electronegativity/winston/async": "^2.6.4"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
}}
|
||||
|
||||
<Rose::Nav::Breadcrumbs as |crumbs|>
|
||||
|
||||
{{#if this.scope.org}}
|
||||
{{#unless this.scope.org.isGlobal}}
|
||||
{{#if this.session.data.authenticated.isGlobal}}
|
||||
<crumbs.link @route='scopes.scope.scopes' @model='global'>
|
||||
{{t 'resources.org.title_plural'}}
|
||||
</crumbs.link>
|
||||
<crumbs.link @route='scopes.scope.edit' @model={{this.scope.org.id}}>
|
||||
{{this.scope.org.displayName}}
|
||||
</crumbs.link>
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
|
||||
{{#if this.scope.project}}
|
||||
<crumbs.link @route='scopes.scope.scopes' @model={{this.scope.org.id}}>
|
||||
{{t 'resources.project.title_plural'}}
|
||||
</crumbs.link>
|
||||
<crumbs.link @route='scopes.scope.edit' @model={{this.scope.project.id}}>
|
||||
{{this.scope.project.displayName}}
|
||||
</crumbs.link>
|
||||
{{/if}}
|
||||
|
||||
{{#each this.breadCrumbs as |crumb|}}
|
||||
{{#if crumb.model}}
|
||||
<crumbs.link @route={{crumb.path}} @model={{crumb.model}}>
|
||||
{{crumb.label}}
|
||||
</crumbs.link>
|
||||
{{else}}
|
||||
<crumbs.link @route={{crumb.path}}>
|
||||
{{crumb.label}}
|
||||
</crumbs.link>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
|
||||
</Rose::Nav::Breadcrumbs>
|
||||
@@ -1,118 +0,0 @@
|
||||
import Component from '@glimmer/component';
|
||||
import EmberObject, { computed, get } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { isBlank, isPresent } from '@ember/utils';
|
||||
import { A } from '@ember/array';
|
||||
|
||||
// This component copies and modifies source from ember-breadcrumbs 0.2.3,
|
||||
// updating it for Ember v4 compatibility.
|
||||
|
||||
// The original copyright is below.
|
||||
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2019 Chris Farber
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
export default class BreadcrumbsComponent extends Component {
|
||||
// =services
|
||||
|
||||
@service session;
|
||||
@service scope;
|
||||
@service router;
|
||||
|
||||
// =properties
|
||||
|
||||
/* eslint-disable-next-line ember/require-computed-property-dependencies */
|
||||
@computed('router.currentRouteName')
|
||||
get routeInfos() {
|
||||
/* eslint-disable-next-line ember/no-private-routing-service */
|
||||
return this.router._router._routerMicrolib.currentRouteInfos;
|
||||
}
|
||||
|
||||
/*
|
||||
For the pathNames and controllers properties, we must be careful not to NOT
|
||||
specify the properties of the route in our dependent keys.
|
||||
|
||||
Observing the controller property of the route causes some serious problems:
|
||||
https://github.com/chrisfarber/ember-breadcrumbs/issues/21
|
||||
*/
|
||||
|
||||
@computed('routeInfos.[]')
|
||||
get pathNames() {
|
||||
return this.routeInfos.map(function (routeInfo) {
|
||||
return routeInfo.name;
|
||||
});
|
||||
}
|
||||
|
||||
@computed('routeInfos.[]')
|
||||
get controllers() {
|
||||
return this.routeInfos.map(function (routeInfo) {
|
||||
var route = routeInfo.route || routeInfo.handler;
|
||||
return route.controller;
|
||||
});
|
||||
}
|
||||
|
||||
@computed(
|
||||
'controllers.@each.{breadCrumbs,breadCrumb,breadCrumbPath,breadCrumbModel}',
|
||||
'pathNames.[]'
|
||||
)
|
||||
get breadCrumbs() {
|
||||
var controllers = this.controllers;
|
||||
var defaultPaths = this.pathNames;
|
||||
var breadCrumbs = A([]);
|
||||
|
||||
controllers.forEach(function (controller, index) {
|
||||
var crumbs = controller.breadCrumbs || A([]);
|
||||
var singleCrumb = controller.breadCrumb;
|
||||
|
||||
if (!isBlank(singleCrumb)) {
|
||||
crumbs.push({
|
||||
label: singleCrumb,
|
||||
path: controller.breadCrumbPath,
|
||||
model: controller.breadCrumbModel,
|
||||
});
|
||||
}
|
||||
|
||||
crumbs.forEach(function (crumb) {
|
||||
breadCrumbs.addObject(
|
||||
EmberObject.create({
|
||||
label: crumb.label,
|
||||
path: crumb.path || defaultPaths[index],
|
||||
model: crumb.model,
|
||||
linkable: isPresent(crumb.linkable)
|
||||
? crumb.linkable
|
||||
: crumb.path !== false,
|
||||
isCurrent: false,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
var deepestCrumb = get(breadCrumbs, 'lastObject');
|
||||
if (deepestCrumb) {
|
||||
deepestCrumb.isCurrent = true;
|
||||
}
|
||||
|
||||
return breadCrumbs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
~}}
|
||||
|
||||
<Hds::Breadcrumb
|
||||
...attributes
|
||||
data-test-breadcrumbs-container
|
||||
{{did-insert this.registerContainer}}
|
||||
>
|
||||
{{yield}}
|
||||
</Hds::Breadcrumb>
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
/*
|
||||
The `containers` property from the `breadcrumbsService` is tracked
|
||||
so registering or unregistering a container will cause the DOM
|
||||
to re-render a container with the correct breadcrumbs.
|
||||
*/
|
||||
|
||||
export default class BreadcrumbsContainerComponent extends Component {
|
||||
@service('breadcrumbs') breadcrumbsService;
|
||||
|
||||
container = null;
|
||||
|
||||
@action
|
||||
registerContainer(element) {
|
||||
// A child `ol` is rendered in the Hds::Breadcrumb container and this is
|
||||
// the element that the in-element helper should drop breadcrumbs into.
|
||||
this.container = {
|
||||
element: element.querySelector('ol'),
|
||||
};
|
||||
|
||||
this.breadcrumbsService.registerContainer(this.container);
|
||||
}
|
||||
|
||||
willDestroy() {
|
||||
super.willDestroy(...arguments);
|
||||
|
||||
this.breadcrumbsService.unregisterContainer(this.container);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
~}}
|
||||
|
||||
{{#each this.breadcrumbsService.containers as |container|}}
|
||||
{{#in-element container.element insertBefore=null}}
|
||||
<Hds::Breadcrumb::Item
|
||||
@text={{@text}}
|
||||
@icon={{@icon}}
|
||||
@route={{@route}}
|
||||
@models={{@models}}
|
||||
@query={{@query}}
|
||||
@model={{@model}}
|
||||
@current={{this.current}}
|
||||
...attributes
|
||||
{{did-insert this.registerSelf}}
|
||||
data-test-breadcrumbs-item
|
||||
/>
|
||||
{{/in-element}}
|
||||
{{/each}}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
|
||||
/*
|
||||
`BreadcrumbsItem` inserts the crumbs to an existing container.
|
||||
For our purposes, there will always be at most one container.
|
||||
*/
|
||||
|
||||
export default class BreadcrumbsItemComponent extends Component {
|
||||
@service('breadcrumbs') breadcrumbsService;
|
||||
|
||||
@tracked element = null;
|
||||
|
||||
@action
|
||||
registerSelf(element) {
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
get current() {
|
||||
const crumbs = this.breadcrumbsService.containers[0].element.children;
|
||||
const lastCrumb = crumbs[crumbs.length - 1];
|
||||
return lastCrumb.isEqualNode(this.element);
|
||||
}
|
||||
}
|
||||
@@ -76,73 +76,37 @@
|
||||
{{/if}}
|
||||
</Hds::Form::TextInput::Field>
|
||||
|
||||
<Hds::Form::Fieldset @isOptional={{true}} as |F|>
|
||||
<F.Legend>{{t 'resources.auth-method.form.certificates.label'}}</F.Legend>
|
||||
<F.HelperText>{{t
|
||||
'resources.auth-method.form.certificates.help'
|
||||
}}</F.HelperText>
|
||||
{{#let (unique-id) as |valueHeaderID|}}
|
||||
<F.Control>
|
||||
<Hds::Table class='key-value-list' name='certificates'>
|
||||
<:head as |H|>
|
||||
<H.Tr>
|
||||
<H.Th id={{valueHeaderID}}>{{t 'titles.value'}}</H.Th>
|
||||
<H.Th>{{t 'titles.actions'}}</H.Th>
|
||||
</H.Tr>
|
||||
</:head>
|
||||
<:body as |B|>
|
||||
{{#each @model.certificates as |cert i|}}
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
<Hds::Form::Textarea::Field
|
||||
@value={{cert.value}}
|
||||
@isOptional={{true}}
|
||||
disabled={{form.disabled}}
|
||||
aria-labelledby={{valueHeaderID}}
|
||||
/>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
<Hds::Button
|
||||
@text={{t 'actions.remove'}}
|
||||
@color='critical'
|
||||
@icon='trash'
|
||||
@isIconOnly={{true}}
|
||||
disabled={{form.disabled}}
|
||||
{{on 'click' (fn @removeItemByIndex 'certificates' i)}}
|
||||
/>
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
{{/each}}
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
<Hds::Form::Textarea::Field
|
||||
@value={{this.newCertificate}}
|
||||
@isOptional={{true}}
|
||||
disabled={{form.disabled}}
|
||||
aria-labelledby={{valueHeaderID}}
|
||||
/>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
<Hds::Button
|
||||
@text={{t 'actions.add'}}
|
||||
@color='secondary'
|
||||
disabled={{or form.disabled (not this.newCertificate)}}
|
||||
{{on 'click' this.addCertificate}}
|
||||
/>
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
</:body>
|
||||
</Hds::Table>
|
||||
</F.Control>
|
||||
{{/let}}
|
||||
{{#if @model.errors.certificates}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.certificates as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</Hds::Form::Fieldset>
|
||||
<Form::Field::ListWrapper
|
||||
@layout='horizontal'
|
||||
@isOptional={{true}}
|
||||
@disabled={{form.disabled}}
|
||||
>
|
||||
<:fieldset as |F|>
|
||||
<F.Legend>
|
||||
{{t 'resources.auth-method.form.certificates.label'}}
|
||||
</F.Legend>
|
||||
<F.HelperText>
|
||||
{{t 'resources.auth-method.form.certificates.help'}}
|
||||
</F.HelperText>
|
||||
|
||||
{{#if @model.errors.certificates}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.certificates as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</:fieldset>
|
||||
|
||||
<:field as |F|>
|
||||
<F.Textarea
|
||||
@name='certificates'
|
||||
@options={{@model.certificates}}
|
||||
@model={{@model}}
|
||||
/>
|
||||
</:field>
|
||||
|
||||
</Form::Field::ListWrapper>
|
||||
|
||||
{{#if @model.isNew}}
|
||||
<Hds::Form::TextInput::Field
|
||||
@@ -152,6 +116,7 @@
|
||||
@type='password'
|
||||
name='client_certificate'
|
||||
disabled={{form.disabled}}
|
||||
@hasVisibilityToggle={{false}}
|
||||
{{on 'input' (set-from-event @model 'client_certificate')}}
|
||||
as |F|
|
||||
>
|
||||
@@ -177,6 +142,7 @@
|
||||
@type='password'
|
||||
name='client_certificate_key'
|
||||
disabled={{form.disabled}}
|
||||
@hasVisibilityToggle={{false}}
|
||||
{{on 'input' (set-from-event @model 'client_certificate_key')}}
|
||||
as |F|
|
||||
>
|
||||
@@ -277,6 +243,7 @@
|
||||
@type='password'
|
||||
name='bind_password'
|
||||
disabled={{form.disabled}}
|
||||
@hasVisibilityToggle={{false}}
|
||||
{{on 'input' (set-from-event @model 'bind_password')}}
|
||||
as |F|
|
||||
>
|
||||
@@ -424,7 +391,7 @@
|
||||
}}</F.HelperText>
|
||||
{{#let (unique-id) (unique-id) as |fromHeaderID toHeaderID|}}
|
||||
<F.Control>
|
||||
<Hds::Table class='key-value-list' name='account_attribute_maps'>
|
||||
<Hds::Table class='list-wrapper-field' name='account_attribute_maps'>
|
||||
<:head as |H|>
|
||||
<H.Tr>
|
||||
<H.Th id={{fromHeaderID}}>{{t
|
||||
|
||||
@@ -122,6 +122,7 @@
|
||||
@helperText={{t 'form.client_secret.help'}}
|
||||
@error={{@model.errors.client_secret}}
|
||||
readonly={{false}}
|
||||
@hasVisibilityToggle={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.client_secret}}
|
||||
@@ -254,176 +255,71 @@
|
||||
</Rose::Form::Fieldset>
|
||||
|
||||
{{! Allowed Audiences }}
|
||||
<Rose::Form::Fieldset>
|
||||
<:title>{{t 'form.allowed_audiences.label'}}</:title>
|
||||
<:description>{{t 'form.allowed_audiences.help'}}</:description>
|
||||
<:body>
|
||||
{{#if @model.errors.allowed_audiences}}
|
||||
<Rose::Form::Errors as |errors|>
|
||||
{{#each @model.errors.allowed_audiences as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</Rose::Form::Errors>
|
||||
{{/if}}
|
||||
<Rose::Table @style='condensed' as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row @hidden={{true}} as |row|>
|
||||
<row.headerCell>{{t 'titles.value'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'titles.actions'}}</row.headerCell>
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.allowed_audiences as |audience i|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='allowed_audiences'
|
||||
@value={{audience.value}}
|
||||
@error={{@model.errors.allowed_audiences}}
|
||||
@contextual={{true}}
|
||||
as |field|
|
||||
>
|
||||
<field.label>{{t 'form.claim.label'}}</field.label>
|
||||
<field.field />
|
||||
</form.input>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='warning'
|
||||
@iconOnly='flight-icons/svg/trash-16'
|
||||
title={{t 'actions.remove'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on 'click' (fn @removeItemByIndex 'allowed_audiences' i)}}
|
||||
>
|
||||
{{t 'actions.remove'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
<Form::Field::ListWrapper
|
||||
@layout='horizontal'
|
||||
@isOptional={{true}}
|
||||
@disabled={{form.disabled}}
|
||||
>
|
||||
<:fieldset as |F|>
|
||||
<F.Legend>
|
||||
{{t 'form.allowed_audiences.label'}}
|
||||
</F.Legend>
|
||||
<F.HelperText>
|
||||
{{t 'form.allowed_audiences.help'}}
|
||||
</F.HelperText>
|
||||
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='allowed_audiences'
|
||||
@value={{this.newAllowedAudience}}
|
||||
@label={{t 'resources.auth-method.titles.new-allowed-audience'}}
|
||||
/>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='secondary'
|
||||
title={{t 'actions.add'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on
|
||||
'click'
|
||||
(fn
|
||||
@addStringItem 'allowed_audiences' this.newAllowedAudience
|
||||
)
|
||||
}}
|
||||
>
|
||||
{{t 'actions.add'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
</:body>
|
||||
</Rose::Form::Fieldset>
|
||||
{{#if @model.errors.allowed_audiences}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.allowed_audiences as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</:fieldset>
|
||||
|
||||
<:field as |F|>
|
||||
<F.TextInput
|
||||
@name='allowed_audiences'
|
||||
@options={{@model.allowed_audiences}}
|
||||
@model={{@model}}
|
||||
/>
|
||||
</:field>
|
||||
|
||||
</Form::Field::ListWrapper>
|
||||
|
||||
{{! Claims Scopes }}
|
||||
<Rose::Form::Fieldset>
|
||||
<:title>{{t 'form.claims_scopes.label'}}</:title>
|
||||
<:description>{{t 'form.claims_scopes.help'}}</:description>
|
||||
<:body>
|
||||
{{#if @model.errors.claims_scopes}}
|
||||
<Rose::Form::Errors as |errors|>
|
||||
{{#each @model.errors.claims_scopes as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</Rose::Form::Errors>
|
||||
{{/if}}
|
||||
<Rose::Table @style='condensed' as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row @hidden={{true}} as |row|>
|
||||
<row.headerCell>{{t 'titles.value'}}</row.headerCell>
|
||||
<row.headerCell />
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.claims_scopes as |claimsScope i|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='claims_scopes'
|
||||
@value={{claimsScope.value}}
|
||||
@error={{@model.errors.claims_scopes}}
|
||||
@contextual={{true}}
|
||||
as |field|
|
||||
>
|
||||
<field.label>{{t 'form.claims_scope.label'}}</field.label>
|
||||
<field.field />
|
||||
</form.input>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='warning'
|
||||
@iconOnly='flight-icons/svg/trash-16'
|
||||
title={{t 'actions.remove'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on 'click' (fn @removeItemByIndex 'claims_scopes' i)}}
|
||||
>
|
||||
{{t 'actions.remove'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='claims_scopes'
|
||||
@value={{this.newClaimsScope}}
|
||||
@label={{t 'resources.auth-method.titles.new-claims-scope'}}
|
||||
/>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='secondary'
|
||||
title={{t 'actions.add'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on
|
||||
'click'
|
||||
(fn @addStringItem 'claims_scopes' this.newClaimsScope)
|
||||
}}
|
||||
>
|
||||
{{t 'actions.add'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
</:body>
|
||||
</Rose::Form::Fieldset>
|
||||
<Form::Field::ListWrapper
|
||||
@layout='horizontal'
|
||||
@isOptional={{true}}
|
||||
@disabled={{form.disabled}}
|
||||
>
|
||||
<:fieldset as |F|>
|
||||
<F.Legend>
|
||||
{{t 'form.claims_scopes.label'}}
|
||||
</F.Legend>
|
||||
<F.HelperText>
|
||||
{{t 'form.claims_scopes.help'}}
|
||||
</F.HelperText>
|
||||
|
||||
{{#if @model.errors.claims_scopes}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.claims_scopes as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</:fieldset>
|
||||
|
||||
<:field as |F|>
|
||||
<F.TextInput
|
||||
@name='claims_scopes'
|
||||
@options={{@model.claims_scopes}}
|
||||
@model={{@model}}
|
||||
/>
|
||||
</:field>
|
||||
|
||||
</Form::Field::ListWrapper>
|
||||
|
||||
{{! Account Claim Maps }}
|
||||
<Rose::Form::Fieldset>
|
||||
@@ -560,94 +456,37 @@
|
||||
</Rose::Form::Fieldset>
|
||||
|
||||
{{! Certificates }}
|
||||
<Rose::Form::Fieldset>
|
||||
<:title>{{t 'form.idp_ca_certs.label'}}</:title>
|
||||
<:description>{{t 'form.idp_ca_certs.help'}}</:description>
|
||||
<:body>
|
||||
{{#if @model.errors.idp_ca_certs}}
|
||||
<Rose::Form::Errors as |errors|>
|
||||
{{#each @model.errors.idp_ca_certs as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</Rose::Form::Errors>
|
||||
{{/if}}
|
||||
<Rose::Table @style='condensed' as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row @hidden={{true}} as |row|>
|
||||
<row.headerCell>{{t 'titles.value'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'titles.actions'}}</row.headerCell>
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.idp_ca_certs as |cert i|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<Hds::Form::Textarea::Field
|
||||
@value={{cert.value}}
|
||||
@isOptional={{true}}
|
||||
@isInvalid={{@model.errors.idp_ca_certs}}
|
||||
disabled={{form.disabled}}
|
||||
aria-label={{t 'form.certificate.label'}}
|
||||
as |F|
|
||||
>
|
||||
{{#if @model.errors.idp_ca_certs}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.idp_ca_certs as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</Hds::Form::Textarea::Field>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='warning'
|
||||
@iconOnly='flight-icons/svg/trash-16'
|
||||
title={{t 'actions.remove'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on 'click' (fn @removeItemByIndex 'idp_ca_certs' i)}}
|
||||
>
|
||||
{{t 'actions.remove'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
<Form::Field::ListWrapper
|
||||
@layout='horizontal'
|
||||
@isOptional={{true}}
|
||||
@disabled={{form.disabled}}
|
||||
>
|
||||
<:fieldset as |F|>
|
||||
<F.Legend>
|
||||
{{t 'form.idp_ca_certs.label'}}
|
||||
</F.Legend>
|
||||
<F.HelperText>
|
||||
{{t 'form.idp_ca_certs.help'}}
|
||||
</F.HelperText>
|
||||
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<Hds::Form::Textarea::Field
|
||||
@value={{this.newCertificate}}
|
||||
@isOptional={{true}}
|
||||
disabled={{form.disabled}}
|
||||
aria-label={{t 'resources.auth-method.titles.new-certificate'}}
|
||||
/>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='secondary'
|
||||
title={{t 'actions.add'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on
|
||||
'click'
|
||||
(fn @addStringItem 'idp_ca_certs' this.newCertificate)
|
||||
}}
|
||||
>
|
||||
{{t 'actions.add'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
</:body>
|
||||
</Rose::Form::Fieldset>
|
||||
{{#if @model.errors.idp_ca_certs}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.idp_ca_certs as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</:fieldset>
|
||||
|
||||
<:field as |F|>
|
||||
<F.Textarea
|
||||
@name='idp_ca_certs'
|
||||
@options={{@model.idp_ca_certs}}
|
||||
@model={{@model}}
|
||||
/>
|
||||
</:field>
|
||||
|
||||
</Form::Field::ListWrapper>
|
||||
|
||||
<form.input
|
||||
@name='max_age'
|
||||
|
||||
@@ -236,55 +236,69 @@
|
||||
{{/if}}
|
||||
</Hds::Form::TextInput::Field>
|
||||
|
||||
<Form::Field::KeyValueList
|
||||
<Form::Field::ListWrapper
|
||||
@layout='horizontal'
|
||||
@isOptional={{true}}
|
||||
@name='critical_options'
|
||||
@options={{@model.critical_options}}
|
||||
@addOption={{fn this.addOption 'critical_options'}}
|
||||
@removeOptionByIndex={{fn this.removeOptionByIndex 'critical_options'}}
|
||||
@disabled={{form.disabled}}
|
||||
as |M|
|
||||
>
|
||||
<M.Legend>
|
||||
{{t 'resources.credential-library.form.critical_options.label'}}
|
||||
</M.Legend>
|
||||
<M.HelperText>
|
||||
{{t 'resources.credential-library.form.critical_options.help'}}
|
||||
</M.HelperText>
|
||||
{{#if @model.errors.critical_options}}
|
||||
<M.Error as |E|>
|
||||
{{#each @model.errors.critical_options as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</M.Error>
|
||||
{{/if}}
|
||||
</Form::Field::KeyValueList>
|
||||
<:fieldset as |F|>
|
||||
<F.Legend>
|
||||
{{t 'resources.credential-library.form.critical_options.label'}}
|
||||
</F.Legend>
|
||||
<F.HelperText>
|
||||
{{t 'resources.credential-library.form.critical_options.help'}}
|
||||
</F.HelperText>
|
||||
|
||||
<Form::Field::KeyValueList
|
||||
{{#if @model.errors.critical_options}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.critical_options as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</:fieldset>
|
||||
|
||||
<:field as |F|>
|
||||
<F.KeyValue
|
||||
@name='critical_options'
|
||||
@options={{@model.critical_options}}
|
||||
@model={{@model}}
|
||||
@disabled={{form.disabled}}
|
||||
/>
|
||||
</:field>
|
||||
|
||||
</Form::Field::ListWrapper>
|
||||
|
||||
<Form::Field::ListWrapper
|
||||
@layout='horizontal'
|
||||
@isOptional={{true}}
|
||||
@name='extensions'
|
||||
@options={{@model.extensions}}
|
||||
@addOption={{fn this.addOption 'extensions'}}
|
||||
@removeOptionByIndex={{fn this.removeOptionByIndex 'extensions'}}
|
||||
@disabled={{form.disabled}}
|
||||
as |M|
|
||||
>
|
||||
<M.Legend>
|
||||
{{t 'resources.credential-library.form.extensions.label'}}
|
||||
</M.Legend>
|
||||
<M.HelperText>
|
||||
{{t 'resources.credential-library.form.extensions.help'}}
|
||||
</M.HelperText>
|
||||
{{#if @model.errors.extensions}}
|
||||
<M.Error as |E|>
|
||||
{{#each @model.errors.extensions as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</M.Error>
|
||||
{{/if}}
|
||||
</Form::Field::KeyValueList>
|
||||
<:fieldset as |F|>
|
||||
<F.Legend>
|
||||
{{t 'resources.credential-library.form.extensions.label'}}
|
||||
</F.Legend>
|
||||
<F.HelperText>
|
||||
{{t 'resources.credential-library.form.extensions.help'}}
|
||||
</F.HelperText>
|
||||
|
||||
{{#if @model.errors.extensions}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.extensions as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</:fieldset>
|
||||
<:field as |F|>
|
||||
<F.KeyValue
|
||||
@name='extensions'
|
||||
@options={{@model.extensions}}
|
||||
@model={{@model}}
|
||||
/>
|
||||
</:field>
|
||||
|
||||
</Form::Field::ListWrapper>
|
||||
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { action, set } from '@ember/object';
|
||||
|
||||
import {
|
||||
options,
|
||||
TYPES_CREDENTIAL_LIBRARY,
|
||||
@@ -31,30 +31,4 @@ export default class FormCredentialLibraryVaultSshCertComponent extends Componen
|
||||
const keyType = this.args.model.key_type;
|
||||
return keyType === 'rsa' || keyType === 'ecdsa';
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a key/value option object. We recreate a new array after adding
|
||||
* so that ember is aware that the array has been modified.
|
||||
* @param field {string}
|
||||
* @param key {string}
|
||||
* @param value {string}
|
||||
*/
|
||||
@action
|
||||
addOption(field, { key, value }) {
|
||||
const existingArray = this.args.model[field] ?? [];
|
||||
const newArray = [...existingArray, { key, value }];
|
||||
set(this.args.model, field, newArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an option by index. We recreate a new array after
|
||||
* splicing out the item so that ember is aware that the array has been modified.
|
||||
* @param field {string}
|
||||
* @param index {number}
|
||||
*/
|
||||
@action
|
||||
removeOptionByIndex(field, index) {
|
||||
const newArray = this.args.model[field].filter((_, i) => i !== index);
|
||||
set(this.args.model, field, newArray);
|
||||
}
|
||||
}
|
||||
@@ -124,6 +124,7 @@
|
||||
@label={{t 'resources.credential.form.private_key_passphrase.label'}}
|
||||
@helperText={{t 'resources.credential.form.private_key_passphrase.help'}}
|
||||
@error={{@model.errors.private_key_passphrase}}
|
||||
@hasVisibilityToggle={{false}}
|
||||
autocomplete='new-password'
|
||||
as |field|
|
||||
>
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
}}
|
||||
|
||||
<Hds::Form::Fieldset
|
||||
@layout={{@layout}}
|
||||
@isRequired={{@isRequired}}
|
||||
@isOptional={{@isOptional}}
|
||||
as |F|
|
||||
>
|
||||
|
||||
{{yield F}}
|
||||
|
||||
{{#let (unique-id) (unique-id) as |keyHeaderID valueHeaderID|}}
|
||||
<F.Control>
|
||||
<Hds::Table class='key-value-list' name={{@name}}>
|
||||
<:head as |H|>
|
||||
<H.Tr>
|
||||
<H.Th id={{keyHeaderID}}>{{t 'form.key.label'}}</H.Th>
|
||||
<H.Th id={{valueHeaderID}}>{{t 'form.value.label'}}</H.Th>
|
||||
<H.Th>
|
||||
{{#if @removeOptionByIndex}}
|
||||
{{t 'titles.actions'}}
|
||||
{{/if}}
|
||||
</H.Th>
|
||||
</H.Tr>
|
||||
</:head>
|
||||
<:body as |B|>
|
||||
|
||||
{{#each @options as |option index|}}
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{option.key}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-labelledby={{keyHeaderID}}
|
||||
{{on 'input' (set-from-event option 'key')}}
|
||||
/>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{option.value}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-labelledby={{valueHeaderID}}
|
||||
{{on 'input' (set-from-event option 'value')}}
|
||||
/>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
{{#if @removeOptionByIndex}}
|
||||
<Hds::Button
|
||||
@text={{t 'actions.remove'}}
|
||||
@color='critical'
|
||||
@icon='trash'
|
||||
@isIconOnly={{true}}
|
||||
disabled={{@disabled}}
|
||||
{{on 'click' (fn @removeOptionByIndex index)}}
|
||||
/>
|
||||
{{/if}}
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
{{/each}}
|
||||
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{this.newOptionKey}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-labelledby={{keyHeaderID}}
|
||||
{{on 'input' (set-from-event this 'newOptionKey')}}
|
||||
/>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{this.newOptionValue}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-labelledby={{valueHeaderID}}
|
||||
{{on 'input' (set-from-event this 'newOptionValue')}}
|
||||
/>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
<Hds::Button
|
||||
@text={{t 'actions.add'}}
|
||||
@color='secondary'
|
||||
type='button'
|
||||
disabled={{or @disabled (not this.newOptionKey)}}
|
||||
{{on 'click' this.addOption}}
|
||||
/>
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
|
||||
</:body>
|
||||
</Hds::Table>
|
||||
</F.Control>
|
||||
{{/let}}
|
||||
</Hds::Form::Fieldset>
|
||||
@@ -1,47 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { assert } from '@ember/debug';
|
||||
|
||||
export default class MappingListComponent extends Component {
|
||||
// =attributes
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
@tracked newOptionKey = '';
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
@tracked newOptionValue = '';
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
* If a new key value is entered and an addOption method was specified,
|
||||
* calls addOption with the new key and value. Resets key and value.
|
||||
*/
|
||||
@action
|
||||
addOption() {
|
||||
assert(
|
||||
'[boundary-admin-key-value-list-field] `@addOption` is required.',
|
||||
this.args.addOption
|
||||
);
|
||||
|
||||
if (this.newOptionKey) {
|
||||
this.args.addOption({
|
||||
key: this.newOptionKey,
|
||||
value: this.newOptionValue,
|
||||
});
|
||||
}
|
||||
|
||||
this.newOptionKey = '';
|
||||
this.newOptionValue = '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
}}
|
||||
|
||||
<Hds::Form::Fieldset
|
||||
@layout={{@layout}}
|
||||
@isRequired={{@isRequired}}
|
||||
@isOptional={{@isOptional}}
|
||||
as |F|
|
||||
>
|
||||
|
||||
{{yield F to='fieldset'}}
|
||||
|
||||
<F.Control>
|
||||
{{yield
|
||||
(hash
|
||||
KeyValue=(component
|
||||
'form/field/list-wrapper/key-value' disabled=@disabled
|
||||
)
|
||||
TextInput=(component
|
||||
'form/field/list-wrapper/text-input' disabled=@disabled
|
||||
)
|
||||
Textarea=(component
|
||||
'form/field/list-wrapper/textarea' disabled=@disabled
|
||||
)
|
||||
)
|
||||
to='field'
|
||||
}}
|
||||
</F.Control>
|
||||
|
||||
</Hds::Form::Fieldset>
|
||||
@@ -0,0 +1,92 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
}}
|
||||
{{#let (unique-id) (unique-id) as |keyHeaderID valueHeaderID|}}
|
||||
|
||||
<Hds::Table class='list-wrapper-field' name={{@name}}>
|
||||
<:head as |H|>
|
||||
<H.Tr>
|
||||
<H.Th id={{keyHeaderID}}>{{t 'form.key.label'}}</H.Th>
|
||||
<H.Th id={{valueHeaderID}}>{{t 'form.value.label'}}</H.Th>
|
||||
<H.Th>
|
||||
{{t 'titles.actions'}}
|
||||
|
||||
</H.Th>
|
||||
</H.Tr>
|
||||
</:head>
|
||||
<:body as |B|>
|
||||
{{#each this.options as |option index|}}
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{option.key}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-labelledby={{keyHeaderID}}
|
||||
{{on 'input' (set-from-event option 'key')}}
|
||||
/>
|
||||
</B.Td>
|
||||
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{option.value}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-labelledby={{valueHeaderID}}
|
||||
{{on 'input' (set-from-event option 'value')}}
|
||||
/>
|
||||
</B.Td>
|
||||
|
||||
<B.Td>
|
||||
{{#if this.removeOptionByIndex}}
|
||||
<Hds::Button
|
||||
data-test-remove-button
|
||||
@text={{t 'actions.remove'}}
|
||||
@color='critical'
|
||||
@icon='trash'
|
||||
@isIconOnly={{true}}
|
||||
disabled={{@disabled}}
|
||||
{{on 'click' (fn this.removeOptionByIndex index)}}
|
||||
/>
|
||||
{{/if}}
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
{{/each}}
|
||||
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{this.newOptionKey}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-labelledby={{keyHeaderID}}
|
||||
{{on 'input' (set-from-event this 'newOptionKey')}}
|
||||
/>
|
||||
</B.Td>
|
||||
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{this.newOptionValue}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-labelledby={{valueHeaderID}}
|
||||
{{on 'input' (set-from-event this 'newOptionValue')}}
|
||||
/>
|
||||
</B.Td>
|
||||
|
||||
<B.Td>
|
||||
<Hds::Button
|
||||
@text={{t 'actions.add'}}
|
||||
@color='secondary'
|
||||
type='button'
|
||||
disabled={{or @disabled (not this.newOptionKey)}}
|
||||
{{on 'click' this.addOption}}
|
||||
/>
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
|
||||
</:body>
|
||||
</Hds::Table>
|
||||
|
||||
{{/let}}
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { set } from '@ember/object';
|
||||
|
||||
export default class MappingListComponent extends Component {
|
||||
// =attributes
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
@tracked newOptionKey = '';
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
@tracked newOptionValue = '';
|
||||
|
||||
/**
|
||||
* Returns an array of key/value pair that the user enters
|
||||
* @type {object}
|
||||
*/
|
||||
|
||||
get options() {
|
||||
return this.args?.options || this.args?.model?.[this.args.name];
|
||||
}
|
||||
// =actions
|
||||
|
||||
/**
|
||||
* If a new key value is entered and an addOption method was specified,
|
||||
* calls addOption with the new key and value. Resets key and value.
|
||||
* Otherwise use the model argument to create the array and update the model
|
||||
*/
|
||||
|
||||
@action
|
||||
addOption() {
|
||||
if (this.args.addOption) {
|
||||
if (this.newOptionKey) {
|
||||
this.args.addOption({
|
||||
key: this.newOptionKey,
|
||||
value: this.newOptionValue,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const field = this.args.name;
|
||||
const existingArray = this.args.model[field] ?? [];
|
||||
const newArray = [
|
||||
...existingArray,
|
||||
{ key: this.newOptionKey, value: this.newOptionValue },
|
||||
];
|
||||
set(this.args.model, field, newArray);
|
||||
}
|
||||
|
||||
this.newOptionKey = '';
|
||||
this.newOptionValue = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* If removeOptionByIndex method was passed, use that.
|
||||
* Otherwise, use the model to remove an option by index. We recreate a new array after
|
||||
* splicing out the item so that ember is aware that the array has been modified.
|
||||
* @param index {number}
|
||||
*/
|
||||
@action
|
||||
removeOptionByIndex(index) {
|
||||
if (this.args.removeOptionByIndex) {
|
||||
this.args.removeOptionByIndex(index);
|
||||
} else {
|
||||
const field = this.args.name;
|
||||
const newArray = this.args.model[field].filter((_, i) => i !== index);
|
||||
set(this.args.model, field, newArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
}}
|
||||
|
||||
<Hds::Table class='list-wrapper-field' name={{@name}}>
|
||||
|
||||
<:body as |B|>
|
||||
|
||||
{{#each @options as |option index|}}
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{option.value}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-label={{t 'titles.value'}}
|
||||
{{on 'input' (set-from-event option 'value')}}
|
||||
/>
|
||||
</B.Td>
|
||||
|
||||
<B.Td>
|
||||
{{#if this.removeOptionByIndex}}
|
||||
<Hds::Button
|
||||
data-test-remove-button
|
||||
@text={{t 'actions.remove'}}
|
||||
@color='critical'
|
||||
@icon='trash'
|
||||
@isIconOnly={{true}}
|
||||
disabled={{@disabled}}
|
||||
{{on 'click' (fn this.removeOptionByIndex index)}}
|
||||
/>
|
||||
{{/if}}
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
{{/each}}
|
||||
|
||||
<B.Tr>
|
||||
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{this.newOptionValue}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-label={{t 'titles.value'}}
|
||||
{{on 'input' (set-from-event this 'newOptionValue')}}
|
||||
/>
|
||||
</B.Td>
|
||||
|
||||
<B.Td>
|
||||
<Hds::Button
|
||||
@text={{t 'actions.add'}}
|
||||
@color='secondary'
|
||||
type='button'
|
||||
disabled={{or @disabled (not this.newOptionValue)}}
|
||||
{{on 'click' this.addOption}}
|
||||
/>
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
|
||||
</:body>
|
||||
</Hds::Table>
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { set } from '@ember/object';
|
||||
|
||||
export default class MappingListTextInputComponent extends Component {
|
||||
// =attributes
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
@tracked newOptionValue = '';
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
* If a new input is entered and an addOption method was specified,
|
||||
* calls addOption with the new input. Resets previous value.
|
||||
* Otherwise use the model argument to create the array and update the model
|
||||
*/
|
||||
|
||||
@action
|
||||
addOption() {
|
||||
if (this.args.addOption) {
|
||||
if (this.newOptionValue) {
|
||||
this.args.addOption({
|
||||
value: this.newOptionValue,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const field = this.args.name;
|
||||
const existingArray = this.args.model[field] ?? [];
|
||||
const newArray = [...existingArray, { value: this.newOptionValue }];
|
||||
set(this.args.model, field, newArray);
|
||||
}
|
||||
|
||||
this.newOptionValue = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* If removeOptionByIndex method was passed, use that.
|
||||
* Otherwise, use the model to remove an option by index. We recreate a new array after
|
||||
* splicing out the item so that ember is aware that the array has been modified.
|
||||
* @param index {number}
|
||||
*/
|
||||
@action
|
||||
removeOptionByIndex(index) {
|
||||
if (this.args.removeOptionByIndex) {
|
||||
this.args.removeOptionByIndex(index);
|
||||
} else {
|
||||
const field = this.args.name;
|
||||
const newArray = this.args.model[field].filter((_, i) => i !== index);
|
||||
set(this.args.model, field, newArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
}}
|
||||
|
||||
<Hds::Table class='list-wrapper-field' name={{@name}}>
|
||||
|
||||
<:body as |B|>
|
||||
|
||||
{{#each @options as |option index|}}
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
<Hds::Form::Textarea::Field
|
||||
@value={{option.value}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-label={{t 'titles.value'}}
|
||||
/>
|
||||
</B.Td>
|
||||
|
||||
<B.Td>
|
||||
{{#if this.removeOptionByIndex}}
|
||||
<Hds::Button
|
||||
data-test-remove-button
|
||||
@text={{t 'actions.remove'}}
|
||||
@color='critical'
|
||||
@icon='trash'
|
||||
@isIconOnly={{true}}
|
||||
disabled={{@disabled}}
|
||||
{{on 'click' (fn this.removeOptionByIndex index)}}
|
||||
/>
|
||||
{{/if}}
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
{{/each}}
|
||||
|
||||
<B.Tr>
|
||||
|
||||
<B.Td>
|
||||
<Hds::Form::Textarea::Field
|
||||
@value={{this.newOptionValue}}
|
||||
@type='text'
|
||||
disabled={{@disabled}}
|
||||
aria-label={{t 'titles.value'}}
|
||||
/>
|
||||
</B.Td>
|
||||
|
||||
<B.Td>
|
||||
<Hds::Button
|
||||
@text={{t 'actions.add'}}
|
||||
@color='secondary'
|
||||
type='button'
|
||||
disabled={{or @disabled (not this.newOptionValue)}}
|
||||
{{on 'click' this.addOption}}
|
||||
/>
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
|
||||
</:body>
|
||||
</Hds::Table>
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { set } from '@ember/object';
|
||||
|
||||
export default class MappingListTextAreaComponent extends Component {
|
||||
// =attributes
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
@tracked newOptionValue = '';
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
* If a new input is entered and an addOption method was specified,
|
||||
* calls addOption with the new input. Resets previous value.
|
||||
* Otherwise use the model argument to create the array and update the model
|
||||
*/
|
||||
|
||||
@action
|
||||
addOption() {
|
||||
if (this.args.addOption) {
|
||||
if (this.newOptionValue) {
|
||||
this.args.addOption({
|
||||
value: this.newOptionValue,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const field = this.args.name;
|
||||
const existingArray = this.args.model[field] ?? [];
|
||||
const newArray = [...existingArray, { value: this.newOptionValue }];
|
||||
set(this.args.model, field, newArray);
|
||||
}
|
||||
|
||||
this.newOptionValue = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* If removeOptionByIndex method was passed, use that.
|
||||
* Otherwise, use the model to remove an option by index. We recreate a new array after
|
||||
* splicing out the item so that ember is aware that the array has been modified.
|
||||
* @param index {number}
|
||||
*/
|
||||
@action
|
||||
removeOptionByIndex(index) {
|
||||
if (this.args.removeOptionByIndex) {
|
||||
this.args.removeOptionByIndex(index);
|
||||
} else {
|
||||
const field = this.args.name;
|
||||
const newArray = this.args.model[field].filter((_, i) => i !== index);
|
||||
set(this.args.model, field, newArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
@type={{(or @type 'password')}}
|
||||
name={{@name}}
|
||||
disabled={{or @isDisabled (not this.isEditing)}}
|
||||
@hasVisibilityToggle={{false}}
|
||||
...attributes
|
||||
as |F|
|
||||
>
|
||||
|
||||
@@ -69,178 +69,61 @@
|
||||
</F.HelperText>
|
||||
</InfoField>
|
||||
|
||||
<Rose::Form::Fieldset
|
||||
@helperText={{t 'resources.host-set.form.preferred_endpoints.help'}}
|
||||
@linkText={{t 'actions.learn-more'}}
|
||||
@link={{doc-url 'host-set.preferred-endpoints'}}
|
||||
<Form::Field::ListWrapper
|
||||
@layout='horizontal'
|
||||
@isOptional={{true}}
|
||||
@disabled={{form.disabled}}
|
||||
>
|
||||
<:title>{{t 'resources.host-set.form.preferred_endpoints.label'}}</:title>
|
||||
<:body>
|
||||
<:fieldset as |F|>
|
||||
<F.Legend>
|
||||
{{t 'resources.host-set.form.preferred_endpoints.label'}}
|
||||
</F.Legend>
|
||||
<F.HelperText>
|
||||
{{t 'resources.host-set.form.preferred_endpoints.help'}}
|
||||
</F.HelperText>
|
||||
|
||||
{{#if @model.errors.preferred_endpoints}}
|
||||
<Rose::Form::Errors as |errors|>
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.preferred_endpoints as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</Rose::Form::Errors>
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
<Rose::Table @style='condensed' as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row @hidden={{true}} as |row|>
|
||||
<row.headerCell>{{t 'titles.value'}}</row.headerCell>
|
||||
<row.headerCell />
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.preferred_endpoints as |endpoint i|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='preferred_endpoints'
|
||||
@value={{endpoint.value}}
|
||||
@error={{@model.errors.preferred_endpoints}}
|
||||
@contextual={{true}}
|
||||
placeholder='cidr:2001:4860:4860::8888/32'
|
||||
as |field|
|
||||
>
|
||||
<field.field />
|
||||
</form.input>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='warning'
|
||||
@iconOnly='flight-icons/svg/trash-16'
|
||||
title={{t 'actions.remove'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on 'click' (fn @removeItemByIndex 'preferred_endpoints' i)}}
|
||||
>
|
||||
{{t 'actions.remove'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
</:fieldset>
|
||||
<:field as |F|>
|
||||
<F.TextInput
|
||||
@name='preferred_endpoints'
|
||||
@options={{@model.preferred_endpoints}}
|
||||
@model={{@model}}
|
||||
/>
|
||||
</:field>
|
||||
</Form::Field::ListWrapper>
|
||||
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='preferred_endpoints'
|
||||
@value={{@model.preferred_endpoint}}
|
||||
placeholder='cidr:2001:4860:4860::8888/32'
|
||||
/>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='secondary'
|
||||
title={{t 'actions.add'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on
|
||||
'click'
|
||||
(fn
|
||||
@addStringItem
|
||||
'preferred_endpoints'
|
||||
@model.preferred_endpoint
|
||||
)
|
||||
}}
|
||||
>
|
||||
{{t 'actions.add'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
</:body>
|
||||
</Rose::Form::Fieldset>
|
||||
<Form::Field::ListWrapper @layout='horizontal' @disabled={{form.disabled}}>
|
||||
<:fieldset as |F|>
|
||||
<F.Legend>
|
||||
{{t 'resources.host-set.form.filter.label'}}
|
||||
</F.Legend>
|
||||
<F.HelperText>
|
||||
{{t 'resources.host-set.form.filter.aws.help'}}
|
||||
</F.HelperText>
|
||||
|
||||
<Rose::Form::Fieldset>
|
||||
<:title>{{t 'resources.host-set.form.filter.label'}}</:title>
|
||||
<:description>{{t 'resources.host-set.form.filter.aws.help'}}</:description>
|
||||
<:body>
|
||||
{{#if @model.errors.filters}}
|
||||
<Rose::Form::Errors as |errors|>
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.filters as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</Rose::Form::Errors>
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
<Rose::Table @style='condensed' as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row @hidden={{true}} as |row|>
|
||||
<row.headerCell>{{t 'titles.value'}}</row.headerCell>
|
||||
<row.headerCell />
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.filters as |filter i|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='filters'
|
||||
@value={{filter.value}}
|
||||
@error={{@model.errors.filters}}
|
||||
@contextual={{true}}
|
||||
as |field|
|
||||
>
|
||||
<field.field />
|
||||
</form.input>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='warning'
|
||||
@iconOnly='flight-icons/svg/trash-16'
|
||||
title={{t 'actions.remove'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on 'click' (fn @removeItemByIndex 'filters' i)}}
|
||||
>
|
||||
{{t 'actions.remove'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='filters'
|
||||
@value={{@model.filter_string}}
|
||||
/>
|
||||
</row.cell>
|
||||
<row.cell @shrink={{true}}>
|
||||
<Rose::Button
|
||||
@style='secondary'
|
||||
title={{t 'actions.add'}}
|
||||
@disabled={{if
|
||||
@model.isNew
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on
|
||||
'click'
|
||||
(fn @addStringItem 'filters' @model.filter_string)
|
||||
}}
|
||||
>
|
||||
{{t 'actions.add'}}
|
||||
</Rose::Button>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
</:body>
|
||||
</Rose::Form::Fieldset>
|
||||
</:fieldset>
|
||||
<:field as |F|>
|
||||
<F.TextInput
|
||||
@name='filters'
|
||||
@options={{@model.filters}}
|
||||
@model={{@model}}
|
||||
/>
|
||||
</:field>
|
||||
</Form::Field::ListWrapper>
|
||||
|
||||
<form.input
|
||||
@name='sync_interval_seconds'
|
||||
|
||||
Loaded 100 of 470 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user