+ The Access Control List (ACL) system, which controls permissions for this UI, is enabled for this cluster. Your token ID will be saved locally and persist through visits.
+
+
+ ACLs are disabled in this Consul cluster. This is the default behavior, as you have to explicitly enable them.
+
+
{{#if create }}
{{! we only need to check for an empty name here as ember munges autofocus, once we have autofocus back revisit this}}
-
Save
-{{ else }}
-
Save
+
Save {{else}}
Save
{{/if}}
Cancel
{{# if (and (not create) (not-eq item.ID 'anonymous')) }}
@@ -38,11 +36,7 @@
Delete
{{/block-slot}}
{{#block-slot 'dialog' as |execute cancel message|}}
-
- {{message}}
-
-
Confirm Delete
-
Cancel
+ {{delete-confirmation message=message execute=execute cancel=cancel}}
{{/block-slot}}
{{/confirmation-dialog}}
{{/if}}
diff --git a/ui-v2/app/templates/dc/acls/-nav.hbs b/ui-v2/app/templates/dc/acls/-nav.hbs
new file mode 100644
index 0000000000..4b7625a82e
--- /dev/null
+++ b/ui-v2/app/templates/dc/acls/-nav.hbs
@@ -0,0 +1,13 @@
+{{tab-nav
+ items=(array
+ (hash
+ label='Tokens'
+ href=(href-to 'dc.acls.tokens')
+ )
+ (hash
+ label='Policies'
+ href=(href-to 'dc.acls.policies')
+ )
+ )
+ selected=(if (is-href 'dc.acls.policies') 'policies' 'tokens')
+}}
diff --git a/ui-v2/app/templates/dc/acls/policies/-fieldsets.hbs b/ui-v2/app/templates/dc/acls/policies/-fieldsets.hbs
new file mode 100644
index 0000000000..be9932ecbb
--- /dev/null
+++ b/ui-v2/app/templates/dc/acls/policies/-fieldsets.hbs
@@ -0,0 +1,49 @@
+
+
+ Name
+ {{input value=item.Name name='policy[Name]' autofocus='autofocus'}}
+
+ Maximum 128 characters. May only include letters (uppercase and/or lowercase) and/or numbers. Must be unique.
+
+ {{#if item.error.Name}}
+ {{item.error.Name.validation}}
+ {{/if}}
+
+
+ Rules (HCL Format)
+ {{code-editor id="policy_rules" class=(if item.error.Rules 'error') name='policy[Rules]' value=item.Rules onkeyup=(action 'change' 'policy[Rules]')}}
+ {{#if item.error.Rules}}
+ {{item.error.Rules.validation}}
+ {{/if}}
+
+
+ Valid datacenters
+
+
+ All
+
+
+{{#if isScoped }}
+
+ {{#each datacenters as |dc| }}
+
+
+ {{dc.Name}}
+
+ {{/each}}
+ {{#each item.Datacenters as |dc| }}
+ {{#if (not (find-by 'Name' dc datacenters))}}
+
+
+ {{dc}}
+
+ {{/if}}
+ {{/each}}
+
+{{/if}}
+
+ Description (Optional)
+
+
+
+
diff --git a/ui-v2/app/templates/dc/acls/policies/-form.hbs b/ui-v2/app/templates/dc/acls/policies/-form.hbs
new file mode 100644
index 0000000000..7896e80b25
--- /dev/null
+++ b/ui-v2/app/templates/dc/acls/policies/-form.hbs
@@ -0,0 +1,46 @@
+
diff --git a/ui-v2/app/templates/dc/acls/policies/-notifications.hbs b/ui-v2/app/templates/dc/acls/policies/-notifications.hbs
new file mode 100644
index 0000000000..99ed439a7d
--- /dev/null
+++ b/ui-v2/app/templates/dc/acls/policies/-notifications.hbs
@@ -0,0 +1,20 @@
+{{#if (eq type 'create')}}
+ {{#if (eq status 'success') }}
+ Your policy has been added.
+ {{else}}
+ There was an error adding your policy.
+ {{/if}}
+{{else if (eq type 'update') }}
+ {{#if (eq status 'success') }}
+ Your policy has been saved.
+ {{else}}
+ There was an error saving your policy.
+ {{/if}}
+{{ else if (eq type 'delete')}}
+ {{#if (eq status 'success') }}
+ Your policy was deleted.
+ {{else}}
+ There was an error deleting your policy.
+ {{/if}}
+{{/if}}
+
diff --git a/ui-v2/app/templates/dc/acls/policies/-view.hbs b/ui-v2/app/templates/dc/acls/policies/-view.hbs
new file mode 100644
index 0000000000..e8f1caaf70
--- /dev/null
+++ b/ui-v2/app/templates/dc/acls/policies/-view.hbs
@@ -0,0 +1,12 @@
+
Management This global-management token is built into Consul's policy system. You can apply this special policy to Tokens for full access. This policy is not editable or removeable, but can be ignored by not applying it to any tokens. Learn more in our documentation .
+
+
+ Name
+ {{item.Name}}
+ Valid Datacenters
+ {{ join ', ' (policy/datacenters item)}}
+ Description
+ {{item.Description}}
+
+
+{{token-list caption="Applied to the following tokens:" items=items}}
diff --git a/ui-v2/app/templates/dc/acls/policies/edit.hbs b/ui-v2/app/templates/dc/acls/policies/edit.hbs
new file mode 100644
index 0000000000..b2b585b1b7
--- /dev/null
+++ b/ui-v2/app/templates/dc/acls/policies/edit.hbs
@@ -0,0 +1,40 @@
+{{#app-view class=(concat 'policy ' (if (or isAuthorized isEnabled) 'edit' 'list')) loading=isLoading authorized=isAuthorized enabled=isEnabled}}
+ {{#block-slot 'notification' as |status type|}}
+ {{partial 'dc/acls/policies/notifications'}}
+ {{/block-slot}}
+ {{#block-slot 'disabled'}}
+ {{partial 'dc/acls/disabled'}}
+ {{/block-slot}}
+ {{#block-slot 'authorization'}}
+ {{partial 'dc/acls/authorization'}}
+ {{/block-slot}}
+ {{#block-slot 'breadcrumbs'}}
+
+ All Policies
+
+ {{/block-slot}}
+ {{#block-slot 'header'}}
+
+{{#if isAuthorized }}
+ {{#if create }}
+ New Policy
+ {{else}}
+ {{#if (policy/is-management item)}}
+ View Policy
+ {{else}}
+ Edit Policy
+ {{/if}}
+ {{/if}}
+{{else}}
+ Access Controls
+{{/if}}
+
+ {{/block-slot}}
+ {{#block-slot 'content'}}
+{{#if (policy/is-management item)}}
+ {{ partial 'dc/acls/policies/view'}}
+{{else}}
+ {{ partial 'dc/acls/policies/form'}}
+{{/if}}
+ {{/block-slot}}
+{{/app-view}}
\ No newline at end of file
diff --git a/ui-v2/app/templates/dc/acls/policies/index.hbs b/ui-v2/app/templates/dc/acls/policies/index.hbs
new file mode 100644
index 0000000000..5d1e4d8718
--- /dev/null
+++ b/ui-v2/app/templates/dc/acls/policies/index.hbs
@@ -0,0 +1,81 @@
+{{#app-view class=(concat 'policy ' (if (not isAuthorized) 'edit' 'list')) loading=isLoading authorized=isAuthorized enabled=isEnabled}}
+ {{#block-slot 'notification' as |status type|}}
+ {{partial 'dc/acls/policies/notifications'}}
+ {{/block-slot}}
+ {{#block-slot 'header'}}
+
+ Access Controls
+
+ {{#if isAuthorized }}
+ {{partial 'dc/acls/nav'}}
+ {{/if}}
+ {{/block-slot}}
+ {{#block-slot 'disabled'}}
+ {{partial 'dc/acls/disabled'}}
+ {{/block-slot}}
+ {{#block-slot 'authorization'}}
+ {{partial 'dc/acls/authorization'}}
+ {{/block-slot}}
+ {{#block-slot 'actions'}}
+
Create
+ {{/block-slot}}
+ {{#block-slot 'content'}}
+{{#if (gt items.length 0) }}
+
+{{/if}}
+{{#if (gt filtered.length 0)}}
+ {{#tabular-collection
+ items=(sort-by 'CreateIndex:desc' 'Name:asc' filtered) as |item index|
+ }}
+ {{#block-slot 'header'}}
+
Name
+
Datacenters
+
Description
+ {{/block-slot}}
+ {{#block-slot 'row' }}
+
+ {{item.Name}}
+
+
+ {{join ', ' (policy/datacenters item)}}
+
+
+ {{item.Description}}
+
+ {{/block-slot}}
+ {{#block-slot 'actions' as |index change checked|}}
+ {{#confirmation-dialog confirming=false index=index message="Are you sure you want to delete this Policy?"}}
+ {{#block-slot 'action' as |confirm|}}
+ {{#action-group index=index onchange=(action change) checked=(if (eq checked index) 'checked')}}
+
+{{#if (policy/is-management item)}}
+
+ View
+
+{{else}}
+
+
+ Edit
+
+
+ Delete
+
+{{/if}}
+
+ {{/action-group}}
+ {{/block-slot}}
+ {{#block-slot 'dialog' as |execute cancel message name|}}
+ {{delete-confirmation message=message execute=execute cancel=cancel}}
+ {{/block-slot}}
+ {{/confirmation-dialog}}
+ {{/block-slot}}
+ {{/tabular-collection}}
+{{else}}
+
+ There are no Policies.
+
+{{/if}}
+ {{/block-slot}}
+{{/app-view}}
\ No newline at end of file
diff --git a/ui-v2/app/templates/dc/acls/tokens/-fieldsets-legacy.hbs b/ui-v2/app/templates/dc/acls/tokens/-fieldsets-legacy.hbs
new file mode 100644
index 0000000000..18c4f8b04d
--- /dev/null
+++ b/ui-v2/app/templates/dc/acls/tokens/-fieldsets-legacy.hbs
@@ -0,0 +1,28 @@
+
+
+ Name
+ {{input value=item.Description name='name' autofocus='autofocus'}}
+
+{{#if false}}
+
+ {{#each (array 'management' 'client') as |type|}}
+
+ {{capitalize type}}
+
+
+ {{/each}}
+
+{{/if}}
+
+ Rules (HCL Format)
+ {{code-editor class=(if item.error.Rules 'error') name='Rules' value=item.Rules onkeyup=(action 'change' 'Rules')}}
+
+{{#if create }}
+
+ ID
+ {{ input value=item.ID }}
+ We'll generate a UUID if this field is left empty.
+
+{{/if}}
+
+
diff --git a/ui-v2/app/templates/dc/acls/tokens/-fieldsets.hbs b/ui-v2/app/templates/dc/acls/tokens/-fieldsets.hbs
new file mode 100644
index 0000000000..96ff233eaf
--- /dev/null
+++ b/ui-v2/app/templates/dc/acls/tokens/-fieldsets.hbs
@@ -0,0 +1,20 @@
+
+{{#if create }}
+
+ Restrict this token to a local datacenter?
+ Local tokens get set in the Raft store of the local DC and do not ever get transmitted to the primary DC or replicated to any other DC.
+
+
+ No
+
+
+{{/if}}
+
+ Description (Optional)
+
+
+
+
+ Policies
+ {{partial 'dc/acls/tokens/policies'}}
+
diff --git a/ui-v2/app/templates/dc/acls/tokens/-form.hbs b/ui-v2/app/templates/dc/acls/tokens/-form.hbs
new file mode 100644
index 0000000000..b22991cabd
--- /dev/null
+++ b/ui-v2/app/templates/dc/acls/tokens/-form.hbs
@@ -0,0 +1,27 @@
+
diff --git a/ui-v2/app/templates/dc/acls/tokens/-notifications.hbs b/ui-v2/app/templates/dc/acls/tokens/-notifications.hbs
new file mode 100644
index 0000000000..5c98ecf4bf
--- /dev/null
+++ b/ui-v2/app/templates/dc/acls/tokens/-notifications.hbs
@@ -0,0 +1,44 @@
+{{#if (eq type 'create')}}
+ {{#if (eq status 'success') }}
+ The token has been added.
+ {{else}}
+ There was an error adding the token.
+ {{/if}}
+{{else if (eq type 'update') }}
+ {{#if (eq status 'success') }}
+ The token has been saved.
+ {{else}}
+ There was an error saving the token.
+ {{/if}}
+{{ else if (eq type 'delete')}}
+ {{#if (eq status 'success') }}
+ The token was deleted.
+ {{else}}
+ There was an error deleting the token.
+ {{/if}}
+{{ else if (eq type 'logout')}}
+ {{#if (eq status 'success') }}
+ You are now logged out.
+ {{else}}
+ There was an error logging out.
+ {{/if}}
+{{ else if (eq type 'clone')}}
+ {{#if (eq status 'success') }}
+ The token has been cloned as {{truncate subject.AccessorID 8 false}}
+ {{else}}
+ There was an error cloning the token.
+ {{/if}}
+{{ else if (eq type 'authorize')}}
+ {{#if (eq status 'success') }}
+ You are now logged in.
+ {{else}}
+ There was an error, please check your SecretID/Token
+ {{/if}}
+{{ else if (eq type 'use')}}
+ {{#if (eq status 'success') }}
+ You are now using the new ACL token
+ {{else}}
+ There was an error using that ACL token.
+ {{/if}}
+{{/if}}
+
diff --git a/ui-v2/app/templates/dc/acls/tokens/-policies.hbs b/ui-v2/app/templates/dc/acls/tokens/-policies.hbs
new file mode 100644
index 0000000000..c1cb54d632
--- /dev/null
+++ b/ui-v2/app/templates/dc/acls/tokens/-policies.hbs
@@ -0,0 +1,77 @@
+
+ Create new policy
+ {{#modal-dialog data-test-policy-form onclose=(action 'sendClearPolicy') onopen=(action 'refreshCodeEditor' '#policy_rules') name="new-policy-toggle"}}
+ {{#block-slot 'header'}}
+ New Policy
+ {{/block-slot}}
+ {{#block-slot 'body'}}
+ {{#with policy as |item|}}
+ {{partial 'dc/acls/policies/fieldsets'}}
+ {{/with}}
+ {{/block-slot}}
+ {{#block-slot 'actions' as |close|}}
+
+ {{#if policy.isSaving }}
+
+ {{/if}}
+ Create and apply
+
+ Cancel
+ {{/block-slot}}
+ {{/modal-dialog}}
+
+
+ Apply an existing policy
+ {{#power-select
+ options=(difference items item.Policies item.Policies.length)
+ searchField='Name'
+ selected=DestinationName
+ searchPlaceholder='Type policy name'
+ onchange=(action 'change' 'Policy') as |policy|
+ }}
+ {{policy.Name}}
+ {{/power-select}}
+
+{{#if (gt item.Policies.length 0)}}
+ {{#with item as |token| }}
+ {{#tabular-details
+ data-test-policies
+ onchange=(action 'change')
+ name="Details"
+ items=(sort-by 'CreateTime:desc' 'Name:asc' item.Policies) as |item index|
+ }}
+ {{#block-slot 'header'}}
+
Name
+
Datacenters
+ {{/block-slot}}
+ {{#block-slot 'row'}}
+
+ {{item.Name}}
+
+
+ {{if (not item.isSaving) (join ', ' (policy/datacenters item)) 'Saving...'}}
+
+ {{/block-slot}}
+ {{#block-slot 'details'}}
+
+ Rules (HCL Format)
+ {{code-editor readonly=true value=item.Rules}}
+
+
+ {{#confirmation-dialog message='Are you sure you want to remove this policy from this token?'}}
+ {{#block-slot 'action' as |confirm|}}
+
Remove
+ {{/block-slot}}
+ {{#block-slot 'dialog' as |execute cancel message|}}
+
+ {{message}}
+
+
Confirm remove
+
Cancel
+ {{/block-slot}}
+ {{/confirmation-dialog}}
+
+ {{/block-slot}}
+ {{/tabular-details}}
+ {{/with}}
+{{/if}}
diff --git a/ui-v2/app/templates/dc/acls/tokens/edit.hbs b/ui-v2/app/templates/dc/acls/tokens/edit.hbs
new file mode 100644
index 0000000000..96e8125fab
--- /dev/null
+++ b/ui-v2/app/templates/dc/acls/tokens/edit.hbs
@@ -0,0 +1,76 @@
+{{#app-view class=(concat 'token ' (if (or isAuthorized isEnabled) 'edit' 'list')) loading=isLoading authorized=isAuthorized enabled=isEnabled}}
+ {{#block-slot 'notification' as |status type|}}
+ {{partial 'dc/acls/tokens/notifications'}}
+ {{/block-slot}}
+ {{#block-slot 'disabled'}}
+ {{partial 'dc/acls/disabled'}}
+ {{/block-slot}}
+ {{#block-slot 'authorization'}}
+ {{partial 'dc/acls/authorization'}}
+ {{/block-slot}}
+ {{#block-slot 'breadcrumbs'}}
+
+ All Tokens
+
+ {{/block-slot}}
+ {{#block-slot 'header'}}
+
+{{#if isAuthorized }}
+ {{#if create }}
+ New Token
+ {{else}}
+ Edit Token
+ {{/if}}
+{{else}}
+ Access Controls
+{{/if}}
+
+ {{/block-slot}}
+ {{#block-slot 'actions'}}
+{{#if (not create)}}
+ {{#if (not-eq item.AccessorID token.AccessorID)}}
+ {{#confirmation-dialog message='Are you sure you want to use this ACL token?'}}
+ {{#block-slot 'action' as |confirm|}}
+
Use
+ {{/block-slot}}
+ {{#block-slot 'dialog' as |execute cancel message|}}
+
+ {{message}}
+
+
Confirm Use
+
Cancel
+ {{/block-slot}}
+ {{/confirmation-dialog}}
+ {{/if}}
+ {{#if (not (token/is-legacy item))}}
+
Duplicate
+ {{/if}}
+{{/if}}
+ {{/block-slot}}
+ {{#block-slot 'content'}}
+ {{#if (token/is-legacy item)}}
+
Update. We've upgraded our ACL system by allowing you to create reusable policies which you can then apply to tokens. Don't worry, even though this token was written in the old style, it is still valid. However, we do recommend upgrading your old Tokens to the new style. Learn how in our documentation .
+ {{/if}}
+{{#if (not create) }}
+
+
+ AccessorID
+
+ {{copy-button-feedback title="Copy AccessorID to the clipboard" copy=item.AccessorID name="AccessorID"}} {{item.AccessorID}}
+
+ Token
+
+ {{copy-button-feedback title="Copy SecretID to the clipboard" copy=item.SecretID name="Token"}} {{#secret-button}}{{item.SecretID}}{{/secret-button}}
+
+{{#if (and (not (token/is-legacy item)) (not create))}}
+ Scope
+
+ {{if item.Local 'local' 'global' }}
+
+{{/if}}
+
+
+{{/if}}
+ {{ partial 'dc/acls/tokens/form'}}
+ {{/block-slot}}
+{{/app-view}}
\ No newline at end of file
diff --git a/ui-v2/app/templates/dc/acls/tokens/index.hbs b/ui-v2/app/templates/dc/acls/tokens/index.hbs
new file mode 100644
index 0000000000..c403d205ae
--- /dev/null
+++ b/ui-v2/app/templates/dc/acls/tokens/index.hbs
@@ -0,0 +1,134 @@
+{{#app-view class=(concat 'token ' (if (and isEnabled (not isAuthorized)) 'edit' 'list')) loading=isLoading authorized=isAuthorized enabled=isEnabled}}
+ {{#block-slot 'notification' as |status type subject|}}
+ {{partial 'dc/acls/tokens/notifications'}}
+ {{/block-slot}}
+ {{#block-slot 'header'}}
+
+ Access Controls
+
+ {{#if isAuthorized }}
+ {{partial 'dc/acls/nav'}}
+ {{/if}}
+ {{/block-slot}}
+ {{#block-slot 'disabled'}}
+ {{partial 'dc/acls/disabled'}}
+ {{/block-slot}}
+ {{#block-slot 'authorization'}}
+ {{partial 'dc/acls/authorization'}}
+ {{/block-slot}}
+ {{#block-slot 'actions'}}
+
Create
+ {{/block-slot}}
+ {{#block-slot 'content'}}
+{{#if (gt items.length 0) }}
+
+{{/if}}
+ {{#if (find-by 'legacy' true items)}}
+
Update. We've upgraded our ACL system by allowing you to create reusable Policies, which you can then apply to Tokens. Read more about the change and learn how to upgrade your legacy Tokens in our documentation .
+ {{/if}}
+{{#if (gt filtered.length 0)}}
+ {{#tabular-collection
+ items=(sort-by 'CreateTime:desc' filtered) as |item index|
+ }}
+ {{#block-slot 'header'}}
+
Accessor ID
+
Scope
+
Description
+
Policies
+
+ {{/block-slot}}
+ {{#block-slot 'row'}}
+
+ {{truncate item.AccessorID 8 false}}
+
+
+ {{if item.Local 'local' 'global' }}
+
+
+ {{default item.Description item.Name}}
+
+
+ {{#if (token/is-legacy item) }}
+ Legacy tokens have embedded policies.
+ {{ else }}
+ {{#each item.Policies as |item|}}
+ {{item.Name}}
+ {{/each}}
+ {{/if}}
+
+ {{#if (eq item.AccessorID token.AccessorID)}}
+
Your token
+ {{/if}}
+ {{/block-slot}}
+ {{#block-slot 'actions' as |index change checked|}}
+ {{#confirmation-dialog confirming=false index=index message="Are you sure you want to delete this Token?"}}
+ {{#block-slot 'action' as |confirm|}}
+ {{#action-group index=index onchange=(action change) checked=(if (eq checked index) 'checked')}}
+
+ {{#if false}}
+
+ {{#copy-button-feedback title="Copy AccessorID to the clipboard" copy=item.AccessorID name="AccessorID"}}Copy AccessorID{{/copy-button-feedback}}
+
+ {{/if}}
+
+ Edit
+
+{{#if (not (token/is-legacy item))}}
+
+ Duplicate
+
+{{/if}}
+{{#if (eq item.AccessorID token.AccessorID) }}
+
+ Stop using
+
+{{else}}
+
+
+ Use
+
+{{/if}}
+{{#unless (token/is-anonymous item) }}
+
+ Delete
+
+{{/unless}}
+
+ {{/action-group}}
+ {{/block-slot}}
+ {{#block-slot 'dialog' as |execute cancel message name|}}
+
+ {{#if (eq name 'delete')}}
+ {{message}}
+ {{#if (eq item.AccessorID token.AccessorID)}}
+ Warning: This is the token you are currently using!
+ {{/if}}
+ {{else if (eq name 'logout')}}
+ Are you sure you want to stop using this ACL token? This will log you out.
+ {{else if (eq name 'use')}}
+ Are you sure you want to use this ACL token?
+ {{/if}}
+
+
+ {{#if (eq name 'delete')}}
+ Confirm Delete
+ {{else if (eq name 'logout')}}
+ Confirm Logout
+ {{ else if (eq name 'use')}}
+ Confirm Use
+ {{/if}}
+
+
Cancel
+ {{/block-slot}}
+ {{/confirmation-dialog}}
+ {{/block-slot}}
+ {{/tabular-collection}}
+{{else}}
+
+ There are no Tokens.
+
+{{/if}}
+ {{/block-slot}}
+{{/app-view}}
\ No newline at end of file
diff --git a/ui-v2/app/templates/dc/intentions/-form.hbs b/ui-v2/app/templates/dc/intentions/-form.hbs
index 97fa59d074..6a1123cbfd 100644
--- a/ui-v2/app/templates/dc/intentions/-form.hbs
+++ b/ui-v2/app/templates/dc/intentions/-form.hbs
@@ -67,11 +67,7 @@
Delete
{{/block-slot}}
{{#block-slot 'dialog' as |execute cancel message|}}
-
- {{message}}
-
-
Confirm Delete
-
Cancel
+ {{delete-confirmation message=message execute=execute cancel=cancel}}
{{/block-slot}}
{{/confirmation-dialog}}
{{/if}}
diff --git a/ui-v2/app/templates/dc/intentions/notifications.hbs b/ui-v2/app/templates/dc/intentions/-notifications.hbs
similarity index 100%
rename from ui-v2/app/templates/dc/intentions/notifications.hbs
rename to ui-v2/app/templates/dc/intentions/-notifications.hbs
diff --git a/ui-v2/app/templates/dc/intentions/index.hbs b/ui-v2/app/templates/dc/intentions/index.hbs
index 4208781cf1..bd509d85a8 100644
--- a/ui-v2/app/templates/dc/intentions/index.hbs
+++ b/ui-v2/app/templates/dc/intentions/index.hbs
@@ -68,11 +68,7 @@
{{/action-group}}
{{/block-slot}}
{{#block-slot 'dialog' as |execute cancel message|}}
-
- {{message}}
-
-
Confirm Delete
-
Cancel
+ {{delete-confirmation message=message execute=execute cancel=cancel}}
{{/block-slot}}
{{/confirmation-dialog}}
{{/block-slot}}
diff --git a/ui-v2/app/templates/dc/kv/-form.hbs b/ui-v2/app/templates/dc/kv/-form.hbs
index 7ff8232b3e..a500e3d3d9 100644
--- a/ui-v2/app/templates/dc/kv/-form.hbs
+++ b/ui-v2/app/templates/dc/kv/-form.hbs
@@ -9,10 +9,12 @@
{{/if}}
{{#if (or (eq (left-trim item.Key parent.Key) '') (not-eq (last item.Key) '/')) }}
-
-
- Code
-
+
+
+
+ Code
+
+
Value
{{#if json}}
@@ -36,11 +38,7 @@
Delete
{{/block-slot}}
{{#block-slot 'dialog' as |execute cancel message|}}
-
- {{message}}
-
- Confirm Delete
- Cancel
+ {{delete-confirmation message=message execute=execute cancel=cancel}}
{{/block-slot}}
{{/confirmation-dialog}}
{{/if}}
diff --git a/ui-v2/app/templates/dc/kv/index.hbs b/ui-v2/app/templates/dc/kv/index.hbs
index e1b2442634..dcc48c8e02 100644
--- a/ui-v2/app/templates/dc/kv/index.hbs
+++ b/ui-v2/app/templates/dc/kv/index.hbs
@@ -64,11 +64,7 @@
{{/action-group}}
{{/block-slot}}
{{#block-slot 'dialog' as |execute cancel message|}}
-
- {{message}}
-
- Confirm Delete
- Cancel
+ {{delete-confirmation message=message execute=execute cancel=cancel}}
{{/block-slot}}
{{/confirmation-dialog}}
{{/block-slot}}
diff --git a/ui-v2/app/templates/error.hbs b/ui-v2/app/templates/error.hbs
index d19729f043..a1e279d1fb 100644
--- a/ui-v2/app/templates/error.hbs
+++ b/ui-v2/app/templates/error.hbs
@@ -12,11 +12,9 @@
{{#block-slot 'content'}}
Consul returned an error.
- You may have visited a URL that is loading an unknown resource, so you can try going back to the root.
- If your ACL token was not found you can reset it, and then you will be redirected to the settings page to enter a new ACL token.
+ You may have visited a URL that is loading an unknown resource, so you can try going back to the root or try re-submitting your ACL Token/SecretID by going back to ACLs.
Try looking in our documentation
- Reset ACL token
Go back to root
{{/block-slot}}
{{/app-view}}
diff --git a/ui-v2/app/utils/acls-status.js b/ui-v2/app/utils/acls-status.js
new file mode 100644
index 0000000000..ae7546381c
--- /dev/null
+++ b/ui-v2/app/utils/acls-status.js
@@ -0,0 +1,48 @@
+// This is used by all acl routes to check whether
+// acls are enabled on the server, and whether the user
+// has a valid token
+// Right now this is very acl specific, but is likely to be
+// made a bit more less specific
+export default function(P = Promise) {
+ return function(obj) {
+ const propName = Object.keys(obj)[0];
+ const p = obj[propName];
+ let authorize;
+ let enable;
+ return {
+ isAuthorized: new P(function(resolve) {
+ authorize = function(bool) {
+ resolve(bool);
+ };
+ }),
+ isEnabled: new P(function(resolve) {
+ enable = function(bool) {
+ resolve(bool);
+ };
+ }),
+ [propName]: p
+ .catch(function(e) {
+ switch (e.errors[0].status) {
+ case '403':
+ enable(true);
+ authorize(false);
+ break;
+ case '401':
+ enable(false);
+ authorize(false);
+ break;
+ default:
+ enable(false);
+ authorize(false);
+ throw e;
+ }
+ return [];
+ })
+ .then(function(res) {
+ enable(true);
+ authorize(true);
+ return res;
+ }),
+ };
+ };
+}
diff --git a/ui-v2/app/utils/dom/click-first-anchor.js b/ui-v2/app/utils/dom/click-first-anchor.js
new file mode 100644
index 0000000000..0a8a6f23ff
--- /dev/null
+++ b/ui-v2/app/utils/dom/click-first-anchor.js
@@ -0,0 +1,30 @@
+const clickEvent = function() {
+ return new MouseEvent('click', {
+ bubbles: true,
+ cancelable: true,
+ view: window,
+ });
+};
+export default function(closest, click = clickEvent) {
+ // TODO: Decide whether we should use `e` for ease
+ // or `target`/`el`
+ return function(e) {
+ // click on row functionality
+ // so if you click the actual row but not a link
+ // find the first link and fire that instead
+ const name = e.target.nodeName.toLowerCase();
+ switch (name) {
+ case 'input':
+ case 'label':
+ case 'a':
+ case 'button':
+ return;
+ }
+ // TODO: why should this be restricted to a tr
+ // closest should probably be relaced with a finder function
+ const $a = closest('tr', e.target).querySelector('a');
+ if ($a) {
+ $a.dispatchEvent(click());
+ }
+ };
+}
diff --git a/ui-v2/app/utils/dom/closest.js b/ui-v2/app/utils/dom/closest.js
new file mode 100644
index 0000000000..d66380a046
--- /dev/null
+++ b/ui-v2/app/utils/dom/closest.js
@@ -0,0 +1,10 @@
+export default function(sel, el) {
+ // basic DOM closest utility to cope with no support
+ // TODO: instead of degrading gracefully
+ // add a while polyfill for closest
+ try {
+ return el.closest(sel);
+ } catch (e) {
+ return;
+ }
+}
diff --git a/ui-v2/app/utils/dom/normalize-event.js b/ui-v2/app/utils/dom/normalize-event.js
new file mode 100644
index 0000000000..b61f11b79c
--- /dev/null
+++ b/ui-v2/app/utils/dom/normalize-event.js
@@ -0,0 +1,8 @@
+export default function(e, value, target = {}) {
+ if (typeof e.target !== 'undefined') {
+ return e;
+ }
+ return {
+ target: { ...target, ...{ name: e, value: value } },
+ };
+}
diff --git a/ui-v2/app/utils/qsa-factory.js b/ui-v2/app/utils/dom/qsa-factory.js
similarity index 100%
rename from ui-v2/app/utils/qsa-factory.js
rename to ui-v2/app/utils/dom/qsa-factory.js
diff --git a/ui-v2/app/utils/dom/sibling.js b/ui-v2/app/utils/dom/sibling.js
new file mode 100644
index 0000000000..9c6cee85bd
--- /dev/null
+++ b/ui-v2/app/utils/dom/sibling.js
@@ -0,0 +1,10 @@
+export default function(el, name) {
+ let sibling = el;
+ while ((sibling = sibling.nextSibling)) {
+ if (sibling.nodeType === 1) {
+ if (sibling.nodeName.toLowerCase() === name) {
+ return sibling;
+ }
+ }
+ }
+}
diff --git a/ui-v2/app/utils/form/builder.js b/ui-v2/app/utils/form/builder.js
new file mode 100644
index 0000000000..b7a8e8c5fd
--- /dev/null
+++ b/ui-v2/app/utils/form/builder.js
@@ -0,0 +1,156 @@
+import { get, set, computed } from '@ember/object';
+import Changeset from 'ember-changeset';
+import lookupValidator from 'ember-changeset-validations';
+
+// Keep these here for now so forms are easy to make
+// TODO: Probably move this to utils/form/parse-element-name
+import parseElementName from 'consul-ui/utils/get-form-name-property';
+const defaultChangeset = function(data, validators) {
+ const changeset = new Changeset(data, lookupValidator(validators), validators);
+ // TODO: Currently supporting ember-data nicely like this
+ changeset.isSaving = computed('data.isSaving', function() {
+ return get(this, 'data.isSaving');
+ });
+ return changeset;
+};
+/**
+ * Form builder/Form factory (WIP)
+ * Deals with handling (generally change) events and updating data in response to the change
+ * in a typical data down event up manner
+ * validations are included currently using ember-changeset-validations
+ *
+ * @param {string} name - The name of the form, generally this is the name of your model
+ * Generally (until view building is complete) you should name your form elements as `name="modelName[property]"`
+ * or pass this name through using you action and create an Event-like object instead
+ * You can also just not set a name and use `name="property"`, but if you want to use combinations
+ * if multiple forms at least form children should use names
+ *
+ * @param {object} config - Form configuration object. Just a plain object to configure the form should be a hash
+ * with property names relating to the form data. Each property is the configuration for that model/data property
+ * currently the only supported property of these configuration objects is `type` which currently allows you to
+ * set a property as 'array-like'
+ */
+export default function(changeset = defaultChangeset, getFormNameProperty = parseElementName) {
+ return function(name = '', obj = {}) {
+ let _data;
+ const _name = name;
+ const _children = {};
+ let _validators = null;
+ // TODO make this into a class to reuse prototype
+ return {
+ getName: function() {
+ return _name;
+ },
+ setData: function(data) {
+ // Array check temporarily for when we get an empty array from repo.status
+ if (_validators && !Array.isArray(data)) {
+ _data = changeset(data, _validators);
+ } else {
+ _data = data;
+ }
+ return this;
+ },
+ getData: function() {
+ return _data;
+ },
+ add: function(child) {
+ _children[child.getName()] = child;
+ return this;
+ },
+ handleEvent: function(e) {
+ const target = e.target;
+ const parts = getFormNameProperty(target.name);
+ // split the form element name from `name[prop]`
+ const name = parts[0];
+ const prop = parts[1];
+ //
+ let config = obj;
+ // if the name (usually the name of the model) isn't this form, look at its children
+ if (name !== _name) {
+ if (this.has(name)) {
+ // is its a child form then use the child form
+ return this.form(name).handleEvent(e);
+ }
+ // should probably throw here, unless we support having a name
+ // even if you are referring to this form
+ config = config[name];
+ }
+ const data = this.getData();
+ // ember-data/changeset dance
+ const json = typeof data.toJSON === 'function' ? data.toJSON() : get(data, 'data').toJSON();
+ // if the form doesn't include a property then throw so it can be
+ // caught outside, therefore the user can deal with things that aren't in the data
+ if (!Object.keys(json).includes(prop)) {
+ const error = new Error(`${prop} property doesn't exist`);
+ error.target = target;
+ throw error;
+ }
+ // deal with the change of property
+ let currentValue = get(data, prop);
+ // if the value is an array-like or config says its an array
+ if (
+ Array.isArray(currentValue) ||
+ (typeof config[prop] !== 'undefined' &&
+ typeof config[prop].type === 'string' &&
+ config[prop].type.toLowerCase() === 'array')
+ ) {
+ // array specific set
+ if (currentValue == null) {
+ currentValue = [];
+ }
+ const method = target.checked ? 'pushObject' : 'removeObject';
+ currentValue[method](target.value);
+ set(data, prop, currentValue);
+ } else {
+ // deal with booleans
+ // but only booleans that aren't checkboxes/radios with values
+ if (
+ typeof target.checked !== 'undefined' &&
+ (target.value.toLowerCase() === 'on' || target.value.toLowerCase() === 'off')
+ ) {
+ set(data, prop, target.checked);
+ } else {
+ // text and non-boolean checkboxes/radios
+ set(data, prop, target.value);
+ }
+ }
+ // validate everything
+ return this.validate();
+ },
+ reset: function() {
+ const data = this.getData();
+ if (typeof data.rollbackAttributes === 'function') {
+ this.getData().rollbackAttributes();
+ }
+ return this;
+ },
+ setValidators: function(validators) {
+ _validators = validators;
+ return this;
+ },
+ validate: function() {
+ const data = this.getData();
+ // just pass along to the Changeset for now
+ if (typeof data.validate === 'function') {
+ data.validate();
+ }
+ return this;
+ },
+ addError: function(name, message) {
+ const data = this.getData();
+ if (typeof data.addError === 'function') {
+ data.addError(...arguments);
+ }
+ },
+ form: function(name) {
+ if (name == null) {
+ return this;
+ }
+ return _children[name];
+ },
+ has: function(name) {
+ return typeof _children[name] !== 'undefined';
+ },
+ };
+ };
+}
diff --git a/ui-v2/app/utils/get-form-name-property.js b/ui-v2/app/utils/get-form-name-property.js
new file mode 100644
index 0000000000..50379c6f37
--- /dev/null
+++ b/ui-v2/app/utils/get-form-name-property.js
@@ -0,0 +1,6 @@
+export default function(name) {
+ if (name.indexOf('[') !== -1) {
+ return name.match(/(.*)\[(.*)\]/).slice(1);
+ }
+ return ['', name];
+}
diff --git a/ui-v2/app/utils/http/status.js b/ui-v2/app/utils/http/status.js
index 0f2f3ead76..6b1a76873a 100644
--- a/ui-v2/app/utils/http/status.js
+++ b/ui-v2/app/utils/http/status.js
@@ -1,3 +1,4 @@
export const OK = 200;
export const UNAUTHORIZED = 401;
+export const FORBIDDEN = 403;
export const INTERNAL_SERVER_ERROR = 500;
diff --git a/ui-v2/app/utils/storage/local-storage.js b/ui-v2/app/utils/storage/local-storage.js
new file mode 100644
index 0000000000..0e17382f07
--- /dev/null
+++ b/ui-v2/app/utils/storage/local-storage.js
@@ -0,0 +1,45 @@
+export default function(
+ scheme = '',
+ storage = window.localStorage,
+ encode = JSON.stringify,
+ decode = JSON.parse
+) {
+ const prefix = `${scheme}:`;
+ return {
+ getValue: function(path) {
+ let value = storage.getItem(`${prefix}${path}`);
+ if (typeof value !== 'string') {
+ value = '""';
+ }
+ try {
+ value = decode(value);
+ } catch (e) {
+ value = '';
+ }
+ return value;
+ },
+ setValue: function(path, value) {
+ if (value === null) {
+ return this.removeValue(path);
+ }
+ try {
+ value = encode(value);
+ } catch (e) {
+ value = '""';
+ }
+ return storage.setItem(`${prefix}${path}`, value);
+ },
+ removeValue: function(path) {
+ return storage.removeItem(`${prefix}${path}`);
+ },
+ all: function() {
+ return Object.keys(storage).reduce((prev, item, i, arr) => {
+ if (item.indexOf(`${prefix}`) === 0) {
+ const key = item.substr(prefix.length);
+ prev[key] = this.getValue(key);
+ }
+ return prev;
+ }, {});
+ },
+ };
+}
diff --git a/ui-v2/app/utils/templatize.js b/ui-v2/app/utils/templatize.js
new file mode 100644
index 0000000000..4b76a11b9a
--- /dev/null
+++ b/ui-v2/app/utils/templatize.js
@@ -0,0 +1,3 @@
+export default function(arr = []) {
+ return arr.map(item => `template-${item}`);
+}
diff --git a/ui-v2/app/utils/update-array-object.js b/ui-v2/app/utils/update-array-object.js
new file mode 100644
index 0000000000..4bdee8c8be
--- /dev/null
+++ b/ui-v2/app/utils/update-array-object.js
@@ -0,0 +1,12 @@
+import { get, set } from '@ember/object';
+export default function(arr, item, prop, value) {
+ value = typeof value === 'undefined' ? get(item, prop) : value;
+ const current = arr.findBy(prop, value);
+ if (current) {
+ // TODO: This is reliant on changeset?
+ Object.keys(get(item, 'data')).forEach(function(prop) {
+ set(current, prop, get(item, prop));
+ });
+ return current;
+ }
+}
diff --git a/ui-v2/app/validations/policy.js b/ui-v2/app/validations/policy.js
new file mode 100644
index 0000000000..bae9ddab3f
--- /dev/null
+++ b/ui-v2/app/validations/policy.js
@@ -0,0 +1,4 @@
+import { validateFormat } from 'ember-changeset-validations/validators';
+export default {
+ Name: validateFormat({ regex: /^[A-Za-z0-9\-_]{1,128}$/ }),
+};
diff --git a/ui-v2/app/validations/token.js b/ui-v2/app/validations/token.js
new file mode 100644
index 0000000000..ff8b4c5632
--- /dev/null
+++ b/ui-v2/app/validations/token.js
@@ -0,0 +1 @@
+export default {};
diff --git a/ui-v2/ember-cli-build.js b/ui-v2/ember-cli-build.js
index 46e24575a3..098d7c1202 100644
--- a/ui-v2/ember-cli-build.js
+++ b/ui-v2/ember-cli-build.js
@@ -5,7 +5,8 @@ module.exports = function(defaults) {
const env = EmberApp.env();
const prodlike = ['production', 'staging'];
const isProd = env === 'production';
- const isProdLike = prodlike.indexOf(env) > -1;
+ // leave this in for now for when I start a proper staging env
+ // const isProdLike = prodlike.indexOf(env) > -1;
const sourcemaps = !isProd;
let app = new EmberApp(
Object.assign(
@@ -19,7 +20,7 @@ module.exports = function(defaults) {
includePolyfill: true
},
'ember-cli-string-helpers': {
- only: ['capitalize', 'lowercase']
+ only: ['capitalize', 'lowercase', 'truncate']
},
'ember-cli-math-helpers': {
only: ['div']
@@ -41,7 +42,7 @@ module.exports = function(defaults) {
},
},
'sassOptions': {
- implementation: require('dart-sass'),
+ implementation: require('node-sass'),
sourceMapEmbed: sourcemaps,
},
'autoprefixer': {
diff --git a/ui-v2/lib/startup/index.js b/ui-v2/lib/startup/index.js
index bb03b642d9..8d9b6e5a22 100644
--- a/ui-v2/lib/startup/index.js
+++ b/ui-v2/lib/startup/index.js
@@ -4,9 +4,9 @@
module.exports = {
name: 'startup',
contentFor: function(type, config) {
+ const enterprise = config.CONSUL_BINARY_TYPE !== 'oss' && config.CONSUL_BINARY_TYPE !== '';
switch (type) {
case 'body':
- const enterprise = config.CONSUL_BINARY_TYPE !== 'oss' && config.CONSUL_BINARY_TYPE !== '';
return ` ${
enterprise
? ` `
diff --git a/ui-v2/package.json b/ui-v2/package.json
index f303931756..7e7ab25070 100644
--- a/ui-v2/package.json
+++ b/ui-v2/package.json
@@ -34,7 +34,7 @@
]
},
"devDependencies": {
- "@hashicorp/consul-api-double": "^1.5.3",
+ "@hashicorp/consul-api-double": "^2.0.1",
"@hashicorp/ember-cli-api-double": "^1.3.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"base64-js": "^1.3.0",
@@ -87,6 +87,7 @@
"ivy-codemirror": "^2.1.0",
"lint-staged": "^7.0.0",
"loader.js": "^4.2.3",
+ "node-sass": "^4.9.3",
"prettier": "^1.10.2",
"svgo": "^1.0.5",
"text-encoding": "^0.6.4"
diff --git a/ui-v2/tests/acceptance/components/acl-filter.feature b/ui-v2/tests/acceptance/components/acl-filter.feature
index 6d90a68f78..6f775f8ea7 100644
--- a/ui-v2/tests/acceptance/components/acl-filter.feature
+++ b/ui-v2/tests/acceptance/components/acl-filter.feature
@@ -1,4 +1,5 @@
@setupApplicationTest
+@ignore
Feature: components / acl filter: Acl Filter
In order to find the acl token I'm looking for easier
As a user
diff --git a/ui-v2/tests/acceptance/dc/acls/index.feature b/ui-v2/tests/acceptance/dc/acls/index.feature
index bf0e8b1638..01d84fd6b1 100644
--- a/ui-v2/tests/acceptance/dc/acls/index.feature
+++ b/ui-v2/tests/acceptance/dc/acls/index.feature
@@ -1,14 +1,12 @@
@setupApplicationTest
-Feature: dc / acls / index: ACL List
-
- Scenario:
- Given 1 datacenter model with the value "dc-1"
- And 3 acl models
+Feature: acl forwarding
+ In order to arrive at a useful page when only specifying 'acls' in the url
+ As a user
+ I should be redirected to the tokens page
+ Scenario: Arriving at the acl index page with no other url info
+ Given 1 datacenter model with the value "datacenter"
When I visit the acls page for yaml
---
- dc: dc-1
+ dc: datacenter
---
- Then the url should be /dc-1/acls
- And I click actions on the acls
- Then I don't see delete on the acls
- Then I see 3 acl models
+ Then the url should be /datacenter/acls/tokens
diff --git a/ui-v2/tests/acceptance/dc/acls/list-order.feature b/ui-v2/tests/acceptance/dc/acls/list-order.feature
index a7c75d901f..4542db056a 100644
--- a/ui-v2/tests/acceptance/dc/acls/list-order.feature
+++ b/ui-v2/tests/acceptance/dc/acls/list-order.feature
@@ -1,4 +1,5 @@
@setupApplicationTest
+@ignore
Feature: dc / acls / list-order
In order to be able to find ACL tokens easier
As a user
diff --git a/ui-v2/tests/acceptance/dc/acls/policies/index.feature b/ui-v2/tests/acceptance/dc/acls/policies/index.feature
new file mode 100644
index 0000000000..448c84caf2
--- /dev/null
+++ b/ui-v2/tests/acceptance/dc/acls/policies/index.feature
@@ -0,0 +1,16 @@
+@setupApplicationTest
+Feature: dc / acls / policies / index: ACL Policy List
+
+ Scenario:
+ Given 1 datacenter model with the value "dc-1"
+ And 3 policy models
+ When I visit the policies page for yaml
+ ---
+ dc: dc-1
+ ---
+ Then the url should be /dc-1/acls/policies
+ Then I see 3 policy models
+@ignore
+ Scenario: The global-managment policy can't be deleted
+ And I click actions on the policies
+ Then I don't see delete on the policies
diff --git a/ui-v2/tests/acceptance/dc/acls/policies/update.feature b/ui-v2/tests/acceptance/dc/acls/policies/update.feature
new file mode 100644
index 0000000000..de9f77effe
--- /dev/null
+++ b/ui-v2/tests/acceptance/dc/acls/policies/update.feature
@@ -0,0 +1,46 @@
+@setupApplicationTest
+Feature: dc / acls / policies / update: ACL Policy Update
+ Background:
+ Given 1 datacenter model with the value "datacenter"
+ And 1 policy model from yaml
+ ---
+ ID: policy-id
+ ---
+ And 3 token models
+ When I visit the policy page for yaml
+ ---
+ dc: datacenter
+ policy: policy-id
+ ---
+ Then the url should be /datacenter/acls/policies/policy-id
+ Then I see 3 token models
+ Scenario: Update to [Name], [Rules], [Description]
+ Then I fill in the policy form with yaml
+ ---
+ Name: [Name]
+ Description: [Description]
+ Rules: [Rules]
+ ---
+ And I submit
+ Then a PUT request is made to "/v1/acl/policy/policy-id?dc=datacenter" with the body from yaml
+ ---
+ Name: [Name]
+ Description: [Description]
+ Rules: [Rules]
+ ---
+ Then the url should be /datacenter/acls/policies
+ And "[data-notification]" has the "notification-update" class
+ And "[data-notification]" has the "success" class
+ Where:
+ ------------------------------------------------------------------------------
+ | Name | Rules | Description |
+ | policy-name | key "foo" {policy = "read"} | policy-name description |
+ | policy_name | key "foo" {policy = "write"} | policy name description |
+ | policyName | key "foo" {policy = "read"} | policy%20name description |
+ ------------------------------------------------------------------------------
+ Scenario: There was an error saving the key
+ Given the url "/v1/acl/policy/policy-id" responds with a 500 status
+ And I submit
+ Then the url should be /datacenter/acls/policies/policy-id
+ Then "[data-notification]" has the "notification-update" class
+ And "[data-notification]" has the "error" class
diff --git a/ui-v2/tests/acceptance/dc/acls/policies/view-management.feature b/ui-v2/tests/acceptance/dc/acls/policies/view-management.feature
new file mode 100644
index 0000000000..d171cf3b2d
--- /dev/null
+++ b/ui-v2/tests/acceptance/dc/acls/policies/view-management.feature
@@ -0,0 +1,20 @@
+@setupApplicationTest
+Feature: dc / acls / policies / view managment: Readonly management policy
+ Background:
+ Given 1 datacenter model with the value "datacenter"
+ And 1 policy model from yaml
+ ---
+ ID: 00000000-0000-0000-0000-000000000001
+ ---
+ Scenario:
+ When I visit the policy page for yaml
+ ---
+ dc: datacenter
+ policy: 00000000-0000-0000-0000-000000000001
+ ---
+ Then the url should be /datacenter/acls/policies/00000000-0000-0000-0000-000000000001
+ Then I see the text "View Policy" in "h1"
+ Then I don't see confirmDelete
+ Then I don't see cancel
+ And I see tokens
+
diff --git a/ui-v2/tests/acceptance/dc/acls/tokens/anonymous-no-delete.feature b/ui-v2/tests/acceptance/dc/acls/tokens/anonymous-no-delete.feature
new file mode 100644
index 0000000000..eae5a0e240
--- /dev/null
+++ b/ui-v2/tests/acceptance/dc/acls/tokens/anonymous-no-delete.feature
@@ -0,0 +1,25 @@
+@setupApplicationTest
+Feature: dc / acls / tokens / anonymous no delete: The anonymous token has no delete buttons
+ Background:
+ Given 1 datacenter model with the value "dc-1"
+ And 1 token model from yaml
+ ---
+ AccessorID: 00000000-0000-0000-0000-000000000002
+ Policies: ~
+ ---
+ Scenario: On the listing page
+ When I visit the tokens page for yaml
+ ---
+ dc: dc-1
+ ---
+ Then the url should be /dc-1/acls/tokens
+ And I click actions on the tokens
+ Then I don't see delete on the tokens
+ Scenario: On the detail page
+ When I visit the token page for yaml
+ ---
+ dc: dc-1
+ token: 00000000-0000-0000-0000-000000000002
+ ---
+ Then the url should be /dc-1/acls/tokens/00000000-0000-0000-0000-000000000002
+ Then I don't see confirmDelete
diff --git a/ui-v2/tests/acceptance/dc/acls/tokens/index.feature b/ui-v2/tests/acceptance/dc/acls/tokens/index.feature
new file mode 100644
index 0000000000..b6b941b1d2
--- /dev/null
+++ b/ui-v2/tests/acceptance/dc/acls/tokens/index.feature
@@ -0,0 +1,13 @@
+@setupApplicationTest
+Feature: dc / acls / tokens / index: ACL Token List
+
+ Scenario:
+ Given 1 datacenter model with the value "dc-1"
+ And 3 token models
+ When I visit the tokens page for yaml
+ ---
+ dc: dc-1
+ ---
+ Then the url should be /dc-1/acls/tokens
+ And I click actions on the tokens
+ Then I see 3 token models
diff --git a/ui-v2/tests/acceptance/dc/acls/tokens/legacy/update.feature b/ui-v2/tests/acceptance/dc/acls/tokens/legacy/update.feature
new file mode 100644
index 0000000000..147abea8f7
--- /dev/null
+++ b/ui-v2/tests/acceptance/dc/acls/tokens/legacy/update.feature
@@ -0,0 +1,56 @@
+@setupApplicationTest
+Feature: dc / acls / tokens / legacy / update: ACL Token Update
+ Background:
+ Given 1 datacenter model with the value "datacenter"
+ And 1 token model from yaml
+ ---
+ AccessorID: key
+ SecretID: secret
+ Rules: ''
+ Type: client
+ Policies: ~
+ ---
+ When I visit the token page for yaml
+ ---
+ dc: datacenter
+ token: key
+ ---
+ Then the url should be /datacenter/acls/tokens/key
+ Scenario: Update to [Name]
+ Then I fill in with yaml
+ ---
+ name: [Name]
+ ---
+ # TODO: Remove this when I'm 100% sure token types are gone
+ # And I click "[value=[Type]]"
+ And I submit
+ Then a PUT request is made to "/v1/acl/update?dc=datacenter" with the body from yaml
+ # You can no longer edit Type but make sure it gets sent
+ ---
+ ID: secret
+ Name: [Name]
+ Type: client
+ ---
+ Then the url should be /datacenter/acls/tokens
+ And "[data-notification]" has the "notification-update" class
+ And "[data-notification]" has the "success" class
+ Where:
+ ---------------------------------------------
+ | Name | Rules |
+ | key-name | node "0" {policy = "read"} |
+ | key name | node "0" {policy = "write"} |
+ | key%20name | node "0" {policy = "read"} |
+ | utf8? | node "0" {policy = "write"} |
+ ---------------------------------------------
+ Scenario: There was an error saving the key
+ Given the url "/v1/acl/update" responds with a 500 status
+ And I submit
+ Then the url should be /datacenter/acls/tokens/key
+ Then "[data-notification]" has the "notification-update" class
+ And "[data-notification]" has the "error" class
+# @ignore
+ # Scenario: Rules can be edited/updated
+ # Then ok
+# @ignore
+ # Scenario: The feedback dialog says success or failure
+ # Then ok
diff --git a/ui-v2/tests/acceptance/dc/acls/tokens/policies/add-existing.feature b/ui-v2/tests/acceptance/dc/acls/tokens/policies/add-existing.feature
new file mode 100644
index 0000000000..4cbdeec827
--- /dev/null
+++ b/ui-v2/tests/acceptance/dc/acls/tokens/policies/add-existing.feature
@@ -0,0 +1,46 @@
+@setupApplicationTest
+Feature: dc / acls / tokens / policies: ACL Token add existing policy
+ Scenario:
+ Given 1 datacenter model with the value "datacenter"
+ And 1 token model from yaml
+ ---
+ AccessorID: key
+ Description: The Description
+ Policies: ~
+ ---
+ And 2 policy models from yaml
+ ---
+ - ID: policy-1
+ Name: Policy 1
+ - ID: policy-2
+ Name: Policy 2
+ ---
+ When I visit the token page for yaml
+ ---
+ dc: datacenter
+ token: key
+ ---
+ Then the url should be /datacenter/acls/tokens/key
+ And I click "[data-test-policy-element] .ember-power-select-trigger"
+ And I click ".ember-power-select-option:first-child"
+ And I see 1 policy model
+ And I click "[data-test-policy-element] .ember-power-select-trigger"
+ And I click ".ember-power-select-option:nth-child(1)"
+ And I see 2 policy models
+ Then I fill in with yaml
+ ---
+ Description: The Description
+ ---
+ And I submit
+ Then a PUT request is made to "/v1/acl/token/key?dc=datacenter" with the body from yaml
+ ---
+ Description: The Description
+ Policies:
+ - ID: policy-1
+ Name: Policy 1
+ - ID: policy-2
+ Name: Policy 2
+ ---
+ Then the url should be /datacenter/acls/tokens
+ And "[data-notification]" has the "notification-update" class
+ And "[data-notification]" has the "success" class
diff --git a/ui-v2/tests/acceptance/dc/acls/tokens/policies/add-new.feature b/ui-v2/tests/acceptance/dc/acls/tokens/policies/add-new.feature
new file mode 100644
index 0000000000..d7ee2b715b
--- /dev/null
+++ b/ui-v2/tests/acceptance/dc/acls/tokens/policies/add-new.feature
@@ -0,0 +1,45 @@
+@setupApplicationTest
+Feature: dc / acls / tokens / policies: Add new
+ Scenario:
+ Given 1 datacenter model with the value "datacenter"
+ And 1 token model from yaml
+ ---
+ AccessorID: key
+ Description: The Description
+ Policies: ~
+ ---
+ When I visit the token page for yaml
+ ---
+ dc: datacenter
+ token: key
+ ---
+ Then the url should be /datacenter/acls/tokens/key
+ And I click newPolicy
+ Then I fill in the policy form with yaml
+ ---
+ Name: New-Policy
+ Description: New Description
+ Rules: key {}
+ ---
+ And I click submit on the policyForm
+ Then the last PUT request was made to "/v1/acl/policy?dc=datacenter" with the body from yaml
+ ---
+ Name: New-Policy
+ Description: New Description
+ Rules: key {}
+ ---
+ And I submit
+ Then a PUT request is made to "/v1/acl/token/key?dc=datacenter" with the body from yaml
+ ---
+ Description: The Description
+ Policies:
+ - Name: New-Policy
+ ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
+ ---
+ Then the url should be /datacenter/acls/tokens
+ And "[data-notification]" has the "notification-update" class
+ And "[data-notification]" has the "success" class
+@pending:
+ Scenario: Click the cancel form
+ Then ok
+ # And I click cancel on the policyForm
diff --git a/ui-v2/tests/acceptance/dc/acls/tokens/policies/list.feature b/ui-v2/tests/acceptance/dc/acls/tokens/policies/list.feature
new file mode 100644
index 0000000000..8f70c32b21
--- /dev/null
+++ b/ui-v2/tests/acceptance/dc/acls/tokens/policies/list.feature
@@ -0,0 +1,22 @@
+@setupApplicationTest
+Feature: dc / acls / tokens / policies: List
+ Scenario:
+ Given 1 datacenter model with the value "datacenter"
+ And 1 token model from yaml
+ ---
+ AccessorID: key
+ Policies:
+ - Name: Policy
+ ID: 0000
+ - Name: Policy 2
+ ID: 0002
+ - Name: Policy 3
+ ID: 0003
+ ---
+ When I visit the token page for yaml
+ ---
+ dc: datacenter
+ token: key
+ ---
+ Then the url should be /datacenter/acls/tokens/key
+ Then I see 3 policy models
diff --git a/ui-v2/tests/acceptance/dc/acls/tokens/policies/remove.feature b/ui-v2/tests/acceptance/dc/acls/tokens/policies/remove.feature
new file mode 100644
index 0000000000..90b681ae25
--- /dev/null
+++ b/ui-v2/tests/acceptance/dc/acls/tokens/policies/remove.feature
@@ -0,0 +1,29 @@
+@setupApplicationTest
+Feature: dc / acls / tokens / policies: Remove
+ Scenario:
+ Given 1 datacenter model with the value "datacenter"
+ And 1 token model from yaml
+ ---
+ AccessorID: key
+ Policies:
+ - Name: Policy
+ ID: 00000000-0000-0000-0000-000000000001
+ ---
+ When I visit the token page for yaml
+ ---
+ dc: datacenter
+ token: key
+ ---
+ Then the url should be /datacenter/acls/tokens/key
+ And I see 1 policy model
+ And I click expand on the policies
+ And the last GET request was made to "/v1/acl/policy/00000000-0000-0000-0000-000000000001?dc=datacenter"
+ And I click delete on the policies
+ And I click confirmDelete on the policies
+ And I see 0 policy models
+ And I submit
+ Then a PUT request is made to "/v1/acl/token/key?dc=datacenter" with the body from yaml
+ ---
+ Policies: []
+ ---
+ Then the url should be /datacenter/acls/tokens
diff --git a/ui-v2/tests/acceptance/dc/acls/tokens/update.feature b/ui-v2/tests/acceptance/dc/acls/tokens/update.feature
new file mode 100644
index 0000000000..91be75d3b9
--- /dev/null
+++ b/ui-v2/tests/acceptance/dc/acls/tokens/update.feature
@@ -0,0 +1,40 @@
+@setupApplicationTest
+Feature: dc / acls / tokens / update: ACL Token Update
+ Background:
+ Given 1 datacenter model with the value "datacenter"
+ And 1 token model from yaml
+ ---
+ AccessorID: key
+ Policies: ~
+ ---
+ When I visit the token page for yaml
+ ---
+ dc: datacenter
+ token: key
+ ---
+ Then the url should be /datacenter/acls/tokens/key
+ Scenario: Update to [Name]
+ Then I fill in with yaml
+ ---
+ Description: [Description]
+ ---
+ And I submit
+ Then a PUT request is made to "/v1/acl/token/key?dc=datacenter" with the body from yaml
+ ---
+ Description: [Description]
+ ---
+ Then the url should be /datacenter/acls/tokens
+ And "[data-notification]" has the "notification-update" class
+ And "[data-notification]" has the "success" class
+ Where:
+ ---------------------------
+ | Description |
+ | description |
+ | description with spaces |
+ ---------------------------
+ Scenario: There was an error saving the key
+ Given the url "/v1/acl/token/key" responds with a 500 status
+ And I submit
+ Then the url should be /datacenter/acls/tokens/key
+ Then "[data-notification]" has the "notification-update" class
+ And "[data-notification]" has the "error" class
diff --git a/ui-v2/tests/acceptance/dc/acls/tokens/use.feature b/ui-v2/tests/acceptance/dc/acls/tokens/use.feature
new file mode 100644
index 0000000000..f0353772a9
--- /dev/null
+++ b/ui-v2/tests/acceptance/dc/acls/tokens/use.feature
@@ -0,0 +1,45 @@
+@setupApplicationTest
+Feature: dc / acls / tokens / use: Using an ACL token
+ Background:
+ Given 1 datacenter model with the value "datacenter"
+ And 1 token model from yaml
+ ---
+ AccessorID: token
+ SecretID: ee52203d-989f-4f7a-ab5a-2bef004164ca
+ ---
+ Scenario: Using an ACL token from the listing page
+ When I visit the tokens page for yaml
+ ---
+ dc: datacenter
+ ---
+ Then I have settings like yaml
+ ---
+ consul:token: ~
+ ---
+ And I click actions on the tokens
+ And I click use on the tokens
+ And I click confirmUse on the tokens
+ Then "[data-notification]" has the "notification-use" class
+ And "[data-notification]" has the "success" class
+ Then I have settings like yaml
+ ---
+ consul:token: "{\"AccessorID\":\"token\",\"SecretID\":\"ee52203d-989f-4f7a-ab5a-2bef004164ca\"}"
+ ---
+ Scenario: Using an ACL token from the detail page
+ When I visit the token page for yaml
+ ---
+ dc: datacenter
+ token: token
+ ---
+ Then I have settings like yaml
+ ---
+ consul:token: ~
+ ---
+ And I click use
+ And I click confirmUse
+ Then "[data-notification]" has the "notification-use" class
+ And "[data-notification]" has the "success" class
+ Then I have settings like yaml
+ ---
+ consul:token: "{\"AccessorID\":\"token\",\"SecretID\":\"ee52203d-989f-4f7a-ab5a-2bef004164ca\"}"
+ ---
diff --git a/ui-v2/tests/acceptance/dc/acls/update.feature b/ui-v2/tests/acceptance/dc/acls/update.feature
index 42a77b3e22..fdfa916c5e 100644
--- a/ui-v2/tests/acceptance/dc/acls/update.feature
+++ b/ui-v2/tests/acceptance/dc/acls/update.feature
@@ -1,4 +1,5 @@
@setupApplicationTest
+@ignore
Feature: dc / acls / update: ACL Update
Background:
Given 1 datacenter model with the value "datacenter"
diff --git a/ui-v2/tests/acceptance/dc/acls/use.feature b/ui-v2/tests/acceptance/dc/acls/use.feature
index cfc1e0eb0e..7e4e070f97 100644
--- a/ui-v2/tests/acceptance/dc/acls/use.feature
+++ b/ui-v2/tests/acceptance/dc/acls/use.feature
@@ -1,4 +1,5 @@
@setupApplicationTest
+@ignore
Feature: dc / acls / use: Using an ACL token
Background:
Given 1 datacenter model with the value "datacenter"
diff --git a/ui-v2/tests/acceptance/dc/intentions/update.feature b/ui-v2/tests/acceptance/dc/intentions/update.feature
index 7d46b636a5..d07fdcfbf8 100644
--- a/ui-v2/tests/acceptance/dc/intentions/update.feature
+++ b/ui-v2/tests/acceptance/dc/intentions/update.feature
@@ -12,16 +12,16 @@ Feature: dc / intentions / update: Intention Update
intention: intention-id
---
Then the url should be /datacenter/intentions/intention-id
- Scenario: Update to [Description], [Action], [Rules]
+ Scenario: Update to [Description], [Action]
Then I fill in with yaml
---
- Description: [Name]
+ Description: [Description]
---
And I click "[value=[Action]]"
And I submit
Then a PUT request is made to "/v1/connect/intentions/intention-id?dc=datacenter" with the body from yaml
---
- Description: [Name]
+ Description: [Description]
Action: [Action]
---
Then the url should be /datacenter/intentions
diff --git a/ui-v2/tests/acceptance/dc/list.feature b/ui-v2/tests/acceptance/dc/list.feature
index bd77f6c817..21b9db1eec 100644
--- a/ui-v2/tests/acceptance/dc/list.feature
+++ b/ui-v2/tests/acceptance/dc/list.feature
@@ -1,5 +1,5 @@
@setupApplicationTest
-Feature: List Models
+Feature: dc > list: List Models
Scenario: Listing [Model]
Given 1 datacenter model with the value "dc-1"
And 3 [Model] models
@@ -16,5 +16,7 @@ Feature: List Models
| service | services | /dc-1/services |
| node | nodes | /dc-1/nodes |
| kv | kvs | /dc-1/kv |
- | acl | acls | /dc-1/acls |
+ # | acl | acls | /dc-1/acls |
+ | token | tokens | /dc-1/acls/tokens |
+ | policy | policies | /dc-1/acls/policies |
-------------------------------------------------
diff --git a/ui-v2/tests/acceptance/deleting.feature b/ui-v2/tests/acceptance/deleting.feature
index 19fabce575..41fce5a37b 100644
--- a/ui-v2/tests/acceptance/deleting.feature
+++ b/ui-v2/tests/acceptance/deleting.feature
@@ -1,23 +1,26 @@
@setupApplicationTest
Feature: deleting: Deleting items with confirmations, success and error notifications
+ In order to delete items in consul
+ As a user
+ I should be able to delete items, get confirmation or a error notification that it has or has not been deleted
Background:
Given 1 datacenter model with the value "datacenter"
- Scenario: Deleting a [Model] from the [Model] listing page
- Given 1 [Model] model from json
+ Scenario: Deleting a [Edit] model from the [Listing] listing page
+ Given 1 [Edit] model from json
---
[Data]
---
- When I visit the [Model]s page for yaml
+ When I visit the [Listing] page for yaml
---
dc: datacenter
---
- And I click actions on the [Model]s
- And I click delete on the [Model]s
- And I click confirmDelete on the [Model]s
+ And I click actions on the [Listing]
+ And I click delete on the [Listing]
+ And I click confirmDelete on the [Listing]
Then a [Method] request is made to "[URL]"
And "[data-notification]" has the "notification-delete" class
And "[data-notification]" has the "success" class
- When I visit the [Model] page for yaml
+ When I visit the [Edit] page for yaml
---
dc: datacenter
[Slug]
@@ -28,12 +31,14 @@ Feature: deleting: Deleting items with confirmations, success and error notifica
And "[data-notification]" has the "notification-delete" class
And "[data-notification]" has the "error" class
Where:
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- | Model | Method | URL | Data | Slug |
- | acl | PUT | /v1/acl/destroy/something?dc=datacenter | {"Name": "something", "ID": "something"} | acl: something |
- | kv | DELETE | /v1/kv/key-name?dc=datacenter | ["key-name"] | kv: key-name |
- | intention | DELETE | /v1/connect/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter | {"SourceName": "name", "ID": "ee52203d-989f-4f7a-ab5a-2bef004164ca"} | intention: ee52203d-989f-4f7a-ab5a-2bef004164ca |
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ | Edit | Listing | Method | URL | Data | Slug |
+ # | acl | acls | PUT | /v1/acl/destroy/something?dc=datacenter | {"Name": "something", "ID": "something"} | acl: something |
+ | kv | kvs | DELETE | /v1/kv/key-name?dc=datacenter | ["key-name"] | kv: key-name |
+ | intention | intentions | DELETE | /v1/connect/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter | {"SourceName": "name", "ID": "ee52203d-989f-4f7a-ab5a-2bef004164ca"} | intention: ee52203d-989f-4f7a-ab5a-2bef004164ca |
+ | token | tokens | DELETE | /v1/acl/token/001fda31-194e-4ff1-a5ec-589abf2cafd0?dc=datacenter | {"AccessorID": "001fda31-194e-4ff1-a5ec-589abf2cafd0"} | token: 001fda31-194e-4ff1-a5ec-589abf2cafd0 |
+ | policy | policies | DELETE | /v1/acl/policy/1981f51d-301a-497b-89a0-05112ef02b4b?dc=datacenter | {"ID": "1981f51d-301a-497b-89a0-05112ef02b4b"} | policy: 1981f51d-301a-497b-89a0-05112ef02b4b |
+ ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Scenario: Deleting a [Model] from the [Model] detail page
When I visit the [Model] page for yaml
---
@@ -58,7 +63,7 @@ Feature: deleting: Deleting items with confirmations, success and error notifica
Where:
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Model | Method | URL | Data | Slug |
- | acl | PUT | /v1/acl/destroy/something?dc=datacenter | {"Name": "something", "ID": "something"} | acl: something |
+ # | acl | PUT | /v1/acl/destroy/something?dc=datacenter | {"Name": "something", "ID": "something"} | acl: something |
| kv | DELETE | /v1/kv/key-name?dc=datacenter | ["key-name"] | kv: key-name |
| intention | DELETE | /v1/connect/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter | {"SourceName": "name", "ID": "ee52203d-989f-4f7a-ab5a-2bef004164ca"} | intention: ee52203d-989f-4f7a-ab5a-2bef004164ca |
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
diff --git a/ui-v2/tests/acceptance/page-navigation.feature b/ui-v2/tests/acceptance/page-navigation.feature
index a032d1b4c0..79b5173df1 100644
--- a/ui-v2/tests/acceptance/page-navigation.feature
+++ b/ui-v2/tests/acceptance/page-navigation.feature
@@ -1,5 +1,8 @@
@setupApplicationTest
Feature: Page Navigation
+ In order to view all the data in consul
+ As a user
+ I should be able to visit every page and view data in a HTML from the API
Background:
Given 1 datacenter model with the value "dc-1"
Scenario: Visiting the index page
@@ -18,14 +21,14 @@ Feature: Page Navigation
Then the url should be [URL]
Then the last GET request was made to "[Endpoint]"
Where:
- ----------------------------------------------------------------------
- | Link | URL | Endpoint |
- | nodes | /dc-1/nodes | /v1/internal/ui/nodes?dc=dc-1 |
- | kvs | /dc-1/kv | /v1/kv/?keys&dc=dc-1&separator=%2F |
- | acls | /dc-1/acls | /v1/acl/list?dc=dc-1 |
- | intentions | /dc-1/intentions | /v1/connect/intentions?dc=dc-1 |
- | settings | /settings | /v1/catalog/datacenters |
- ----------------------------------------------------------------------
+ -----------------------------------------------------------------------
+ | Link | URL | Endpoint |
+ | nodes | /dc-1/nodes | /v1/internal/ui/nodes?dc=dc-1 |
+ | kvs | /dc-1/kv | /v1/kv/?keys&dc=dc-1&separator=%2F |
+ | acls | /dc-1/acls/tokens | /v1/acl/tokens?dc=dc-1 |
+ | intentions | /dc-1/intentions | /v1/connect/intentions?dc=dc-1 |
+ # | settings | /settings | /v1/catalog/datacenters |
+ -----------------------------------------------------------------------
Scenario: Clicking a [Item] in the [Model] listing and back again
When I visit the [Model] page for yaml
---
@@ -37,20 +40,25 @@ Feature: Page Navigation
And I click "[data-test-back]"
Then the url should be [Back]
Where:
- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- | Item | Model | URL | Endpoint | Back |
- | service | services | /dc-1/services/service-0 | /v1/health/service/service-0?dc=dc-1 | /dc-1/services |
- | node | nodes | /dc-1/nodes/node-0 | /v1/session/node/node-0?dc=dc-1 | /dc-1/nodes |
- | kv | kvs | /dc-1/kv/necessitatibus-0/edit | /v1/session/info/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=dc-1 | /dc-1/kv |
- | acl | acls | /dc-1/acls/anonymous | /v1/acl/info/anonymous?dc=dc-1 | /dc-1/acls |
- | intention | intentions | /dc-1/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca | /v1/internal/ui/services?dc=dc-1 | /dc-1/intentions |
- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ | Item | Model | URL | Endpoint | Back |
+ | service | services | /dc-1/services/service-0 | /v1/health/service/service-0?dc=dc-1 | /dc-1/services |
+ | node | nodes | /dc-1/nodes/node-0 | /v1/session/node/node-0?dc=dc-1 | /dc-1/nodes |
+ | kv | kvs | /dc-1/kv/necessitatibus-0/edit | /v1/session/info/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=dc-1 | /dc-1/kv |
+ # | acl | acls | /dc-1/acls/anonymous | /v1/acl/info/anonymous?dc=dc-1 | /dc-1/acls |
+ | intention | intentions | /dc-1/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca | /v1/internal/ui/services?dc=dc-1 | /dc-1/intentions |
+ | token | tokens | /dc-1/acls/tokens/7ca5cd4d-4a7e-459d-b812-bb4078cecbd4 | /v1/acl/policies?dc=dc-1 | /dc-1/acls/tokens |
+ | policy | policies | /dc-1/acls/policies/ee52203d-989f-4f7a-ab5a-2bef004164ca | /v1/acl/tokens?policy=ee52203d-989f-4f7a-ab5a-2bef004164ca&dc=dc-1 | /dc-1/acls/policies |
+ # | token | tokens | /dc-1/acls/tokens/00000000-0000-0000-0000-000000000000 | /v1/acl/token/00000000-0000-0000-0000-000000000000?dc=dc-1 | /dc-1/acls/tokens |
+ # | policy | policies | /dc-1/acls/policies/ee52203d-989f-4f7a-ab5a-2bef004164ca | /v1/acl/policy/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=dc-1 | /dc-1/acls/policies |
+ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Scenario: The node detail page calls the correct API endpoints
When I visit the node page for yaml
---
dc: dc-1
node: node-0
---
+ Then the url should be /dc-1/nodes/node-0
Then the last GET requests were like yaml
---
- /v1/catalog/datacenters
@@ -64,18 +72,31 @@ Feature: Page Navigation
dc: dc-1
kv: keyname
---
+ Then the url should be /dc-1/kv/keyname/edit
Then the last GET requests were like yaml
---
- /v1/catalog/datacenters
- /v1/kv/keyname?dc=dc-1
- /v1/session/info/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=dc-1
---
+ Scenario: The policies page/tab calls the correct API endpoints
+ When I visit the policies page for yaml
+ ---
+ dc: dc-1
+ ---
+ Then the url should be /dc-1/acls/policies
+ Then the last GET requests were like yaml
+ ---
+ - /v1/catalog/datacenters
+ - /v1/acl/policies?dc=dc-1
+ ---
Scenario: The intention detail page calls the correct API endpoints
When I visit the intention page for yaml
---
dc: dc-1
intention: intention
- ---
+ ---
+ Then the url should be /dc-1/intentions/intention
Then the last GET requests were like yaml
---
- /v1/catalog/datacenters
@@ -83,7 +104,7 @@ Feature: Page Navigation
- /v1/internal/ui/services?dc=dc-1
---
- Scenario: Clicking a [Item] in the [Model] listing and canceling
+ Scenario: Clicking a [Item] in the [Model] listing and cancelling
When I visit the [Model] page for yaml
---
dc: dc-1
@@ -96,7 +117,7 @@ Feature: Page Navigation
--------------------------------------------------------------------------------------------------------
| Item | Model | URL | Back |
| kv | kvs | /dc-1/kv/necessitatibus-0/edit | /dc-1/kv |
- | acl | acls | /dc-1/acls/anonymous | /dc-1/acls |
+ # | acl | acls | /dc-1/acls/anonymous | /dc-1/acls |
| intention | intentions | /dc-1/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca | /dc-1/intentions |
--------------------------------------------------------------------------------------------------------
@ignore
@@ -112,12 +133,14 @@ Feature: Page Navigation
And I click "[data-test-back]"
Then the url should be [Back]
Where:
- ------------------------------------------------------------------------
- | Item | Model | URL | Back |
- | kv | kvs | /dc-1/kv/create | /dc-1/kv |
- | acl | acls | /dc-1/acls/create | /dc-1/acls |
- | intention | intentions | /dc-1/intentions/create | /dc-1/intentions |
- ------------------------------------------------------------------------
+ -----------------------------------------------------------------------------
+ | Item | Model | URL | Back |
+ | kv | kvs | /dc-1/kv/create | /dc-1/kv |
+ # | acl | acls | /dc-1/acls/create | /dc-1/acls |
+ | intention | intentions | /dc-1/intentions/create | /dc-1/intentions |
+ | token | tokens | /dc-1/acls/tokens/create | /dc-1/acls/tokens |
+ | policy | policies | /dc-1/acls/policies/create | /dc-1/acls/policies |
+ -----------------------------------------------------------------------------
@ignore
Scenario: Using I click on should change the currentPage ^
Then ok
diff --git a/ui-v2/tests/acceptance/settings/update.feature b/ui-v2/tests/acceptance/settings/update.feature
index 46d5b8feb7..680c69577f 100644
--- a/ui-v2/tests/acceptance/settings/update.feature
+++ b/ui-v2/tests/acceptance/settings/update.feature
@@ -1,4 +1,5 @@
@setupApplicationTest
+@ignore
Feature: settings / update: Update Settings
In order to authenticate with an ACL token
As a user
@@ -9,12 +10,12 @@ Feature: settings / update: Update Settings
Then the url should be /settings
Then I have settings like yaml
---
- token: ~
+ consul:token: ~
---
And I submit
Then I have settings like yaml
---
- token: ''
+ consul:token: ''
---
And the url should be /settings
And "[data-notification]" has the "notification-update" class
diff --git a/ui-v2/tests/acceptance/steps/dc/acls/policies/index-steps.js b/ui-v2/tests/acceptance/steps/dc/acls/policies/index-steps.js
new file mode 100644
index 0000000000..7dbc46ae17
--- /dev/null
+++ b/ui-v2/tests/acceptance/steps/dc/acls/policies/index-steps.js
@@ -0,0 +1,11 @@
+import steps from '../../../steps';
+
+// step definitions that are shared between features should be moved to the
+// tests/acceptance/steps/steps.js file
+
+export default function(assert) {
+ return steps(assert)
+ .then('I should find a file', function() {
+ assert.ok(true, this.step);
+ });
+}
diff --git a/ui-v2/tests/acceptance/steps/dc/acls/policies/update-steps.js b/ui-v2/tests/acceptance/steps/dc/acls/policies/update-steps.js
new file mode 100644
index 0000000000..7dbc46ae17
--- /dev/null
+++ b/ui-v2/tests/acceptance/steps/dc/acls/policies/update-steps.js
@@ -0,0 +1,11 @@
+import steps from '../../../steps';
+
+// step definitions that are shared between features should be moved to the
+// tests/acceptance/steps/steps.js file
+
+export default function(assert) {
+ return steps(assert)
+ .then('I should find a file', function() {
+ assert.ok(true, this.step);
+ });
+}
diff --git a/ui-v2/tests/acceptance/steps/dc/acls/policies/view-management-steps.js b/ui-v2/tests/acceptance/steps/dc/acls/policies/view-management-steps.js
new file mode 100644
index 0000000000..7dbc46ae17
--- /dev/null
+++ b/ui-v2/tests/acceptance/steps/dc/acls/policies/view-management-steps.js
@@ -0,0 +1,11 @@
+import steps from '../../../steps';
+
+// step definitions that are shared between features should be moved to the
+// tests/acceptance/steps/steps.js file
+
+export default function(assert) {
+ return steps(assert)
+ .then('I should find a file', function() {
+ assert.ok(true, this.step);
+ });
+}
diff --git a/ui-v2/tests/acceptance/steps/dc/acls/tokens/anonymous-no-delete-steps.js b/ui-v2/tests/acceptance/steps/dc/acls/tokens/anonymous-no-delete-steps.js
new file mode 100644
index 0000000000..9bfbe9ac9b
--- /dev/null
+++ b/ui-v2/tests/acceptance/steps/dc/acls/tokens/anonymous-no-delete-steps.js
@@ -0,0 +1,10 @@
+import steps from '../../../steps';
+
+// step definitions that are shared between features should be moved to the
+// tests/acceptance/steps/steps.js file
+
+export default function(assert) {
+ return steps(assert).then('I should find a file', function() {
+ assert.ok(true, this.step);
+ });
+}
diff --git a/ui-v2/tests/acceptance/steps/dc/acls/tokens/index-steps.js b/ui-v2/tests/acceptance/steps/dc/acls/tokens/index-steps.js
new file mode 100644
index 0000000000..7dbc46ae17
--- /dev/null
+++ b/ui-v2/tests/acceptance/steps/dc/acls/tokens/index-steps.js
@@ -0,0 +1,11 @@
+import steps from '../../../steps';
+
+// step definitions that are shared between features should be moved to the
+// tests/acceptance/steps/steps.js file
+
+export default function(assert) {
+ return steps(assert)
+ .then('I should find a file', function() {
+ assert.ok(true, this.step);
+ });
+}
diff --git a/ui-v2/tests/acceptance/steps/dc/acls/tokens/legacy/update-steps.js b/ui-v2/tests/acceptance/steps/dc/acls/tokens/legacy/update-steps.js
new file mode 100644
index 0000000000..f2aad107ec
--- /dev/null
+++ b/ui-v2/tests/acceptance/steps/dc/acls/tokens/legacy/update-steps.js
@@ -0,0 +1,10 @@
+import steps from '../../../../steps';
+
+// step definitions that are shared between features should be moved to the
+// tests/acceptance/steps/steps.js file
+
+export default function(assert) {
+ return steps(assert).then('I should find a file', function() {
+ assert.ok(true, this.step);
+ });
+}
diff --git a/ui-v2/tests/acceptance/steps/dc/acls/tokens/policies/add-existing-steps.js b/ui-v2/tests/acceptance/steps/dc/acls/tokens/policies/add-existing-steps.js
new file mode 100644
index 0000000000..4ce41c3555
--- /dev/null
+++ b/ui-v2/tests/acceptance/steps/dc/acls/tokens/policies/add-existing-steps.js
@@ -0,0 +1,11 @@
+import steps from '../../../../steps';
+
+// step definitions that are shared between features should be moved to the
+// tests/acceptance/steps/steps.js file
+
+export default function(assert) {
+ return steps(assert)
+ .then('I should find a file', function() {
+ assert.ok(true, this.step);
+ });
+}
diff --git a/ui-v2/tests/acceptance/steps/dc/acls/tokens/policies/add-new-steps.js b/ui-v2/tests/acceptance/steps/dc/acls/tokens/policies/add-new-steps.js
new file mode 100644
index 0000000000..550f688585
--- /dev/null
+++ b/ui-v2/tests/acceptance/steps/dc/acls/tokens/policies/add-new-steps.js
@@ -0,0 +1,10 @@
+import steps from '../../../../steps';
+
+// step definitions that are shared between features should be moved to the
+// tests/acceptance/steps/steps.js file
+
+export default function(assert) {
+ return steps(assert).then('I should find a file', function() {
+ assert.ok(true, this.step);
+ });
+}
diff --git a/ui-v2/tests/acceptance/steps/dc/acls/tokens/policies/list-steps.js b/ui-v2/tests/acceptance/steps/dc/acls/tokens/policies/list-steps.js
new file mode 100644
index 0000000000..4ce41c3555
--- /dev/null
+++ b/ui-v2/tests/acceptance/steps/dc/acls/tokens/policies/list-steps.js
@@ -0,0 +1,11 @@
+import steps from '../../../../steps';
+
+// step definitions that are shared between features should be moved to the
+// tests/acceptance/steps/steps.js file
+
+export default function(assert) {
+ return steps(assert)
+ .then('I should find a file', function() {
+ assert.ok(true, this.step);
+ });
+}
diff --git a/ui-v2/tests/acceptance/steps/dc/acls/tokens/policies/remove-steps.js b/ui-v2/tests/acceptance/steps/dc/acls/tokens/policies/remove-steps.js
new file mode 100644
index 0000000000..4ce41c3555
--- /dev/null
+++ b/ui-v2/tests/acceptance/steps/dc/acls/tokens/policies/remove-steps.js
@@ -0,0 +1,11 @@
+import steps from '../../../../steps';
+
+// step definitions that are shared between features should be moved to the
+// tests/acceptance/steps/steps.js file
+
+export default function(assert) {
+ return steps(assert)
+ .then('I should find a file', function() {
+ assert.ok(true, this.step);
+ });
+}
diff --git a/ui-v2/tests/acceptance/steps/dc/acls/tokens/update-steps.js b/ui-v2/tests/acceptance/steps/dc/acls/tokens/update-steps.js
new file mode 100644
index 0000000000..9bfbe9ac9b
--- /dev/null
+++ b/ui-v2/tests/acceptance/steps/dc/acls/tokens/update-steps.js
@@ -0,0 +1,10 @@
+import steps from '../../../steps';
+
+// step definitions that are shared between features should be moved to the
+// tests/acceptance/steps/steps.js file
+
+export default function(assert) {
+ return steps(assert).then('I should find a file', function() {
+ assert.ok(true, this.step);
+ });
+}
diff --git a/ui-v2/tests/acceptance/steps/dc/acls/tokens/use-steps.js b/ui-v2/tests/acceptance/steps/dc/acls/tokens/use-steps.js
new file mode 100644
index 0000000000..7dbc46ae17
--- /dev/null
+++ b/ui-v2/tests/acceptance/steps/dc/acls/tokens/use-steps.js
@@ -0,0 +1,11 @@
+import steps from '../../../steps';
+
+// step definitions that are shared between features should be moved to the
+// tests/acceptance/steps/steps.js file
+
+export default function(assert) {
+ return steps(assert)
+ .then('I should find a file', function() {
+ assert.ok(true, this.step);
+ });
+}
diff --git a/ui-v2/tests/acceptance/token-header.feature b/ui-v2/tests/acceptance/token-header.feature
index 6ca14431c8..87271925dd 100644
--- a/ui-v2/tests/acceptance/token-header.feature
+++ b/ui-v2/tests/acceptance/token-header.feature
@@ -1,4 +1,5 @@
@setupApplicationTest
+@ignore
Feature: token headers
In order to authenticate with tokens
As a user
diff --git a/ui-v2/tests/helpers/api.js b/ui-v2/tests/helpers/api.js
index b2a38d460c..651ae96da4 100644
--- a/ui-v2/tests/helpers/api.js
+++ b/ui-v2/tests/helpers/api.js
@@ -21,6 +21,7 @@ export const get = function(_url, options = { headers: { cookie: {} } }) {
path: url.pathname,
url: url.href,
cookies: options.headers.cookie || {},
+ headers: {},
query: [...url.searchParams.keys()].reduce(function(prev, key) {
prev[key] = url.searchParams.get(key);
return prev;
diff --git a/ui-v2/tests/helpers/set-cookies.js b/ui-v2/tests/helpers/set-cookies.js
index 61f1e95c2b..0cfa58313b 100644
--- a/ui-v2/tests/helpers/set-cookies.js
+++ b/ui-v2/tests/helpers/set-cookies.js
@@ -1,5 +1,6 @@
export default function(type, count, obj) {
var key = '';
+ obj['CONSUL_ACLS_ENABLE'] = 1;
switch (type) {
case 'dc':
key = 'CONSUL_DATACENTER_COUNT';
@@ -15,7 +16,7 @@ export default function(type, count, obj) {
break;
case 'acl':
key = 'CONSUL_ACL_COUNT';
- obj['CONSUL_ENABLE_ACLS'] = 1;
+ obj['CONSUL_ACLS_ENABLE'] = 1;
break;
case 'session':
key = 'CONSUL_SESSION_COUNT';
@@ -23,6 +24,14 @@ export default function(type, count, obj) {
case 'intention':
key = 'CONSUL_INTENTION_COUNT';
break;
+ case 'policy':
+ key = 'CONSUL_POLICY_COUNT';
+ obj['CONSUL_ACLS_ENABLE'] = 1;
+ break;
+ case 'token':
+ key = 'CONSUL_TOKEN_COUNT';
+ obj['CONSUL_ACLS_ENABLE'] = 1;
+ break;
}
if (key) {
obj[key] = count;
diff --git a/ui-v2/tests/helpers/type-to-url.js b/ui-v2/tests/helpers/type-to-url.js
index 57fbbe3538..1b217dcb4d 100644
--- a/ui-v2/tests/helpers/type-to-url.js
+++ b/ui-v2/tests/helpers/type-to-url.js
@@ -19,6 +19,12 @@ export default function(type) {
case 'session':
requests = ['/v1/session/node/'];
break;
+ case 'policy':
+ requests = ['/v1/acl/policies', '/v1/acl/policy/'];
+ break;
+ case 'token':
+ requests = ['/v1/acl/tokens', '/v1/acl/token/'];
+ break;
}
// TODO: An instance of URL should come in here (instead of 2 args)
return function(url, method) {
diff --git a/ui-v2/tests/integration/adapters/policy/response-test.js b/ui-v2/tests/integration/adapters/policy/response-test.js
new file mode 100644
index 0000000000..dc90fa1079
--- /dev/null
+++ b/ui-v2/tests/integration/adapters/policy/response-test.js
@@ -0,0 +1,38 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+import { get } from 'consul-ui/tests/helpers/api';
+module('Integration | Adapter | policy | response', function(hooks) {
+ setupTest(hooks);
+ const dc = 'dc-1';
+ const id = 'policy-name';
+ test('handleResponse returns the correct data for list endpoint', function(assert) {
+ const adapter = this.owner.lookup('adapter:policy');
+ const request = {
+ url: `/v1/acl/policies?dc=${dc}`,
+ };
+ return get(request.url).then(function(payload) {
+ const expected = payload.map(item =>
+ Object.assign({}, item, {
+ Datacenter: dc,
+ uid: `["${dc}","${item.ID}"]`,
+ })
+ );
+ const actual = adapter.handleResponse(200, {}, payload, request);
+ assert.deepEqual(actual, expected);
+ });
+ });
+ test('handleResponse returns the correct data for item endpoint', function(assert) {
+ const adapter = this.owner.lookup('adapter:policy');
+ const request = {
+ url: `/v1/acl/policy/${id}?dc=${dc}`,
+ };
+ return get(request.url).then(function(payload) {
+ const expected = Object.assign({}, payload, {
+ Datacenter: dc,
+ uid: `["${dc}","${id}"]`,
+ });
+ const actual = adapter.handleResponse(200, {}, payload, request);
+ assert.deepEqual(actual, expected);
+ });
+ });
+});
diff --git a/ui-v2/tests/integration/adapters/policy/url-test.js b/ui-v2/tests/integration/adapters/policy/url-test.js
new file mode 100644
index 0000000000..4becb15d14
--- /dev/null
+++ b/ui-v2/tests/integration/adapters/policy/url-test.js
@@ -0,0 +1,76 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+import makeAttrable from 'consul-ui/utils/makeAttrable';
+module('Integration | Adapter | policy | url', function(hooks) {
+ setupTest(hooks);
+ const dc = 'dc-1';
+ const id = 'policy-name';
+ test('urlForQuery returns the correct url', function(assert) {
+ const adapter = this.owner.lookup('adapter:policy');
+ const expected = `/v1/acl/policies?dc=${dc}`;
+ const actual = adapter.urlForQuery({
+ dc: dc,
+ });
+ assert.equal(actual, expected);
+ });
+ test('urlForQueryRecord returns the correct url', function(assert) {
+ const adapter = this.owner.lookup('adapter:policy');
+ const expected = `/v1/acl/policy/${id}?dc=${dc}`;
+ const actual = adapter.urlForQueryRecord({
+ dc: dc,
+ id: id,
+ });
+ assert.equal(actual, expected);
+ });
+ test("urlForQueryRecord throws if you don't specify an id", function(assert) {
+ const adapter = this.owner.lookup('adapter:policy');
+ assert.throws(function() {
+ adapter.urlForQueryRecord({
+ dc: dc,
+ });
+ });
+ });
+ test('urlForCreateRecord returns the correct url', function(assert) {
+ const adapter = this.owner.lookup('adapter:policy');
+ const expected = `/v1/acl/policy?dc=${dc}`;
+ const actual = adapter.urlForCreateRecord(
+ 'policy',
+ makeAttrable({
+ Datacenter: dc,
+ })
+ );
+ assert.equal(actual, expected);
+ });
+ test('urlForUpdateRecord returns the correct url', function(assert) {
+ const adapter = this.owner.lookup('adapter:policy');
+ const expected = `/v1/acl/policy/${id}?dc=${dc}`;
+ const actual = adapter.urlForUpdateRecord(
+ id,
+ 'policy',
+ makeAttrable({
+ Datacenter: dc,
+ ID: id,
+ })
+ );
+ assert.equal(actual, expected);
+ });
+ test('urlForDeleteRecord returns the correct url', function(assert) {
+ const adapter = this.owner.lookup('adapter:policy');
+ const expected = `/v1/acl/policy/${id}?dc=${dc}`;
+ const actual = adapter.urlForDeleteRecord(
+ id,
+ 'policy',
+ makeAttrable({
+ Datacenter: dc,
+ ID: id,
+ })
+ );
+ assert.equal(actual, expected);
+ });
+ test('urlForTranslateRecord returns the correct url', function(assert) {
+ const adapter = this.owner.lookup('adapter:policy');
+ const expected = `/v1/acl/policy/translate`;
+ const actual = adapter.urlForTranslateRecord('translate');
+ assert.equal(actual, expected);
+ });
+});
diff --git a/ui-v2/tests/integration/adapters/token/response-test.js b/ui-v2/tests/integration/adapters/token/response-test.js
new file mode 100644
index 0000000000..0a60965b8d
--- /dev/null
+++ b/ui-v2/tests/integration/adapters/token/response-test.js
@@ -0,0 +1,38 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+import { get } from 'consul-ui/tests/helpers/api';
+module('Integration | Adapter | token | response', function(hooks) {
+ setupTest(hooks);
+ const dc = 'dc-1';
+ const id = 'token-name';
+ test('handleResponse returns the correct data for list endpoint', function(assert) {
+ const adapter = this.owner.lookup('adapter:token');
+ const request = {
+ url: `/v1/acl/tokens?dc=${dc}`,
+ };
+ return get(request.url).then(function(payload) {
+ const expected = payload.map(item =>
+ Object.assign({}, item, {
+ Datacenter: dc,
+ uid: `["${dc}","${item.AccessorID}"]`,
+ })
+ );
+ const actual = adapter.handleResponse(200, {}, payload, request);
+ assert.deepEqual(actual, expected);
+ });
+ });
+ test('handleResponse returns the correct data for item endpoint', function(assert) {
+ const adapter = this.owner.lookup('adapter:token');
+ const request = {
+ url: `/v1/acl/token/${id}?dc=${dc}`,
+ };
+ return get(request.url).then(function(payload) {
+ const expected = Object.assign({}, payload, {
+ Datacenter: dc,
+ uid: `["${dc}","${id}"]`,
+ });
+ const actual = adapter.handleResponse(200, {}, payload, request);
+ assert.deepEqual(actual, expected);
+ });
+ });
+});
diff --git a/ui-v2/tests/integration/adapters/token/url-test.js b/ui-v2/tests/integration/adapters/token/url-test.js
new file mode 100644
index 0000000000..92dfa3292b
--- /dev/null
+++ b/ui-v2/tests/integration/adapters/token/url-test.js
@@ -0,0 +1,84 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+import makeAttrable from 'consul-ui/utils/makeAttrable';
+module('Integration | Adapter | token | url', function(hooks) {
+ setupTest(hooks);
+ const dc = 'dc-1';
+ const id = 'policy-id';
+ test('urlForQuery returns the correct url', function(assert) {
+ const adapter = this.owner.lookup('adapter:token');
+ const expected = `/v1/acl/tokens?dc=${dc}`;
+ const actual = adapter.urlForQuery({
+ dc: dc,
+ });
+ assert.equal(actual, expected);
+ });
+ test('urlForQueryRecord returns the correct url', function(assert) {
+ const adapter = this.owner.lookup('adapter:token');
+ const expected = `/v1/acl/token/${id}?dc=${dc}`;
+ const actual = adapter.urlForQueryRecord({
+ dc: dc,
+ id: id,
+ });
+ assert.equal(actual, expected);
+ });
+ test("urlForQueryRecord throws if you don't specify an id", function(assert) {
+ const adapter = this.owner.lookup('adapter:token');
+ assert.throws(function() {
+ adapter.urlForQueryRecord({
+ dc: dc,
+ });
+ });
+ });
+ test('urlForCreateRecord returns the correct url', function(assert) {
+ const adapter = this.owner.lookup('adapter:token');
+ const expected = `/v1/acl/token?dc=${dc}`;
+ const actual = adapter.urlForCreateRecord(
+ 'token',
+ makeAttrable({
+ Datacenter: dc,
+ })
+ );
+ assert.equal(actual, expected);
+ });
+ test('urlForUpdateRecord returns the correct url (without Rules it uses the v2 API)', function(assert) {
+ const adapter = this.owner.lookup('adapter:token');
+ const expected = `/v1/acl/token/${id}?dc=${dc}`;
+ const actual = adapter.urlForUpdateRecord(
+ id,
+ 'token',
+ makeAttrable({
+ Datacenter: dc,
+ AccessorID: id,
+ })
+ );
+ assert.equal(actual, expected);
+ });
+ test('urlForUpdateRecord returns the correct url (with Rules it uses the v1 API)', function(assert) {
+ const adapter = this.owner.lookup('adapter:token');
+ const expected = `/v1/acl/update?dc=${dc}`;
+ const actual = adapter.urlForUpdateRecord(
+ id,
+ 'token',
+ makeAttrable({
+ Rules: 'key {}',
+ Datacenter: dc,
+ AccessorID: id,
+ })
+ );
+ assert.equal(actual, expected);
+ });
+ test('urlForDeleteRecord returns the correct url', function(assert) {
+ const adapter = this.owner.lookup('adapter:token');
+ const expected = `/v1/acl/token/${id}?dc=${dc}`;
+ const actual = adapter.urlForDeleteRecord(
+ id,
+ 'token',
+ makeAttrable({
+ Datacenter: dc,
+ AccessorID: id,
+ })
+ );
+ assert.equal(actual, expected);
+ });
+});
diff --git a/ui-v2/tests/integration/components/copy-button-feedback-test.js b/ui-v2/tests/integration/components/copy-button-feedback-test.js
new file mode 100644
index 0000000000..19c4bfd27f
--- /dev/null
+++ b/ui-v2/tests/integration/components/copy-button-feedback-test.js
@@ -0,0 +1,32 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('copy-button-feedback', 'Integration | Component | copy button feedback', {
+ integration: true,
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{copy-button-feedback value='Click Me'}}`);
+
+ assert.equal(
+ this.$()
+ .text()
+ .trim(),
+ 'Click Me'
+ );
+
+ // Template block usage:
+ this.render(hbs`
+ {{#copy-button-feedback}}Click Me{{/copy-button-feedback}}
+ `);
+
+ assert.equal(
+ this.$()
+ .text()
+ .trim(),
+ 'Click Me'
+ );
+});
diff --git a/ui-v2/tests/integration/components/delete-confirmation-test.js b/ui-v2/tests/integration/components/delete-confirmation-test.js
new file mode 100644
index 0000000000..24a02241c0
--- /dev/null
+++ b/ui-v2/tests/integration/components/delete-confirmation-test.js
@@ -0,0 +1,22 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('delete-confirmation', 'Integration | Component | delete confirmation', {
+ integration: true,
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{delete-confirmation}}`);
+
+ assert.equal(this.$('.type-delete').length, 1);
+
+ // Template block usage:
+ this.render(hbs`
+ {{#delete-confirmation}}{{/delete-confirmation}}
+ `);
+
+ assert.equal(this.$('.type-delete').length, 1);
+});
diff --git a/ui-v2/tests/integration/components/dom-buffer-flush-test.js b/ui-v2/tests/integration/components/dom-buffer-flush-test.js
new file mode 100644
index 0000000000..e7b260729a
--- /dev/null
+++ b/ui-v2/tests/integration/components/dom-buffer-flush-test.js
@@ -0,0 +1,34 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('dom-buffer-flush', 'Integration | Component | dom buffer flush', {
+ integration: true,
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{dom-buffer-flush}}`);
+
+ assert.equal(
+ this.$()
+ .text()
+ .trim(),
+ ''
+ );
+
+ // Template block usage:
+ this.render(hbs`
+ {{#dom-buffer-flush}}
+ template block text
+ {{/dom-buffer-flush}}
+ `);
+
+ assert.equal(
+ this.$()
+ .text()
+ .trim(),
+ 'template block text'
+ );
+});
diff --git a/ui-v2/tests/integration/components/dom-buffer-test.js b/ui-v2/tests/integration/components/dom-buffer-test.js
new file mode 100644
index 0000000000..3b75b3dd5b
--- /dev/null
+++ b/ui-v2/tests/integration/components/dom-buffer-test.js
@@ -0,0 +1,34 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('dom-buffer', 'Integration | Component | dom buffer', {
+ integration: true,
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{dom-buffer}}`);
+
+ assert.equal(
+ this.$()
+ .text()
+ .trim(),
+ ''
+ );
+
+ // Template block usage:
+ this.render(hbs`
+ {{#dom-buffer}}
+ template block text
+ {{/dom-buffer}}
+ `);
+
+ assert.equal(
+ this.$()
+ .text()
+ .trim(),
+ 'template block text'
+ );
+});
diff --git a/ui-v2/tests/integration/components/modal-dialog-test.js b/ui-v2/tests/integration/components/modal-dialog-test.js
new file mode 100644
index 0000000000..0a46b973b8
--- /dev/null
+++ b/ui-v2/tests/integration/components/modal-dialog-test.js
@@ -0,0 +1,33 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('modal-dialog', 'Integration | Component | modal dialog', {
+ integration: true,
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{modal-dialog}}`);
+
+ assert.ok(
+ this.$()
+ .text()
+ .trim()
+ .indexOf('Close') !== -1
+ );
+
+ // Template block usage:
+ this.render(hbs`
+ {{#modal-dialog}}
+ {{/modal-dialog}}
+ `);
+
+ assert.ok(
+ this.$()
+ .text()
+ .trim()
+ .indexOf('Close') !== -1
+ );
+});
diff --git a/ui-v2/tests/integration/components/modal-layer-test.js b/ui-v2/tests/integration/components/modal-layer-test.js
new file mode 100644
index 0000000000..bca907d275
--- /dev/null
+++ b/ui-v2/tests/integration/components/modal-layer-test.js
@@ -0,0 +1,22 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('modal-layer', 'Integration | Component | modal layer', {
+ integration: true,
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{modal-layer}}`);
+
+ assert.ok(this.$('#modal_close').length === 1);
+
+ // Template block usage:
+ this.render(hbs`
+ {{#modal-layer}}
+ {{/modal-layer}}
+ `);
+ assert.ok(this.$('#modal_close').length === 1);
+});
diff --git a/ui-v2/tests/integration/components/secret-button-test.js b/ui-v2/tests/integration/components/secret-button-test.js
new file mode 100644
index 0000000000..757baba078
--- /dev/null
+++ b/ui-v2/tests/integration/components/secret-button-test.js
@@ -0,0 +1,33 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('secret-button', 'Integration | Component | secret button', {
+ integration: true,
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{secret-button}}`);
+
+ assert.ok(
+ this.$()
+ .text()
+ .trim()
+ .indexOf('Reveal') !== -1
+ );
+
+ // Template block usage:
+ this.render(hbs`
+ {{#secret-button}}
+ {{/secret-button}}
+ `);
+
+ assert.ok(
+ this.$()
+ .text()
+ .trim()
+ .indexOf('Reveal') !== -1
+ );
+});
diff --git a/ui-v2/tests/integration/components/tabular-details-test.js b/ui-v2/tests/integration/components/tabular-details-test.js
new file mode 100644
index 0000000000..46671b854e
--- /dev/null
+++ b/ui-v2/tests/integration/components/tabular-details-test.js
@@ -0,0 +1,33 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('tabular-details', 'Integration | Component | tabular details', {
+ integration: true,
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{tabular-details}}`);
+
+ assert.equal(
+ this.$()
+ .text()
+ .trim(),
+ 'Actions'
+ );
+
+ // Template block usage:
+ this.render(hbs`
+ {{#tabular-details}}
+ {{/tabular-details}}
+ `);
+
+ assert.equal(
+ this.$()
+ .text()
+ .trim(),
+ 'Actions'
+ );
+});
diff --git a/ui-v2/tests/integration/components/token-list-test.js b/ui-v2/tests/integration/components/token-list-test.js
new file mode 100644
index 0000000000..617d140642
--- /dev/null
+++ b/ui-v2/tests/integration/components/token-list-test.js
@@ -0,0 +1,33 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('token-list', 'Integration | Component | token list', {
+ integration: true,
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{token-list}}`);
+
+ assert.equal(
+ this.$()
+ .text()
+ .trim(),
+ ''
+ );
+
+ // Template block usage:
+ this.render(hbs`
+ {{#token-list}}
+ {{/token-list}}
+ `);
+
+ assert.equal(
+ this.$()
+ .text()
+ .trim(),
+ ''
+ );
+});
diff --git a/ui-v2/tests/integration/helpers/policy/datacenters-test.js b/ui-v2/tests/integration/helpers/policy/datacenters-test.js
new file mode 100644
index 0000000000..ffec942f71
--- /dev/null
+++ b/ui-v2/tests/integration/helpers/policy/datacenters-test.js
@@ -0,0 +1,20 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('policy/datacenters', 'helper:policy/datacenters', {
+ integration: true,
+});
+
+// Replace this with your real tests.
+test('it renders', function(assert) {
+ this.set('inputValue', {});
+
+ this.render(hbs`{{policy/datacenters inputValue}}`);
+
+ assert.equal(
+ this.$()
+ .text()
+ .trim(),
+ 'All'
+ );
+});
diff --git a/ui-v2/tests/integration/helpers/policy/is-management-test.js b/ui-v2/tests/integration/helpers/policy/is-management-test.js
new file mode 100644
index 0000000000..92e89df912
--- /dev/null
+++ b/ui-v2/tests/integration/helpers/policy/is-management-test.js
@@ -0,0 +1,20 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('policy/is-management', 'helper:policy/is-management', {
+ integration: true,
+});
+
+// Replace this with your real tests.
+test('it renders', function(assert) {
+ this.set('inputValue', {});
+
+ this.render(hbs`{{policy/is-management inputValue}}`);
+
+ assert.equal(
+ this.$()
+ .text()
+ .trim(),
+ 'false'
+ );
+});
diff --git a/ui-v2/tests/integration/helpers/token/is-anonymous-test.js b/ui-v2/tests/integration/helpers/token/is-anonymous-test.js
new file mode 100644
index 0000000000..ba2fd863bd
--- /dev/null
+++ b/ui-v2/tests/integration/helpers/token/is-anonymous-test.js
@@ -0,0 +1,20 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('token/is-anonymous', 'helper:token/is-anonymous', {
+ integration: true,
+});
+
+// Replace this with your real tests.
+test('it renders', function(assert) {
+ this.set('inputValue', { AccessorID: '00000' });
+
+ this.render(hbs`{{token/is-anonymous inputValue}}`);
+
+ assert.equal(
+ this.$()
+ .text()
+ .trim(),
+ 'false'
+ );
+});
diff --git a/ui-v2/tests/integration/helpers/token/is-legacy-test.js b/ui-v2/tests/integration/helpers/token/is-legacy-test.js
new file mode 100644
index 0000000000..8fc8295e97
--- /dev/null
+++ b/ui-v2/tests/integration/helpers/token/is-legacy-test.js
@@ -0,0 +1,20 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('token/is-legacy', 'helper:token/is-legacy', {
+ integration: true,
+});
+
+// Replace this with your real tests.
+test('it renders', function(assert) {
+ this.set('inputValue', {});
+
+ this.render(hbs`{{token/is-legacy inputValue}}`);
+
+ assert.equal(
+ this.$()
+ .text()
+ .trim(),
+ 'false'
+ );
+});
diff --git a/ui-v2/tests/integration/services/policies-test.js b/ui-v2/tests/integration/services/policies-test.js
new file mode 100644
index 0000000000..a72b8f19e5
--- /dev/null
+++ b/ui-v2/tests/integration/services/policies-test.js
@@ -0,0 +1,68 @@
+import { moduleFor, test, skip } from 'ember-qunit';
+import repo from 'consul-ui/tests/helpers/repo';
+moduleFor('service:policies', 'Integration | Service | policies', {
+ // Specify the other units that are required for this test.
+ needs: [
+ 'service:store',
+ 'model:policy',
+ 'adapter:policy',
+ 'serializer:policy',
+ 'service:settings',
+ ],
+});
+const dc = 'dc-1';
+const id = 'policy-name';
+test('findByDatacenter returns the correct data for list endpoint', function(assert) {
+ return repo(
+ 'Policy',
+ 'findAllByDatacenter',
+ this.subject(),
+ function retrieveStub(stub) {
+ return stub(`/v1/acl/policies?dc=${dc}`, {
+ CONSUL_POLICY_COUNT: '100',
+ });
+ },
+ function performTest(service) {
+ return service.findAllByDatacenter(dc);
+ },
+ function performAssertion(actual, expected) {
+ assert.deepEqual(
+ actual,
+ expected(function(payload) {
+ return payload.map(item =>
+ Object.assign({}, item, {
+ Datacenter: dc,
+ uid: `["${dc}","${item.ID}"]`,
+ })
+ );
+ })
+ );
+ }
+ );
+});
+test('findBySlug returns the correct data for item endpoint', function(assert) {
+ return repo(
+ 'Policy',
+ 'findBySlug',
+ this.subject(),
+ function retrieveStub(stub) {
+ return stub(`/v1/acl/policy/${id}?dc=${dc}`);
+ },
+ function performTest(service) {
+ return service.findBySlug(id, dc);
+ },
+ function performAssertion(actual, expected) {
+ assert.deepEqual(
+ actual,
+ expected(function(payload) {
+ const item = payload;
+ return Object.assign({}, item, {
+ Datacenter: dc,
+ uid: `["${dc}","${item.ID}"]`,
+ });
+ })
+ );
+ }
+ );
+});
+skip('translate returns the correct data for the translate enpoint');
diff --git a/ui-v2/tests/integration/services/tokens-test.js b/ui-v2/tests/integration/services/tokens-test.js
new file mode 100644
index 0000000000..4c0ec9b283
--- /dev/null
+++ b/ui-v2/tests/integration/services/tokens-test.js
@@ -0,0 +1,64 @@
+import { moduleFor, test, skip } from 'ember-qunit';
+import repo from 'consul-ui/tests/helpers/repo';
+moduleFor('service:tokens', 'Integration | Service | tokens', {
+ // Specify the other units that are required for this test.
+ needs: ['service:store', 'model:token', 'adapter:token', 'serializer:token', 'service:settings'],
+});
+const dc = 'dc-1';
+const id = 'token-id';
+test('findByDatacenter returns the correct data for list endpoint', function(assert) {
+ return repo(
+ 'Token',
+ 'findAllByDatacenter',
+ this.subject(),
+ function retrieveStub(stub) {
+ return stub(`/v1/acl/tokens?dc=${dc}`, {
+ CONSUL_TOKEN_COUNT: '100',
+ });
+ },
+ function performTest(service) {
+ return service.findAllByDatacenter(dc);
+ },
+ function performAssertion(actual, expected) {
+ assert.deepEqual(
+ actual,
+ expected(function(payload) {
+ return payload.map(item =>
+ Object.assign({}, item, {
+ Datacenter: dc,
+ CreateTime: new Date(item.CreateTime),
+ uid: `["${dc}","${item.AccessorID}"]`,
+ })
+ );
+ })
+ );
+ }
+ );
+});
+test('findBySlug returns the correct data for item endpoint', function(assert) {
+ return repo(
+ 'Token',
+ 'findBySlug',
+ this.subject(),
+ function retrieveStub(stub) {
+ return stub(`/v1/acl/token/${id}?dc=${dc}`);
+ },
+ function performTest(service) {
+ return service.findBySlug(id, dc);
+ },
+ function performAssertion(actual, expected) {
+ assert.deepEqual(
+ actual,
+ expected(function(payload) {
+ const item = payload;
+ return Object.assign({}, item, {
+ Datacenter: dc,
+ CreateTime: new Date(item.CreateTime),
+ uid: `["${dc}","${item.AccessorID}"]`,
+ });
+ })
+ );
+ }
+ );
+});
+skip('clone returns the correct data for the clone endpoint');
diff --git a/ui-v2/tests/lib/page-object/createCancelable.js b/ui-v2/tests/lib/page-object/createCancelable.js
index 390362e86d..4319ea934a 100644
--- a/ui-v2/tests/lib/page-object/createCancelable.js
+++ b/ui-v2/tests/lib/page-object/createCancelable.js
@@ -1,10 +1,13 @@
export default function(clickable, is) {
- return function(obj) {
+ return function(obj, scope = '') {
+ if (scope !== '') {
+ scope = scope + ' ';
+ }
return {
...obj,
...{
- cancel: clickable('[type=reset]'),
- cancelIsEnabled: is(':not(:disabled)', '[type=reset]'),
+ cancel: clickable(scope + '[type=reset]'),
+ cancelIsEnabled: is(':not(:disabled)', scope + '[type=reset]'),
},
};
};
diff --git a/ui-v2/tests/lib/page-object/createSubmitable.js b/ui-v2/tests/lib/page-object/createSubmitable.js
index c566bd7f06..aabd562900 100644
--- a/ui-v2/tests/lib/page-object/createSubmitable.js
+++ b/ui-v2/tests/lib/page-object/createSubmitable.js
@@ -1,10 +1,13 @@
export default function(clickable, is) {
- return function(obj) {
+ return function(obj, scope = '') {
+ if (scope !== '') {
+ scope = scope + ' ';
+ }
return {
...obj,
...{
- submit: clickable('[type=submit]'),
- submitIsEnabled: is(':not(:disabled)', '[type=submit]'),
+ submit: clickable(scope + '[type=submit]'),
+ submitIsEnabled: is(':not(:disabled)', scope + '[type=submit]'),
},
};
};
diff --git a/ui-v2/tests/pages.js b/ui-v2/tests/pages.js
index 6720acc544..885594ed27 100644
--- a/ui-v2/tests/pages.js
+++ b/ui-v2/tests/pages.js
@@ -7,21 +7,28 @@ import createCancelable from 'consul-ui/tests/lib/page-object/createCancelable';
import page from 'consul-ui/tests/pages/components/page';
import radiogroup from 'consul-ui/tests/lib/page-object/radiogroup';
+import freetextFilter from 'consul-ui/tests/pages/components/freetext-filter';
+import catalogFilter from 'consul-ui/tests/pages/components/catalog-filter';
+import aclFilter from 'consul-ui/tests/pages/components/acl-filter';
+import intentionFilter from 'consul-ui/tests/pages/components/intention-filter';
+// TODO: should this specifically be modal or form?
+// should all forms be forms?
import index from 'consul-ui/tests/pages/index';
import dcs from 'consul-ui/tests/pages/dc';
import settings from 'consul-ui/tests/pages/settings';
-import catalogFilter from 'consul-ui/tests/pages/components/catalog-filter';
import services from 'consul-ui/tests/pages/dc/services/index';
import service from 'consul-ui/tests/pages/dc/services/show';
import nodes from 'consul-ui/tests/pages/dc/nodes/index';
import node from 'consul-ui/tests/pages/dc/nodes/show';
import kvs from 'consul-ui/tests/pages/dc/kv/index';
import kv from 'consul-ui/tests/pages/dc/kv/edit';
-import aclFilter from 'consul-ui/tests/pages/components/acl-filter';
import acls from 'consul-ui/tests/pages/dc/acls/index';
import acl from 'consul-ui/tests/pages/dc/acls/edit';
-import intentionFilter from 'consul-ui/tests/pages/components/intention-filter';
+import policies from 'consul-ui/tests/pages/dc/acls/policies/index';
+import policy from 'consul-ui/tests/pages/dc/acls/policies/edit';
+import tokens from 'consul-ui/tests/pages/dc/acls/tokens/index';
+import token from 'consul-ui/tests/pages/dc/acls/tokens/edit';
import intentions from 'consul-ui/tests/pages/dc/intentions/index';
import intention from 'consul-ui/tests/pages/dc/intentions/edit';
@@ -40,6 +47,18 @@ export default {
kv: create(kv(visitable, submitable, deletable, cancelable, clickable)),
acls: create(acls(visitable, deletable, creatable, clickable, attribute, collection, aclFilter)),
acl: create(acl(visitable, submitable, deletable, cancelable, clickable)),
+ policies: create(
+ policies(visitable, deletable, creatable, clickable, attribute, collection, freetextFilter)
+ ),
+ policy: create(
+ policy(visitable, submitable, deletable, cancelable, clickable, attribute, collection)
+ ),
+ tokens: create(
+ tokens(visitable, deletable, creatable, clickable, attribute, collection, freetextFilter)
+ ),
+ token: create(
+ token(visitable, submitable, deletable, cancelable, clickable, attribute, collection)
+ ),
intentions: create(
intentions(visitable, deletable, creatable, clickable, attribute, collection, intentionFilter)
),
diff --git a/ui-v2/tests/pages/components/freetext-filter.js b/ui-v2/tests/pages/components/freetext-filter.js
new file mode 100644
index 0000000000..76fda01024
--- /dev/null
+++ b/ui-v2/tests/pages/components/freetext-filter.js
@@ -0,0 +1,4 @@
+import { triggerable } from 'ember-cli-page-object';
+export default {
+ search: triggerable('keypress', '[name="s"]'),
+};
diff --git a/ui-v2/tests/pages/dc/acls/policies/edit.js b/ui-v2/tests/pages/dc/acls/policies/edit.js
new file mode 100644
index 0000000000..437fc4beb6
--- /dev/null
+++ b/ui-v2/tests/pages/dc/acls/policies/edit.js
@@ -0,0 +1,16 @@
+export default function(visitable, submitable, deletable, cancelable, clickable, attribute, collection) {
+ return submitable(
+ cancelable(
+ deletable({
+ visit: visitable(['/:dc/acls/policies/:policy', '/:dc/acls/policies/create']),
+ tokens: collection(
+ '[data-test-tabular-row]',
+ deletable({
+ id: attribute('data-test-token', '[data-test-token]'),
+ token: clickable('a'),
+ })
+ ),
+ })
+ )
+ );
+}
diff --git a/ui-v2/tests/pages/dc/acls/policies/index.js b/ui-v2/tests/pages/dc/acls/policies/index.js
new file mode 100644
index 0000000000..ff9204ad25
--- /dev/null
+++ b/ui-v2/tests/pages/dc/acls/policies/index.js
@@ -0,0 +1,14 @@
+export default function(visitable, deletable, creatable, clickable, attribute, collection, filter) {
+ return creatable({
+ visit: visitable('/:dc/acls/policies'),
+ policies: collection(
+ '[data-test-tabular-row]',
+ deletable({
+ name: attribute('data-test-policy', '[data-test-policy]'),
+ policy: clickable('a'),
+ actions: clickable('label'),
+ })
+ ),
+ filter: filter,
+ });
+}
diff --git a/ui-v2/tests/pages/dc/acls/tokens/edit.js b/ui-v2/tests/pages/dc/acls/tokens/edit.js
new file mode 100644
index 0000000000..862c9eee23
--- /dev/null
+++ b/ui-v2/tests/pages/dc/acls/tokens/edit.js
@@ -0,0 +1,36 @@
+export default function(
+ visitable,
+ submitable,
+ deletable,
+ cancelable,
+ clickable,
+ attribute,
+ collection
+) {
+ return submitable(
+ cancelable(
+ deletable(
+ {
+ visit: visitable(['/:dc/acls/tokens/:token', '/:dc/acls/tokens/create']),
+ use: clickable('[data-test-use]'),
+ confirmUse: clickable('button.type-delete'),
+ newPolicy: clickable('[data-test-new-policy]'),
+ policyForm: submitable(
+ cancelable({}, '[data-test-policy-form]'),
+ '[data-test-policy-form]'
+ ),
+ policies: collection(
+ '[data-test-tabular-row]',
+ deletable(
+ {
+ expand: clickable('label'),
+ },
+ '+ tr'
+ )
+ ),
+ },
+ 'form > div'
+ )
+ )
+ );
+}
diff --git a/ui-v2/tests/pages/dc/acls/tokens/index.js b/ui-v2/tests/pages/dc/acls/tokens/index.js
new file mode 100644
index 0000000000..375fdd86cd
--- /dev/null
+++ b/ui-v2/tests/pages/dc/acls/tokens/index.js
@@ -0,0 +1,16 @@
+export default function(visitable, deletable, creatable, clickable, attribute, collection, filter) {
+ return creatable({
+ visit: visitable('/:dc/acls/tokens'),
+ tokens: collection(
+ '[data-test-tabular-row]',
+ deletable({
+ id: attribute('data-test-token', '[data-test-token]'),
+ token: clickable('a'),
+ actions: clickable('label'),
+ use: clickable('[data-test-use]'),
+ confirmUse: clickable('button.type-delete'),
+ })
+ ),
+ filter: filter,
+ });
+}
diff --git a/ui-v2/tests/steps.js b/ui-v2/tests/steps.js
index 05cfad9f86..05f5c4759c 100644
--- a/ui-v2/tests/steps.js
+++ b/ui-v2/tests/steps.js
@@ -1,17 +1,36 @@
/* eslint no-console: "off" */
+import Inflector from 'ember-inflector';
import yadda from './helpers/yadda';
import { currentURL, click, triggerKeyEvent, fillIn, find } from '@ember/test-helpers';
import getDictionary from '@hashicorp/ember-cli-api-double/dictionary';
import pages from 'consul-ui/tests/pages';
import api from 'consul-ui/tests/helpers/api';
-
// const dont = `( don't| shouldn't| can't)?`;
-
+const pluralize = function(str) {
+ return Inflector.inflector.pluralize(str);
+};
const create = function(number, name, value) {
// don't return a promise here as
// I don't need it to wait
api.server.createList(name, number, value);
};
+const lastRequest = function(method) {
+ return api.server.history
+ .slice(0)
+ .reverse()
+ .find(function(item) {
+ return item.method === method;
+ });
+};
+const fillInElement = function(page, name, value) {
+ const cm = document.querySelector(`textarea[name="${name}"] + .CodeMirror`);
+ if (cm) {
+ cm.CodeMirror.setValue(value);
+ return page;
+ } else {
+ return page.fillIn(name, value);
+ }
+};
var currentPage;
export default function(assert) {
return (
@@ -106,8 +125,9 @@ export default function(assert) {
try {
return func();
} catch (e) {
- console.error(e);
- throw new Error(`The '${prop}' property on the '${component}' page object doesn't exist`);
+ throw new Error(
+ `The '${prop}' property on the '${component}' page object doesn't exist.\n${e.message}`
+ );
}
})
.when('I submit', function(selector) {
@@ -118,9 +138,18 @@ export default function(assert) {
})
.then(['I fill in with yaml\n$yaml', 'I fill in with json\n$json'], function(data) {
return Object.keys(data).reduce(function(prev, item, i, arr) {
- return prev.fillIn(item, data[item]);
+ return fillInElement(prev, item, data[item]);
}, currentPage);
})
+ .then(
+ ['I fill in the $form form with yaml\n$yaml', 'I fill in the $form with json\n$json'],
+ function(form, data) {
+ return Object.keys(data).reduce(function(prev, item, i, arr) {
+ const name = `${form}[${item}]`;
+ return fillInElement(prev, name, data[item]);
+ }, currentPage);
+ }
+ )
.then(['I type "$text" into "$selector"'], function(text, selector) {
return fillIn(selector, text);
})
@@ -167,10 +196,10 @@ export default function(assert) {
assert.equal(request.url, url, `Expected the request url to be ${url}, was ${request.url}`);
const body = JSON.parse(request.requestBody);
Object.keys(data).forEach(function(key, i, arr) {
- assert.equal(
+ assert.deepEqual(
body[key],
data[key],
- `Expected the payload to contain ${key} to equal ${body[key]}, ${key} was ${data[key]}`
+ `Expected the payload to contain ${key} equaling ${data[key]}, ${key} was ${body[key]}`
);
});
})
@@ -242,14 +271,36 @@ export default function(assert) {
assert.equal(request.url, url, `Expected the request url to be ${url}, was ${request.url}`);
})
.then('the last $method request was made to "$url"', function(method, url) {
- const request = api.server.history
- .slice(0)
- .reverse()
- .find(function(item) {
- return item.method === method;
- });
+ const request = lastRequest(method);
+ assert.equal(
+ request.method,
+ method,
+ `Expected the request method to be ${method}, was ${request.method}`
+ );
assert.equal(request.url, url, `Expected the request url to be ${url}, was ${request.url}`);
})
+ .then('the last $method request was made to "$url" with the body from yaml\n$yaml', function(
+ method,
+ url,
+ data
+ ) {
+ const request = lastRequest(method);
+ assert.ok(request, `Expected a ${method} request`);
+ assert.equal(
+ request.method,
+ method,
+ `Expected the request method to be ${method}, was ${request.method}`
+ );
+ assert.equal(request.url, url, `Expected the request url to be ${url}, was ${request.url}`);
+ const body = JSON.parse(request.requestBody);
+ Object.keys(data).forEach(function(key, i, arr) {
+ assert.deepEqual(
+ body[key],
+ data[key],
+ `Expected the payload to contain ${key} equaling ${data[key]}, ${key} was ${body[key]}`
+ );
+ });
+ })
.then('the last $method requests were like yaml\n$yaml', function(method, data) {
const requests = api.server.history.reverse().filter(function(item) {
return item.method === method;
@@ -274,11 +325,11 @@ export default function(assert) {
num,
model
) {
- const len = currentPage[`${model}s`].filter(function(item) {
+ const len = currentPage[pluralize(model)].filter(function(item) {
return item.isVisible;
}).length;
- assert.equal(len, num, `Expected ${num} ${model}s, saw ${len}`);
+ assert.equal(len, num, `Expected ${num} ${pluralize(model)}, saw ${len}`);
})
// TODO: I${ dont } see
.then([`I see $num $model model[s]? with the $property "$value"`], function(
@@ -288,13 +339,13 @@ export default function(assert) {
property,
value
) {
- const len = currentPage[`${model}s`].filter(function(item) {
+ const len = currentPage[pluralize(model)].filter(function(item) {
return item.isVisible && item[property] == value;
}).length;
assert.equal(
len,
num,
- `Expected ${num} ${model}s with ${property} set to "${value}", saw ${len}`
+ `Expected ${num} ${pluralize(model)} with ${property} set to "${value}", saw ${len}`
);
})
// TODO: Make this accept a 'contains' word so you can search for text containing also
@@ -381,6 +432,17 @@ export default function(assert) {
`Expected to not see ${property} on ${component}`
);
})
+ .then(["I don't see $property"], function(property) {
+ assert.throws(
+ function() {
+ currentPage[property]();
+ },
+ function(e) {
+ return e.toString().indexOf('Element not found') !== -1;
+ },
+ `Expected to not see ${property}`
+ );
+ })
.then(['I see $property'], function(property) {
assert.ok(currentPage[property], `Expected to see ${property}`);
})
diff --git a/ui-v2/tests/unit/adapters/policy-test.js b/ui-v2/tests/unit/adapters/policy-test.js
new file mode 100644
index 0000000000..750576e221
--- /dev/null
+++ b/ui-v2/tests/unit/adapters/policy-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Adapter | policy', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let adapter = this.owner.lookup('adapter:policy');
+ assert.ok(adapter);
+ });
+});
diff --git a/ui-v2/tests/unit/adapters/token-test.js b/ui-v2/tests/unit/adapters/token-test.js
new file mode 100644
index 0000000000..39aa07e76f
--- /dev/null
+++ b/ui-v2/tests/unit/adapters/token-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Adapter | token', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let adapter = this.owner.lookup('adapter:token');
+ assert.ok(adapter);
+ });
+});
diff --git a/ui-v2/tests/unit/controllers/dc/acls/create-test.js b/ui-v2/tests/unit/controllers/dc/acls/create-test.js
new file mode 100644
index 0000000000..88fab0190b
--- /dev/null
+++ b/ui-v2/tests/unit/controllers/dc/acls/create-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:dc/acls/create', 'Unit | Controller | dc/acls/create', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/ui-v2/tests/unit/controllers/dc/acls/policies/create-test.js b/ui-v2/tests/unit/controllers/dc/acls/policies/create-test.js
new file mode 100644
index 0000000000..12f561f5e9
--- /dev/null
+++ b/ui-v2/tests/unit/controllers/dc/acls/policies/create-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:dc/acls/policies/create', 'Unit | Controller | dc/acls/policies/create', {
+ // Specify the other units that are required for this test.
+ needs: ['service:dom', 'service:form'],
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/ui-v2/tests/unit/controllers/dc/acls/policies/edit-test.js b/ui-v2/tests/unit/controllers/dc/acls/policies/edit-test.js
new file mode 100644
index 0000000000..1b94ab8a74
--- /dev/null
+++ b/ui-v2/tests/unit/controllers/dc/acls/policies/edit-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:dc/acls/policies/edit', 'Unit | Controller | dc/acls/policies/edit', {
+ // Specify the other units that are required for this test.
+ needs: ['service:dom', 'service:form'],
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/ui-v2/tests/unit/controllers/dc/acls/policies/index-test.js b/ui-v2/tests/unit/controllers/dc/acls/policies/index-test.js
new file mode 100644
index 0000000000..fc5e3a97b3
--- /dev/null
+++ b/ui-v2/tests/unit/controllers/dc/acls/policies/index-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:dc/acls/policies/index', 'Unit | Controller | dc/acls/policies/index', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/ui-v2/tests/unit/controllers/dc/acls/tokens/create-test.js b/ui-v2/tests/unit/controllers/dc/acls/tokens/create-test.js
new file mode 100644
index 0000000000..ea9cc3ab6c
--- /dev/null
+++ b/ui-v2/tests/unit/controllers/dc/acls/tokens/create-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:dc/acls/tokens/create', 'Unit | Controller | dc/acls/tokens/create', {
+ // Specify the other units that are required for this test.
+ needs: ['service:dom', 'service:form'],
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/ui-v2/tests/unit/controllers/dc/acls/tokens/edit-test.js b/ui-v2/tests/unit/controllers/dc/acls/tokens/edit-test.js
new file mode 100644
index 0000000000..c331988ad4
--- /dev/null
+++ b/ui-v2/tests/unit/controllers/dc/acls/tokens/edit-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:dc/acls/tokens/edit', 'Unit | Controller | dc/acls/tokens/edit', {
+ // Specify the other units that are required for this test.
+ needs: ['service:dom', 'service:form'],
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/ui-v2/tests/unit/controllers/dc/acls/tokens/index-test.js b/ui-v2/tests/unit/controllers/dc/acls/tokens/index-test.js
new file mode 100644
index 0000000000..9eb384d4b1
--- /dev/null
+++ b/ui-v2/tests/unit/controllers/dc/acls/tokens/index-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:dc/acls/tokens/index', 'Unit | Controller | dc/acls/tokens/index', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/ui-v2/tests/unit/helpers/policy/datacenters-test.js b/ui-v2/tests/unit/helpers/policy/datacenters-test.js
new file mode 100644
index 0000000000..f508d6aae4
--- /dev/null
+++ b/ui-v2/tests/unit/helpers/policy/datacenters-test.js
@@ -0,0 +1,26 @@
+import { datacenters } from 'consul-ui/helpers/policy/datacenters';
+import { module, test } from 'qunit';
+
+module('Unit | Helper | policy/datacenters');
+
+test('it returns "All" if you pass a policy with no Datacenters property', function(assert) {
+ const expected = ['All'];
+ const actual = datacenters([{}]);
+ assert.deepEqual(actual, expected);
+});
+test('it returns "All" if you pass a policy with an empty Array as its Datacenters property', function(assert) {
+ const expected = ['All'];
+ const actual = datacenters([{ Datacenters: [] }]);
+ assert.deepEqual(actual, expected);
+});
+test('it returns "All" if you pass a policy with anything but an array', function(assert) {
+ // we know this uses isArray so lets just test with null as thats slightly likely
+ const expected = ['All'];
+ const actual = datacenters([{ Datacenters: null }]);
+ assert.deepEqual(actual, expected);
+});
+test('it returns the Datacenters if you pass a policy with correctly set Datacenters', function(assert) {
+ const expected = ['dc-1', 'dc-2'];
+ const actual = datacenters([{ Datacenters: ['dc-1', 'dc-2'] }]);
+ assert.deepEqual(actual, expected);
+});
diff --git a/ui-v2/tests/unit/helpers/policy/is-management-test.js b/ui-v2/tests/unit/helpers/policy/is-management-test.js
new file mode 100644
index 0000000000..e77a427650
--- /dev/null
+++ b/ui-v2/tests/unit/helpers/policy/is-management-test.js
@@ -0,0 +1,13 @@
+import { isManagement } from 'consul-ui/helpers/policy/is-management';
+import { module, test } from 'qunit';
+
+module('Unit | Helper | policy/is-management');
+
+test('it returns true if the policy is the management policy', function(assert) {
+ const actual = isManagement([{ ID: '00000000-0000-0000-0000-000000000001' }]);
+ assert.ok(actual);
+});
+test("it returns false if the policy isn't the management policy", function(assert) {
+ const actual = isManagement([{ ID: '00000000-0000-0000-0000-000000000000' }]);
+ assert.ok(!actual);
+});
diff --git a/ui-v2/tests/unit/helpers/token/is-anonymous-test.js b/ui-v2/tests/unit/helpers/token/is-anonymous-test.js
new file mode 100644
index 0000000000..b3f077f165
--- /dev/null
+++ b/ui-v2/tests/unit/helpers/token/is-anonymous-test.js
@@ -0,0 +1,13 @@
+import { isAnonymous } from 'consul-ui/helpers/token/is-anonymous';
+import { module, test } from 'qunit';
+
+module('Unit | Helper | token/is-anonymous');
+
+test('it returns true if the token is the anonymous token', function(assert) {
+ const actual = isAnonymous([{ AccessorID: '00000000-0000-0000-0000-000000000002' }]);
+ assert.ok(actual);
+});
+test("it returns false if the token isn't the anonymous token", function(assert) {
+ const actual = isAnonymous([{ AccessorID: '00000000-0000-0000-0000-000000000000' }]);
+ assert.ok(!actual);
+});
diff --git a/ui-v2/tests/unit/mixins/creating-route-test.js b/ui-v2/tests/unit/mixins/creating-route-test.js
new file mode 100644
index 0000000000..0371cdb514
--- /dev/null
+++ b/ui-v2/tests/unit/mixins/creating-route-test.js
@@ -0,0 +1,12 @@
+import EmberObject from '@ember/object';
+import CreatingRouteMixin from 'consul-ui/mixins/creating-route';
+import { module, test } from 'qunit';
+
+module('Unit | Mixin | creating route');
+
+// Replace this with your real tests.
+test('it works', function(assert) {
+ let CreatingRouteObject = EmberObject.extend(CreatingRouteMixin);
+ let subject = CreatingRouteObject.create();
+ assert.ok(subject);
+});
diff --git a/ui-v2/tests/unit/mixins/policy/with-actions-test.js b/ui-v2/tests/unit/mixins/policy/with-actions-test.js
new file mode 100644
index 0000000000..1daa67b773
--- /dev/null
+++ b/ui-v2/tests/unit/mixins/policy/with-actions-test.js
@@ -0,0 +1,29 @@
+import { moduleFor } from 'ember-qunit';
+import test from 'ember-sinon-qunit/test-support/test';
+import { getOwner } from '@ember/application';
+import Route from 'consul-ui/routes/dc/acls/policies/index';
+
+import Mixin from 'consul-ui/mixins/policy/with-actions';
+
+moduleFor('mixin:policy/with-actions', 'Unit | Mixin | policy/with actions', {
+ // Specify the other units that are required for this test.
+ needs: [
+ 'mixin:with-blocking-actions',
+ 'service:feedback',
+ 'service:flashMessages',
+ 'service:logger',
+ 'service:settings',
+ 'service:policies',
+ ],
+ subject: function() {
+ const MixedIn = Route.extend(Mixin);
+ this.register('test-container:policy/with-actions-object', MixedIn);
+ return getOwner(this).lookup('test-container:policy/with-actions-object');
+ },
+});
+
+// Replace this with your real tests.
+test('it works', function(assert) {
+ const subject = this.subject();
+ assert.ok(subject);
+});
diff --git a/ui-v2/tests/unit/mixins/token/with-actions-test.js b/ui-v2/tests/unit/mixins/token/with-actions-test.js
new file mode 100644
index 0000000000..2f2284b97b
--- /dev/null
+++ b/ui-v2/tests/unit/mixins/token/with-actions-test.js
@@ -0,0 +1,29 @@
+import { moduleFor } from 'ember-qunit';
+import test from 'ember-sinon-qunit/test-support/test';
+import { getOwner } from '@ember/application';
+import Route from 'consul-ui/routes/dc/acls/tokens/index';
+
+import Mixin from 'consul-ui/mixins/token/with-actions';
+
+moduleFor('mixin:token/with-actions', 'Unit | Mixin | token/with actions', {
+ // Specify the other units that are required for this test.
+ needs: [
+ 'mixin:with-blocking-actions',
+ 'service:feedback',
+ 'service:flashMessages',
+ 'service:logger',
+ 'service:settings',
+ 'service:tokens',
+ ],
+ subject: function() {
+ const MixedIn = Route.extend(Mixin);
+ this.register('test-container:token/with-actions-object', MixedIn);
+ return getOwner(this).lookup('test-container:token/with-actions-object');
+ },
+});
+
+// Replace this with your real tests.
+test('it works', function(assert) {
+ const subject = this.subject();
+ assert.ok(subject);
+});
diff --git a/ui-v2/tests/unit/models/policy-test.js b/ui-v2/tests/unit/models/policy-test.js
new file mode 100644
index 0000000000..b8756e6742
--- /dev/null
+++ b/ui-v2/tests/unit/models/policy-test.js
@@ -0,0 +1,14 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+import { run } from '@ember/runloop';
+
+module('Unit | Model | policy', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let store = this.owner.lookup('service:store');
+ let model = run(() => store.createRecord('policy', {}));
+ assert.ok(model);
+ });
+});
diff --git a/ui-v2/tests/unit/models/token-test.js b/ui-v2/tests/unit/models/token-test.js
new file mode 100644
index 0000000000..2f2c56acb0
--- /dev/null
+++ b/ui-v2/tests/unit/models/token-test.js
@@ -0,0 +1,14 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+import { run } from '@ember/runloop';
+
+module('Unit | Model | token', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let store = this.owner.lookup('service:store');
+ let model = run(() => store.createRecord('token', {}));
+ assert.ok(model);
+ });
+});
diff --git a/ui-v2/tests/unit/routes/dc/acls-test.js b/ui-v2/tests/unit/routes/dc/acls-test.js
new file mode 100644
index 0000000000..77e42f360a
--- /dev/null
+++ b/ui-v2/tests/unit/routes/dc/acls-test.js
@@ -0,0 +1,17 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:dc/acls', 'Unit | Route | dc/acls', {
+ // Specify the other units that are required for this test.
+ needs: [
+ 'service:tokens',
+ 'service:feedback',
+ 'service:logger',
+ 'service:settings',
+ 'service:flashMessages',
+ ],
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/ui-v2/tests/unit/routes/dc/acls/policies/create-test.js b/ui-v2/tests/unit/routes/dc/acls/policies/create-test.js
new file mode 100644
index 0000000000..f51eead5dc
--- /dev/null
+++ b/ui-v2/tests/unit/routes/dc/acls/policies/create-test.js
@@ -0,0 +1,19 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:dc/acls/policies/create', 'Unit | Route | dc/acls/policies/create', {
+ // Specify the other units that are required for this test.
+ needs: [
+ 'service:policies',
+ 'service:tokens',
+ 'service:dc',
+ 'service:feedback',
+ 'service:logger',
+ 'service:settings',
+ 'service:flashMessages',
+ ],
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/ui-v2/tests/unit/routes/dc/acls/policies/edit-test.js b/ui-v2/tests/unit/routes/dc/acls/policies/edit-test.js
new file mode 100644
index 0000000000..410d6bf27f
--- /dev/null
+++ b/ui-v2/tests/unit/routes/dc/acls/policies/edit-test.js
@@ -0,0 +1,19 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:dc/acls/policies/edit', 'Unit | Route | dc/acls/policies/edit', {
+ // Specify the other units that are required for this test.
+ needs: [
+ 'service:policies',
+ 'service:tokens',
+ 'service:dc',
+ 'service:feedback',
+ 'service:logger',
+ 'service:settings',
+ 'service:flashMessages',
+ ],
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/ui-v2/tests/unit/routes/dc/acls/policies/index-test.js b/ui-v2/tests/unit/routes/dc/acls/policies/index-test.js
new file mode 100644
index 0000000000..992c92f671
--- /dev/null
+++ b/ui-v2/tests/unit/routes/dc/acls/policies/index-test.js
@@ -0,0 +1,17 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:dc/acls/policies/index', 'Unit | Route | dc/acls/policies/index', {
+ // Specify the other units that are required for this test.
+ needs: [
+ 'service:policies',
+ 'service:feedback',
+ 'service:logger',
+ 'service:settings',
+ 'service:flashMessages',
+ ],
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/ui-v2/tests/unit/routes/dc/acls/tokens/create-test.js b/ui-v2/tests/unit/routes/dc/acls/tokens/create-test.js
new file mode 100644
index 0000000000..625653a5bf
--- /dev/null
+++ b/ui-v2/tests/unit/routes/dc/acls/tokens/create-test.js
@@ -0,0 +1,19 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:dc/acls/tokens/create', 'Unit | Route | dc/acls/tokens/create', {
+ // Specify the other units that are required for this test.
+ needs: [
+ 'service:tokens',
+ 'service:policies',
+ 'service:dc',
+ 'service:feedback',
+ 'service:logger',
+ 'service:settings',
+ 'service:flashMessages',
+ ],
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/ui-v2/tests/unit/routes/dc/acls/tokens/edit-test.js b/ui-v2/tests/unit/routes/dc/acls/tokens/edit-test.js
new file mode 100644
index 0000000000..aba5507f8b
--- /dev/null
+++ b/ui-v2/tests/unit/routes/dc/acls/tokens/edit-test.js
@@ -0,0 +1,19 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:dc/acls/tokens/edit', 'Unit | Route | dc/acls/tokens/edit', {
+ // Specify the other units that are required for this test.
+ needs: [
+ 'service:tokens',
+ 'service:policies',
+ 'service:dc',
+ 'service:feedback',
+ 'service:logger',
+ 'service:settings',
+ 'service:flashMessages',
+ ],
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/ui-v2/tests/unit/routes/dc/acls/tokens/index-test.js b/ui-v2/tests/unit/routes/dc/acls/tokens/index-test.js
new file mode 100644
index 0000000000..792f561748
--- /dev/null
+++ b/ui-v2/tests/unit/routes/dc/acls/tokens/index-test.js
@@ -0,0 +1,17 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:dc/acls/tokens/index', 'Unit | Route | dc/acls/tokens/index', {
+ // Specify the other units that are required for this test.
+ needs: [
+ 'service:tokens',
+ 'service:feedback',
+ 'service:logger',
+ 'service:settings',
+ 'service:flashMessages',
+ ],
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/ui-v2/tests/unit/serializers/policy-test.js b/ui-v2/tests/unit/serializers/policy-test.js
new file mode 100644
index 0000000000..a49b25a800
--- /dev/null
+++ b/ui-v2/tests/unit/serializers/policy-test.js
@@ -0,0 +1,24 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+import { run } from '@ember/runloop';
+
+module('Unit | Serializer | policy', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let store = this.owner.lookup('service:store');
+ let serializer = store.serializerFor('policy');
+
+ assert.ok(serializer);
+ });
+
+ test('it serializes records', function(assert) {
+ let store = this.owner.lookup('service:store');
+ let record = run(() => store.createRecord('policy', {}));
+
+ let serializedRecord = record.serialize();
+
+ assert.ok(serializedRecord);
+ });
+});
diff --git a/ui-v2/tests/unit/serializers/token-test.js b/ui-v2/tests/unit/serializers/token-test.js
new file mode 100644
index 0000000000..d22a797cbe
--- /dev/null
+++ b/ui-v2/tests/unit/serializers/token-test.js
@@ -0,0 +1,24 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+import { run } from '@ember/runloop';
+
+module('Unit | Serializer | token', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let store = this.owner.lookup('service:store');
+ let serializer = store.serializerFor('token');
+
+ assert.ok(serializer);
+ });
+
+ test('it serializes records', function(assert) {
+ let store = this.owner.lookup('service:store');
+ let record = run(() => store.createRecord('token', {}));
+
+ let serializedRecord = record.serialize();
+
+ assert.ok(serializedRecord);
+ });
+});
diff --git a/ui-v2/tests/unit/services/dom-buffer-test.js b/ui-v2/tests/unit/services/dom-buffer-test.js
new file mode 100644
index 0000000000..5a40120044
--- /dev/null
+++ b/ui-v2/tests/unit/services/dom-buffer-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('service:dom-buffer', 'Unit | Service | dom buffer', {
+ // Specify the other units that are required for this test.
+ // needs: ['service:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let service = this.subject();
+ assert.ok(service);
+});
diff --git a/ui-v2/tests/unit/services/dom-test.js b/ui-v2/tests/unit/services/dom-test.js
new file mode 100644
index 0000000000..f611005e4e
--- /dev/null
+++ b/ui-v2/tests/unit/services/dom-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('service:dom', 'Unit | Service | dom', {
+ // Specify the other units that are required for this test.
+ // needs: ['service:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let service = this.subject();
+ assert.ok(service);
+});
diff --git a/ui-v2/tests/unit/services/form-test.js b/ui-v2/tests/unit/services/form-test.js
new file mode 100644
index 0000000000..d256f3e452
--- /dev/null
+++ b/ui-v2/tests/unit/services/form-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('service:form', 'Unit | Service | form', {
+ // Specify the other units that are required for this test.
+ // needs: ['service:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let service = this.subject();
+ assert.ok(service);
+});
diff --git a/ui-v2/tests/unit/utils/acls-status-test.js b/ui-v2/tests/unit/utils/acls-status-test.js
new file mode 100644
index 0000000000..19766d2a44
--- /dev/null
+++ b/ui-v2/tests/unit/utils/acls-status-test.js
@@ -0,0 +1,10 @@
+import aclsStatus from 'consul-ui/utils/acls-status';
+import { module, test } from 'qunit';
+
+module('Unit | Utility | acls status');
+
+// Replace this with your real tests.
+test('it works', function(assert) {
+ let result = aclsStatus();
+ assert.ok(result);
+});
diff --git a/ui-v2/tests/unit/utils/dom/click-first-anchor-test.js b/ui-v2/tests/unit/utils/dom/click-first-anchor-test.js
new file mode 100644
index 0000000000..e8c64d662a
--- /dev/null
+++ b/ui-v2/tests/unit/utils/dom/click-first-anchor-test.js
@@ -0,0 +1,63 @@
+import domClickFirstAnchor from 'consul-ui/utils/dom/click-first-anchor';
+import { module, test } from 'qunit';
+
+module('Unit | Utility | dom/click first anchor');
+
+test('it does nothing if the clicked element is generally a clickable thing', function(assert) {
+ const closest = function() {
+ return {
+ querySelector: function() {
+ assert.ok(false);
+ },
+ };
+ };
+ const click = domClickFirstAnchor(closest);
+ ['INPUT', 'LABEL', 'A', 'Button'].forEach(function(item) {
+ const expected = null;
+ const actual = click({
+ target: {
+ nodeName: item,
+ },
+ });
+ assert.equal(actual, expected);
+ });
+});
+test("it does nothing if an anchor isn't found", function(assert) {
+ const closest = function() {
+ return {
+ querySelector: function() {
+ return null;
+ },
+ };
+ };
+ const click = domClickFirstAnchor(closest);
+ const expected = null;
+ const actual = click({
+ target: {
+ nodeName: 'DIV',
+ },
+ });
+ assert.equal(actual, expected);
+});
+test('it dispatches the result of `click` if an anchor is found', function(assert) {
+ assert.expect(1);
+ const expected = 'click';
+ const closest = function() {
+ return {
+ querySelector: function() {
+ return {
+ dispatchEvent: function(ev) {
+ const actual = ev.type;
+ assert.equal(actual, expected);
+ },
+ };
+ },
+ };
+ };
+ const click = domClickFirstAnchor(closest);
+ click({
+ target: {
+ nodeName: 'DIV',
+ },
+ });
+});
diff --git a/ui-v2/tests/unit/utils/dom/closest-test.js b/ui-v2/tests/unit/utils/dom/closest-test.js
new file mode 100644
index 0000000000..dc44926b60
--- /dev/null
+++ b/ui-v2/tests/unit/utils/dom/closest-test.js
@@ -0,0 +1,22 @@
+import domClosest from 'consul-ui/utils/dom/closest';
+import { module } from 'ember-qunit';
+import test from 'ember-sinon-qunit/test-support/test';
+import { skip } from 'qunit';
+
+module('Unit | Utility | dom/closest');
+
+test('it calls Element.closest with the specified selector', function(assert) {
+ const el = {
+ closest: this.stub().returnsArg(0),
+ };
+ const expected = 'selector';
+ const actual = domClosest(expected, el);
+ assert.equal(actual, expected);
+ assert.ok(el.closest.calledOnce);
+});
+test("it fails silently/null if calling closest doesn't work/exist", function(assert) {
+ const expected = null;
+ const actual = domClosest('selector', {});
+ assert.equal(actual, expected);
+});
+skip('polyfill closest');
diff --git a/ui-v2/tests/unit/utils/dom/normalize-event-test.js b/ui-v2/tests/unit/utils/dom/normalize-event-test.js
new file mode 100644
index 0000000000..774556caff
--- /dev/null
+++ b/ui-v2/tests/unit/utils/dom/normalize-event-test.js
@@ -0,0 +1,15 @@
+import domNormalizeEvent from 'consul-ui/utils/dom/normalize-event';
+import { module, test } from 'qunit';
+
+module('Unit | Utility | dom/normalize event');
+
+test('it returns the same object if target is defined', function(assert) {
+ const expected = { target: true };
+ const actual = domNormalizeEvent(expected, 'value');
+ assert.deepEqual(actual, expected);
+});
+test('it returns an event-like object if target is undefined', function(assert) {
+ const expected = { target: { name: 'name', value: 'value' } };
+ const actual = domNormalizeEvent('name', 'value');
+ assert.deepEqual(actual, expected);
+});
diff --git a/ui-v2/tests/unit/utils/qsa-factory-test.js b/ui-v2/tests/unit/utils/dom/qsa-factory-test.js
similarity index 93%
rename from ui-v2/tests/unit/utils/qsa-factory-test.js
rename to ui-v2/tests/unit/utils/dom/qsa-factory-test.js
index feadc8c3f5..9317edb1eb 100644
--- a/ui-v2/tests/unit/utils/qsa-factory-test.js
+++ b/ui-v2/tests/unit/utils/dom/qsa-factory-test.js
@@ -1,4 +1,4 @@
-import qsaFactory from 'consul-ui/utils/qsa-factory';
+import qsaFactory from 'consul-ui/utils/dom/qsa-factory';
import { module, test } from 'qunit';
module('Unit | Utility | qsa factory');
diff --git a/ui-v2/tests/unit/utils/dom/sibling-test.js b/ui-v2/tests/unit/utils/dom/sibling-test.js
new file mode 100644
index 0000000000..abc4911386
--- /dev/null
+++ b/ui-v2/tests/unit/utils/dom/sibling-test.js
@@ -0,0 +1,62 @@
+import domSibling from 'consul-ui/utils/dom/sibling';
+import { module, test } from 'qunit';
+
+module('Unit | Utility | dom/sibling');
+
+test('it returns the next sibling if it matches the requested nodeName', function(assert) {
+ const expected = {
+ nodeType: 1,
+ nodeName: 'H1',
+ };
+ const actual = domSibling(
+ {
+ nextSibling: expected,
+ },
+ 'h1'
+ );
+ assert.deepEqual(actual, expected);
+});
+test('it returns the next sibling from a list of nodes if it matches the requested nodeName', function(assert) {
+ const expected = {
+ nodeType: 1,
+ nodeName: 'H1',
+ };
+ const nodes = {
+ nodeType: 3,
+ nodeName: '#text',
+ nextSibling: {
+ nodeType: 4,
+ nodeName: '#cdata-section',
+ nextSibling: expected,
+ },
+ };
+ const actual = domSibling(
+ {
+ nextSibling: nodes,
+ },
+ 'h1'
+ );
+ assert.deepEqual(actual, expected);
+});
+test("it returns the null from a list of nodes if it can't match", function(assert) {
+ let expected;
+ const nodes = {
+ nodeType: 3,
+ nodeName: '#text',
+ nextSibling: {
+ nodeType: 4,
+ nodeName: '#cdata-section',
+ nextSibling: {
+ nodeType: 1,
+ nodeName: 'p',
+ },
+ },
+ };
+ const actual = domSibling(
+ {
+ nextSibling: nodes,
+ },
+ 'h1'
+ );
+ assert.deepEqual(actual, expected);
+});
diff --git a/ui-v2/tests/unit/utils/get-form-name-property-test.js b/ui-v2/tests/unit/utils/get-form-name-property-test.js
new file mode 100644
index 0000000000..a1b5d79847
--- /dev/null
+++ b/ui-v2/tests/unit/utils/get-form-name-property-test.js
@@ -0,0 +1,11 @@
+import getFormNameProperty from 'consul-ui/utils/get-form-name-property';
+import { module, test } from 'qunit';
+
+module('Unit | Utility | get form name property');
+
+// Replace this with your real tests.
+test("it parses 'item[property]' to `['item',' property']`", function(assert) {
+ const expected = ['item', 'property'];
+ const actual = getFormNameProperty(`${expected[0]}[${expected[1]}]`);
+ assert.deepEqual(actual, expected);
+});
diff --git a/ui-v2/tests/unit/utils/storage/local-storage-test.js b/ui-v2/tests/unit/utils/storage/local-storage-test.js
new file mode 100644
index 0000000000..7d4a76f42d
--- /dev/null
+++ b/ui-v2/tests/unit/utils/storage/local-storage-test.js
@@ -0,0 +1,68 @@
+import localStorage from 'consul-ui/utils/storage/local-storage';
+import { module, test } from 'qunit';
+
+module('Unit | Utility | storage/local-storage');
+
+// Replace this with your real tests.
+const mockStorage = function(obj, encode = val => val, decode = val => val) {
+ return localStorage('test', obj, encode, decode);
+};
+test('getValue returns an empty string if the value is null', function(assert) {
+ const expected = '""';
+ const storage = mockStorage({
+ getItem: function(path) {
+ return null;
+ },
+ });
+ const actual = storage.getValue('test');
+ assert.equal(actual, expected);
+});
+test('getValue uses the scheme in the path', function(assert) {
+ assert.expect(1);
+ const expected = 'test:test';
+ const storage = mockStorage({
+ getItem: function(actual) {
+ assert.equal(actual, expected);
+ return '';
+ },
+ });
+ storage.getValue('test');
+});
+test('setValue uses the scheme in the path', function(assert) {
+ assert.expect(1);
+ const expected = 'test:test';
+ const storage = mockStorage({
+ setItem: function(actual, value) {
+ assert.equal(actual, expected);
+ return '';
+ },
+ });
+ storage.setValue('test');
+});
+test('setValue calls removeItem if the value is null', function(assert) {
+ assert.expect(1);
+ const expected = 'test:test';
+ const storage = mockStorage({
+ removeItem: function(actual) {
+ assert.equal(actual, expected);
+ },
+ });
+ storage.setValue('test', null);
+});
+test('all returns an object of kvs under the correct prefix/scheme', function(assert) {
+ const storage = mockStorage({
+ 'tester:a': 'a',
+ b: 'b',
+ 'test:a': 'a',
+ 'test:b': 'b',
+ getItem: function(path) {
+ return this[path];
+ },
+ });
+ const expected = {
+ a: 'a',
+ b: 'b',
+ };
+ const actual = storage.all();
+ assert.deepEqual(actual, expected);
+});
diff --git a/ui-v2/tests/unit/utils/templatize-test.js b/ui-v2/tests/unit/utils/templatize-test.js
new file mode 100644
index 0000000000..4c02447260
--- /dev/null
+++ b/ui-v2/tests/unit/utils/templatize-test.js
@@ -0,0 +1,20 @@
+import templatize from 'consul-ui/utils/templatize';
+import { module, test } from 'qunit';
+
+module('Unit | Utility | templatize');
+
+test('it prefixes the word template to every string in the array', function(assert) {
+ const expected = ['template-one', 'template-two'];
+ const actual = templatize(['one', 'two']);
+ assert.deepEqual(actual, expected);
+});
+test('it returns an empty array when passed an empty array', function(assert) {
+ const expected = [];
+ const actual = templatize([]);
+ assert.deepEqual(actual, expected);
+});
+test('it returns an empty array when passed nothing', function(assert) {
+ const expected = [];
+ const actual = templatize();
+ assert.deepEqual(actual, expected);
+});
diff --git a/ui-v2/tests/unit/utils/update-array-object-test.js b/ui-v2/tests/unit/utils/update-array-object-test.js
new file mode 100644
index 0000000000..f066b3cc9d
--- /dev/null
+++ b/ui-v2/tests/unit/utils/update-array-object-test.js
@@ -0,0 +1,30 @@
+import updateArrayObject from 'consul-ui/utils/update-array-object';
+import { module, test } from 'qunit';
+
+module('Unit | Utility | update array object');
+
+// Replace this with your real tests.
+test('it works', function(assert) {
+ const expected = {
+ data: {
+ id: '2',
+ name: 'expected',
+ },
+ };
+ const arr = [
+ {
+ data: {
+ id: '1',
+ name: 'name',
+ },
+ },
+ {
+ data: {
+ id: '2',
+ name: '-',
+ },
+ },
+ ];
+ const actual = updateArrayObject(arr, expected, 'id');
+ assert.ok(actual, expected);
+});
diff --git a/ui-v2/yarn.lock b/ui-v2/yarn.lock
index 6c233e531c..024caf040c 100644
--- a/ui-v2/yarn.lock
+++ b/ui-v2/yarn.lock
@@ -82,9 +82,9 @@
faker "^4.1.0"
js-yaml "^3.10.0"
-"@hashicorp/consul-api-double@^1.5.3":
- version "1.5.3"
- resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-1.5.3.tgz#c797bd702c1c1f9c669b9df7f95126b3a76dd1c6"
+"@hashicorp/consul-api-double@^2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-2.0.1.tgz#eaf2e3f230fbdd876c90b931fd4bb4d94aac10e2"
"@hashicorp/ember-cli-api-double@^1.3.0":
version "1.6.1"
@@ -327,7 +327,7 @@ ajv@^4.9.1:
co "^4.6.0"
json-stable-stringify "^1.0.1"
-ajv@^5.2.3, ajv@^5.3.0:
+ajv@^5.1.0, ajv@^5.2.3, ajv@^5.3.0:
version "5.5.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
dependencies:
@@ -618,6 +618,10 @@ async-each@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
+async-foreach@^0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542"
+
async-limiter@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
@@ -676,7 +680,11 @@ aws-sign2@~0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
-aws4@^1.2.1:
+aws-sign2@~0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
+
+aws4@^1.2.1, aws4@^1.6.0, aws4@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
@@ -739,7 +747,7 @@ babel-core@^5.0.0:
trim-right "^1.0.0"
try-resolve "^1.0.0"
-babel-core@^6.14.0, babel-core@^6.24.1, babel-core@^6.26.0, babel-core@^6.26.3:
+babel-core@^6.14.0, babel-core@^6.26.0, babel-core@^6.26.3:
version "6.26.3"
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207"
dependencies:
@@ -763,6 +771,30 @@ babel-core@^6.14.0, babel-core@^6.24.1, babel-core@^6.26.0, babel-core@^6.26.3:
slash "^1.0.0"
source-map "^0.5.7"
+babel-core@^6.24.1:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8"
+ dependencies:
+ babel-code-frame "^6.26.0"
+ babel-generator "^6.26.0"
+ babel-helpers "^6.24.1"
+ babel-messages "^6.23.0"
+ babel-register "^6.26.0"
+ babel-runtime "^6.26.0"
+ babel-template "^6.26.0"
+ babel-traverse "^6.26.0"
+ babel-types "^6.26.0"
+ babylon "^6.18.0"
+ convert-source-map "^1.5.0"
+ debug "^2.6.8"
+ json5 "^0.5.1"
+ lodash "^4.17.4"
+ minimatch "^3.0.4"
+ path-is-absolute "^1.0.1"
+ private "^0.1.7"
+ slash "^1.0.0"
+ source-map "^0.5.6"
+
babel-generator@^6.18.0, babel-generator@^6.26.0:
version "6.26.1"
resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90"
@@ -915,7 +947,13 @@ babel-plugin-ember-modules-api-polyfill@^1.4.2:
dependencies:
ember-rfc176-data "^0.2.0"
-babel-plugin-ember-modules-api-polyfill@^2.3.0, babel-plugin-ember-modules-api-polyfill@^2.5.0:
+babel-plugin-ember-modules-api-polyfill@^2.3.0, babel-plugin-ember-modules-api-polyfill@^2.3.2:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.3.2.tgz#56ea34bea963498d070a2b7dc2ce18a92c434093"
+ dependencies:
+ ember-rfc176-data "^0.3.0"
+
+babel-plugin-ember-modules-api-polyfill@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.5.0.tgz#860aab9fecbf38c10d1fe0779c6979a854fff154"
dependencies:
@@ -1853,7 +1891,7 @@ broccoli-plugin@1.1.0:
rimraf "^2.3.4"
symlink-or-copy "^1.0.1"
-broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0:
+broccoli-plugin@^1.0.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.1.tgz#a26315732fb99ed2d9fb58f12a1e14e986b4fabd"
dependencies:
@@ -1862,7 +1900,7 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.1, broccoli
rimraf "^2.3.4"
symlink-or-copy "^1.1.8"
-broccoli-plugin@^1.2.0:
+broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee"
dependencies:
@@ -2247,8 +2285,8 @@ can-symlink@^1.0.0:
tmp "0.0.28"
caniuse-lite@^1.0.30000792, caniuse-lite@^1.0.30000844:
- version "1.0.30000888"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000888.tgz#22edb50d91dd70612b5898e3b36f460600c6492f"
+ version "1.0.30000883"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000883.tgz#597c1eabfb379bd9fbeaa778632762eb574706ac"
caniuse-lite@^1.0.30000805:
version "1.0.30000832"
@@ -2561,7 +2599,13 @@ combine-source-map@^0.8.0, combine-source-map@~0.8.0:
lodash.memoize "~3.0.3"
source-map "~0.5.3"
-combined-stream@^1.0.5, combined-stream@~1.0.5:
+combined-stream@1.0.6:
+ version "1.0.6"
+ resolved "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
+ dependencies:
+ delayed-stream "~1.0.0"
+
+combined-stream@^1.0.5, combined-stream@~1.0.5, combined-stream@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828"
dependencies:
@@ -2730,7 +2774,7 @@ convert-source-map@^1.1.0:
version "1.5.1"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5"
-convert-source-map@^1.5.1:
+convert-source-map@^1.5.0, convert-source-map@^1.5.1:
version "1.6.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
dependencies:
@@ -2832,6 +2876,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
+cross-spawn@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
+ dependencies:
+ lru-cache "^4.0.1"
+ which "^1.2.9"
+
cross-spawn@^5.0.1, cross-spawn@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
@@ -3243,8 +3294,8 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
electron-to-chromium@^1.3.30, electron-to-chromium@^1.3.47:
- version "1.3.73"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.73.tgz#aa67787067d58cc3920089368b3b8d6fe0fc12f6"
+ version "1.3.62"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.62.tgz#2e8e2dc070c800ec8ce23ff9dfcceb585d6f9ed8"
elegant-spinner@^1.0.1:
version "1.0.1"
@@ -3371,7 +3422,7 @@ ember-cli-autoprefixer@^0.8.1:
broccoli-autoprefixer "^5.0.0"
lodash "^4.0.0"
-ember-cli-babel@6.12.0, ember-cli-babel@^6.7.2:
+ember-cli-babel@6.12.0, ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.10.0, ember-cli-babel@^6.11.0, ember-cli-babel@^6.12.0, ember-cli-babel@^6.3.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.7.2, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.9.0, ember-cli-babel@^6.9.2:
version "6.12.0"
resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.12.0.tgz#3adcdbe1278da1fcd0b9038f1360cb4ac5d4414c"
dependencies:
@@ -3399,7 +3450,7 @@ ember-cli-babel@^5.1.6, ember-cli-babel@^5.1.7:
ember-cli-version-checker "^1.0.2"
resolve "^1.1.2"
-ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.10.0, ember-cli-babel@^6.11.0, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.3.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0, ember-cli-babel@^6.9.2:
+ember-cli-babel@^6.16.0:
version "6.17.2"
resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.17.2.tgz#f0d53d2fb95e70c15d8db84760d045f88f458f69"
dependencies:
@@ -3417,6 +3468,24 @@ ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-be
ember-cli-version-checker "^2.1.2"
semver "^5.5.0"
+ember-cli-babel@^6.8.2:
+ version "6.17.0"
+ resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.17.0.tgz#1f3e8ed9f4e2338caef6bc2c3d08d3c9928d0ddd"
+ dependencies:
+ amd-name-resolver "1.2.0"
+ babel-plugin-debug-macros "^0.2.0-beta.6"
+ babel-plugin-ember-modules-api-polyfill "^2.3.2"
+ babel-plugin-transform-es2015-modules-amd "^6.24.0"
+ babel-polyfill "^6.26.0"
+ babel-preset-env "^1.7.0"
+ broccoli-babel-transpiler "^6.5.0"
+ broccoli-debug "^0.6.4"
+ broccoli-funnel "^2.0.0"
+ broccoli-source "^1.1.0"
+ clone "^2.0.0"
+ ember-cli-version-checker "^2.1.2"
+ semver "^5.5.0"
+
ember-cli-broccoli-sane-watcher@^2.0.4:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.1.1.tgz#1687adada9022de26053fba833dc7dd10f03dd08"
@@ -3716,7 +3785,14 @@ ember-cli-version-checker@^1.0.2:
dependencies:
semver "^5.3.0"
-ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-version-checker@^2.1.2:
+ember-cli-version-checker@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.1.0.tgz#fc79a56032f3717cf844ada7cbdec1a06fedb604"
+ dependencies:
+ resolve "^1.3.3"
+ semver "^5.3.0"
+
+ember-cli-version-checker@^2.1.0, ember-cli-version-checker@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.1.2.tgz#305ce102390c66e4e0f1432dea9dc5c7c19fed98"
dependencies:
@@ -4041,14 +4117,14 @@ ember-rfc176-data@^0.2.0:
version "0.2.7"
resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.2.7.tgz#bd355bc9b473e08096b518784170a23388bc973b"
+ember-rfc176-data@^0.3.0, ember-rfc176-data@^0.3.3, ember-rfc176-data@^0.3.5:
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.5.tgz#f630e550572c81a5e5c7220f864c0f06eee9e977"
+
ember-rfc176-data@^0.3.1:
version "0.3.2"
resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.2.tgz#bde5538939529b263c142b53a47402f8127f8dce"
-ember-rfc176-data@^0.3.3, ember-rfc176-data@^0.3.5:
- version "0.3.5"
- resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.5.tgz#f630e550572c81a5e5c7220f864c0f06eee9e977"
-
ember-router-generator@^1.0.0, ember-router-generator@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee"
@@ -4666,7 +4742,7 @@ extend@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
-extend@~3.0.0:
+extend@~3.0.0, extend@~3.0.1, extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
@@ -4956,6 +5032,14 @@ form-data@~2.1.1:
combined-stream "^1.0.5"
mime-types "^2.1.12"
+form-data@~2.3.1, form-data@~2.3.2:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099"
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "1.0.6"
+ mime-types "^2.1.12"
+
formatio@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.2.0.tgz#f3b2167d9068c4698a8d51f4f760a39a54d818eb"
@@ -5155,6 +5239,12 @@ gauge@~2.7.3:
strip-ansi "^3.0.1"
wide-align "^1.1.0"
+gaze@^1.0.0:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a"
+ dependencies:
+ globule "^1.0.0"
+
get-caller-file@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
@@ -5240,7 +5330,7 @@ glob@^5.0.10, glob@^5.0.15:
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@^7.0.3, glob@^7.0.5:
+glob@^7.0.0, glob@^7.0.5, glob@~7.1.1:
version "7.1.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
dependencies:
@@ -5251,7 +5341,7 @@ glob@^7.0.3, glob@^7.0.5:
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@^7.0.4, glob@^7.1.0, glob@^7.1.2:
+glob@^7.0.3, glob@^7.0.4, glob@^7.1.0, glob@^7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
dependencies:
@@ -5319,6 +5409,14 @@ globby@^5.0.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
+globule@^1.0.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d"
+ dependencies:
+ glob "~7.1.1"
+ lodash "~4.17.10"
+ minimatch "~3.0.2"
+
good-listener@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
@@ -5361,6 +5459,10 @@ har-schema@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+har-schema@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
+
har-validator@~4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
@@ -5368,6 +5470,20 @@ har-validator@~4.2.1:
ajv "^4.9.1"
har-schema "^1.0.5"
+har-validator@~5.0.3:
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd"
+ dependencies:
+ ajv "^5.1.0"
+ har-schema "^2.0.0"
+
+har-validator@~5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29"
+ dependencies:
+ ajv "^5.3.0"
+ har-schema "^2.0.0"
+
has-ansi@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e"
@@ -5588,6 +5704,14 @@ http-signature@~1.1.0:
jsprim "^1.2.2"
sshpk "^1.7.0"
+http-signature@~1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
+ dependencies:
+ assert-plus "^1.0.0"
+ jsprim "^1.2.2"
+ sshpk "^1.7.0"
+
https-browserify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
@@ -5659,6 +5783,10 @@ imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+in-publish@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51"
+
include-path-searcher@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/include-path-searcher/-/include-path-searcher-0.1.0.tgz#c0cf2ddfa164fb2eae07bc7ca43a7f191cb4d7bd"
@@ -6191,6 +6319,10 @@ jquery@^3.2.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca"
+js-base64@^2.1.8:
+ version "2.4.9"
+ resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.9.tgz#748911fb04f48a60c4771b375cac45a80df11c03"
+
js-reporters@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b"
@@ -6677,6 +6809,10 @@ lodash.assign@^3.2.0:
lodash._createassigner "^3.0.0"
lodash.keys "^3.0.0"
+lodash.assign@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
+
lodash.assignin@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2"
@@ -6693,7 +6829,7 @@ lodash.castarray@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115"
-lodash.clonedeep@^4.4.1:
+lodash.clonedeep@^4.3.2, lodash.clonedeep@^4.4.1:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
@@ -6806,6 +6942,10 @@ lodash.merge@^4.3.0, lodash.merge@^4.4.0, lodash.merge@^4.6.0:
version "4.6.1"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54"
+lodash.mergewith@^4.6.0:
+ version "4.6.1"
+ resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
+
lodash.noop@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-2.3.0.tgz#3059d628d51bbf937cd2a0b6fc3a7f212a669c2c"
@@ -6874,14 +7014,18 @@ lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
-lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.5.1:
- version "4.17.11"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
-
-lodash@^4.3.0, lodash@^4.6.1:
+lodash@^4.0.0, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1:
version "4.17.5"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
+lodash@^4.14.0, lodash@^4.17.10, lodash@^4.17.4:
+ version "4.17.10"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
+
+lodash@^4.17.5, lodash@~4.17.10:
+ version "4.17.11"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
+
log-symbols@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
@@ -7049,7 +7193,7 @@ memory-streams@^0.1.0:
dependencies:
readable-stream "~1.0.2"
-meow@^3.4.0:
+meow@^3.4.0, meow@^3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
dependencies:
@@ -7144,7 +7288,7 @@ mime-db@~1.36.0:
version "1.36.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397"
-mime-types@^2.1.12, mime-types@~2.1.18, mime-types@~2.1.7:
+mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.19, mime-types@~2.1.7:
version "2.1.20"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19"
dependencies:
@@ -7178,7 +7322,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
-"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
+"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
@@ -7328,14 +7472,14 @@ najax@^1.0.3:
lodash.defaultsdeep "^4.6.0"
qs "^6.2.0"
+nan@^2.10.0, nan@^2.9.2:
+ version "2.11.1"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.1.tgz#90e22bccb8ca57ea4cd37cc83d3819b52eea6766"
+
nan@^2.3.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f"
-nan@^2.9.2:
- version "2.11.1"
- resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.1.tgz#90e22bccb8ca57ea4cd37cc83d3819b52eea6766"
-
nanomatch@^1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2"
@@ -7418,6 +7562,23 @@ node-fetch@^1.3.3:
encoding "^0.1.11"
is-stream "^1.0.1"
+node-gyp@^3.8.0:
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
+ dependencies:
+ fstream "^1.0.0"
+ glob "^7.0.3"
+ graceful-fs "^4.1.2"
+ mkdirp "^0.5.0"
+ nopt "2 || 3"
+ npmlog "0 || 1 || 2 || 3 || 4"
+ osenv "0"
+ request "^2.87.0"
+ rimraf "2"
+ semver "~5.3.0"
+ tar "^2.0.0"
+ which "1"
+
node-int64@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
@@ -7494,7 +7655,31 @@ node-pre-gyp@^0.6.39:
tar "^2.2.1"
tar-pack "^3.4.0"
-nopt@^3.0.6:
+node-sass@^4.9.3:
+ version "4.9.3"
+ resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.3.tgz#f407cf3d66f78308bb1e346b24fa428703196224"
+ dependencies:
+ async-foreach "^0.1.3"
+ chalk "^1.1.1"
+ cross-spawn "^3.0.0"
+ gaze "^1.0.0"
+ get-stdin "^4.0.1"
+ glob "^7.0.3"
+ in-publish "^2.0.0"
+ lodash.assign "^4.2.0"
+ lodash.clonedeep "^4.3.2"
+ lodash.mergewith "^4.6.0"
+ meow "^3.7.0"
+ mkdirp "^0.5.1"
+ nan "^2.10.0"
+ node-gyp "^3.8.0"
+ npmlog "^4.0.0"
+ request "2.87.0"
+ sass-graph "^2.2.4"
+ stdout-stream "^1.4.0"
+ "true-case-path" "^1.0.2"
+
+"nopt@2 || 3", nopt@^3.0.6:
version "3.0.6"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
dependencies:
@@ -7574,7 +7759,7 @@ npm-which@^3.0.1:
npm-path "^2.0.2"
which "^1.2.10"
-npmlog@^4.0.0, npmlog@^4.0.2:
+"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
dependencies:
@@ -7597,10 +7782,14 @@ number-is-nan@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
-oauth-sign@~0.8.1:
+oauth-sign@~0.8.1, oauth-sign@~0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+oauth-sign@~0.9.0:
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
+
object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@@ -7741,7 +7930,7 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
-osenv@^0.1.3, osenv@^0.1.4, osenv@^0.1.5:
+osenv@0, osenv@^0.1.3, osenv@^0.1.4, osenv@^0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
dependencies:
@@ -7958,6 +8147,10 @@ performance-now@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+performance-now@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
+
pify@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@@ -8059,7 +8252,7 @@ printf@^0.2.3:
version "0.2.5"
resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f"
-private@^0.1.6, private@^0.1.8, private@~0.1.5:
+private@^0.1.6, private@^0.1.7, private@^0.1.8, private@~0.1.5:
version "0.1.8"
resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
@@ -8114,6 +8307,10 @@ pseudomap@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+psl@^1.1.24:
+ version "1.1.29"
+ resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67"
+
public-encrypt@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.2.tgz#46eb9107206bf73489f8b85b69d91334c6610994"
@@ -8159,7 +8356,7 @@ qs@6.5.1, qs@^6.4.0:
version "6.5.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
-qs@6.5.2, qs@^6.2.0:
+qs@6.5.2, qs@^6.2.0, qs@~6.5.1, qs@~6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
@@ -8508,6 +8705,56 @@ request@2.81.0:
tunnel-agent "^0.6.0"
uuid "^3.0.0"
+request@2.87.0:
+ version "2.87.0"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e"
+ dependencies:
+ aws-sign2 "~0.7.0"
+ aws4 "^1.6.0"
+ caseless "~0.12.0"
+ combined-stream "~1.0.5"
+ extend "~3.0.1"
+ forever-agent "~0.6.1"
+ form-data "~2.3.1"
+ har-validator "~5.0.3"
+ http-signature "~1.2.0"
+ is-typedarray "~1.0.0"
+ isstream "~0.1.2"
+ json-stringify-safe "~5.0.1"
+ mime-types "~2.1.17"
+ oauth-sign "~0.8.2"
+ performance-now "^2.1.0"
+ qs "~6.5.1"
+ safe-buffer "^5.1.1"
+ tough-cookie "~2.3.3"
+ tunnel-agent "^0.6.0"
+ uuid "^3.1.0"
+
+request@^2.87.0:
+ version "2.88.0"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
+ dependencies:
+ aws-sign2 "~0.7.0"
+ aws4 "^1.8.0"
+ caseless "~0.12.0"
+ combined-stream "~1.0.6"
+ extend "~3.0.2"
+ forever-agent "~0.6.1"
+ form-data "~2.3.2"
+ har-validator "~5.1.0"
+ http-signature "~1.2.0"
+ is-typedarray "~1.0.0"
+ isstream "~0.1.2"
+ json-stringify-safe "~5.0.1"
+ mime-types "~2.1.19"
+ oauth-sign "~0.9.0"
+ performance-now "^2.1.0"
+ qs "~6.5.2"
+ safe-buffer "^5.1.2"
+ tough-cookie "~2.4.3"
+ tunnel-agent "^0.6.0"
+ uuid "^3.3.2"
+
require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
@@ -8559,13 +8806,13 @@ resolve@1.5.0:
dependencies:
path-parse "^1.0.5"
-resolve@^1.1.2, resolve@^1.1.3, resolve@^1.1.4, resolve@^1.3.0:
+resolve@^1.1.2, resolve@^1.1.3, resolve@^1.1.4, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.0, resolve@^1.5.0:
version "1.7.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.1.tgz#aadd656374fd298aee895bc026b8297418677fd3"
dependencies:
path-parse "^1.0.5"
-resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.7.1:
+resolve@^1.3.3, resolve@^1.4.0, resolve@^1.7.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26"
dependencies:
@@ -8665,10 +8912,14 @@ rsvp@^4.6.1, rsvp@^4.8.1:
version "4.8.2"
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.2.tgz#9d5647108735784eb13418cdddb56f75b919d722"
-rsvp@^4.7.0, rsvp@^4.8.2:
+rsvp@^4.7.0:
version "4.8.4"
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.4.tgz#b50e6b34583f3dd89329a2f23a8a2be072845911"
+rsvp@^4.8.2:
+ version "4.8.3"
+ resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.3.tgz#25d4b9fdd0f95e216eb5884d9b3767d3fbfbe2cd"
+
rsvp@~3.0.6:
version "3.0.21"
resolved "http://registry.npmjs.org/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f"
@@ -8753,6 +9004,15 @@ sane@^2.2.0, sane@^2.4.1:
optionalDependencies:
fsevents "^1.1.1"
+sass-graph@^2.2.4:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49"
+ dependencies:
+ glob "^7.0.0"
+ lodash "^4.0.0"
+ scss-tokenizer "^0.2.3"
+ yargs "^7.0.0"
+
sax@^1.2.4, sax@~1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
@@ -8764,6 +9024,13 @@ schema-utils@^0.4.4, schema-utils@^0.4.5:
ajv "^6.1.0"
ajv-keywords "^3.1.0"
+scss-tokenizer@^0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
+ dependencies:
+ js-base64 "^2.1.8"
+ source-map "^0.4.2"
+
select@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
@@ -8772,13 +9039,17 @@ semver-compare@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
-"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0:
+"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.5.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
+
+semver@^5.3.0, semver@^5.4.1:
version "5.5.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477"
-semver@^5.1.0, semver@^5.1.1:
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
+semver@~5.3.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
send@0.16.2:
version "0.16.2"
@@ -9201,6 +9472,12 @@ statuses@~1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
+stdout-stream@^1.4.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de"
+ dependencies:
+ readable-stream "^2.0.1"
+
stream-browserify@^2.0.0, stream-browserify@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
@@ -9460,7 +9737,7 @@ tar-pack@^3.4.0:
tar "^2.2.1"
uid-number "^0.0.6"
-tar@^2.2.1:
+tar@^2.0.0, tar@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
dependencies:
@@ -9639,12 +9916,19 @@ to-regex@^3.0.1, to-regex@^3.0.2:
regex-not "^1.0.2"
safe-regex "^1.1.0"
-tough-cookie@~2.3.0:
+tough-cookie@~2.3.0, tough-cookie@~2.3.3:
version "2.3.4"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"
dependencies:
punycode "^1.4.1"
+tough-cookie@~2.4.3:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
+ dependencies:
+ psl "^1.1.24"
+ punycode "^1.4.1"
+
tree-sync@^1.2.1, tree-sync@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7"
@@ -9663,6 +9947,12 @@ trim-right@^1.0.0, trim-right@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+"true-case-path@^1.0.2":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d"
+ dependencies:
+ glob "^7.1.2"
+
try-resolve@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912"
@@ -9924,7 +10214,7 @@ utils-merge@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
-uuid@^3.0.0:
+uuid@^3.0.0, uuid@^3.1.0, uuid@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
@@ -9963,7 +10253,7 @@ vm-browserify@0.0.4, vm-browserify@~0.0.1:
dependencies:
indexof "0.0.1"
-walk-sync@0.3.2, walk-sync@^0.3.2:
+walk-sync@0.3.2, walk-sync@^0.3.0, walk-sync@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75"
dependencies:
@@ -9977,7 +10267,7 @@ walk-sync@^0.2.5, walk-sync@^0.2.7:
ensure-posix-path "^1.0.0"
matcher-collection "^1.0.0"
-walk-sync@^0.3.0, walk-sync@^0.3.1:
+walk-sync@^0.3.1:
version "0.3.3"
resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.3.tgz#1e9f12cd4fe6e0e6d4a0715b5cc7e30711d43cd1"
dependencies:
@@ -10062,15 +10352,15 @@ which-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
-which@^1.2.10, which@^1.2.12, which@^1.2.14, which@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"
+which@1, which@^1.2.9:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
dependencies:
isexe "^2.0.0"
-which@^1.2.9:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+which@^1.2.10, which@^1.2.12, which@^1.2.14, which@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"
dependencies:
isexe "^2.0.0"
@@ -10118,8 +10408,8 @@ worker-farm@^1.5.2:
errno "~0.1.7"
workerpool@^2.3.0:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-2.3.3.tgz#49a70089bd55e890d68cc836a19419451d7c81d7"
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-2.3.1.tgz#6872d3a749dd820d42b8390abaac20fb14ce4c81"
dependencies:
object-assign "4.1.1"
@@ -10213,6 +10503,12 @@ yargs-parser@^4.2.0:
dependencies:
camelcase "^3.0.0"
+yargs-parser@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"
+ dependencies:
+ camelcase "^3.0.0"
+
yargs@^6.5.0:
version "6.6.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
@@ -10231,6 +10527,24 @@ yargs@^6.5.0:
y18n "^3.2.1"
yargs-parser "^4.2.0"
+yargs@^7.0.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"
+ dependencies:
+ camelcase "^3.0.0"
+ cliui "^3.2.0"
+ decamelize "^1.1.1"
+ get-caller-file "^1.0.1"
+ os-locale "^1.4.0"
+ read-pkg-up "^1.0.1"
+ require-directory "^2.1.1"
+ require-main-filename "^1.0.1"
+ set-blocking "^2.0.0"
+ string-width "^1.0.2"
+ which-module "^1.0.0"
+ y18n "^3.2.1"
+ yargs-parser "^5.0.0"
+
yargs@~3.10.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"