-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PKI role create view #17263
PKI role create view #17263
Conversation
@@ -20,9 +20,8 @@ export default class PkiIssuerEngineAdapter extends ApplicationAdapter { | |||
return url; | |||
} | |||
|
|||
async query(store, type, query) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clean up (thank you Claire for pointing this out).
@@ -0,0 +1,52 @@ | |||
<div class="column is-narrow is-flex-center has-text-grey has-right-margin-s has-top-margin-negative-s"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New component that I will use several times in PKI but unsure if it will be used in future designs.
newcomponent.mov
@@ -213,6 +213,9 @@ | |||
.has-top-margin-xxl { | |||
margin-top: $spacing-xxl; | |||
} | |||
.has-top-margin-negative-s { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the new component, needed them to be closer to the label so they seemed "grouped" together.
@@ -6,8 +16,8 @@ | |||
</ToolbarActions> | |||
</Toolbar> | |||
|
|||
{{#if (gt this.model.length 0)}} | |||
{{#each this.model as |pkiRole|}} | |||
{{#if (gt this.model.model.length 0)}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect there's a better way to do this, but I couldn't figure out how shape the model without giving it a label. I tried spread attrs, and that didn't work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can change the key specified in RSVP.hash
to something other than model
@@ -19,5 +23,9 @@ export default class RolesIndexRoute extends Route { | |||
throw err; | |||
} | |||
}); | |||
return RSVP.hash({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Jordan, you might have some comments on this. I tried not using hash, but had issues with it returning a promise and not a class. I tried a then, and that didn't work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since modelFor
does not return a promise you could return an object in the then
of query:
return this.store
.query('pki/pki-role-engine', { backend: this.secretMountPath.currentPath })
.then((model) => {
return { model, parentModel: this.modelFor('roles') };
})
.catch((err) => {
if (err.httpStatus === 404) {
return [];
} else {
throw err;
}
});
I don't mind using RSVP.hash
though too. It just might not be immediately clear to someone who is unfamiliar with the method.
I would avoid using let
to assign those variables since they are not being reassigned if you decide to leave as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, thank you. I see now how to structure the then. I prefer this method only because it doesn't rely on an import, it's pure js.
@@ -13,7 +13,7 @@ | |||
<FormFieldLabel | |||
for={{@attr.name}} | |||
@label={{this.labelString}} | |||
@helpText={{@attr.options.helpText}} | |||
@helpText={{(if this.showHelpText @attr.options.helpText)}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some issues on the formField
component with the attribute showHelpText
not being added to all form field types.
@@ -58,7 +58,10 @@ export default class FormFieldComponent extends Component { | |||
return this.args.disabled || false; | |||
} | |||
get showHelpText() { | |||
return this.args.showHelpText || true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was my bad 🤦🏻♀️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And yeah, ideally we wouldn't return a true by default on a param, but this is an old pattern and if we choose to modify should be done in a cleanup ticket.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made some comments! Nice work on this. PKI is 🤯
Great job on the new component! It'd be nice to have some tests written for it, maybe as a follow on after this PR? It'd be nice to have early on in PKI development to confirm that the values sent are as expected.
<MessageError @errorMessage={{this.errorBanner}} class="has-top-margin-s" /> | ||
{{! ARG TODO write a test for namespace reminder }} | ||
<NamespaceReminder @mode={{if @model.isNew "create" "update"}} @noun="PKI role" /> | ||
{{! This is the code from FormFieldGroupsLoop. However, because we need to pass the attr into the yielded component, I'm unable to use that component.}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this comment is necessary as we've used this pattern of iterating over FormFields outside of the loop component
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I just wanted to make a comment in case a future developer came along and noticed the code was nearly identical to the FormFieldGroupsLoop component and wondered why I didn't just use that component instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I recall discussing this and maybe I didn't have the full context at the time but slightly modifying FormFieldGroupsLoop
will prevent having to copy the code out.
Since you added the yield to FormField
you can yield that up from the FormFieldGroupsLoop
as well. Update both instances to something like:
<FormField data-test-field={{true}} @attr={{attr}} @model={{@model}}>
{{yield attr}}
</FormField
Then you can use the RadioSelectTtlOrString
component which will render in the yield block of FormField
:
<FormFieldGroupsLoop @model={{this.model}} @mode={{this.mode}} as |attr|>
<RadioSelectTtlOrString @model={{@model}} @attr={{attr}} />
</FormFieldGroupsLoop>
It looks like you also need modelValidations
and showHelpText
passed in so you could add those as args to the groups loop as well.
In a situation where you might have multiple different attr types that yield you can just do a check in the block and display the proper component.
<FormFieldGroupsLoop @model={{this.model}} @mode={{this.mode}} as |attr|>
{{#if attr.type "someType"}}
<RadioSelectTtlOrString @model={{@model}} @attr={{attr}} />
{{else if attr.type "someOtherType"}}
<SomeOtherComponent />
{{/if}}
</FormFieldGroupsLoop>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! (reviewed over zoom), but passing through the attr in the yield the way you showed was awesome. A lot cleaner now.
createRecord(store, type, snapshot) { | ||
let name = snapshot.attr('name'); | ||
let url = this._urlForRole(snapshot.record.backend, name); | ||
return this.ajax(url, 'POST', { data: this.serialize(snapshot) }).then(() => { | ||
return { | ||
id: name, | ||
name, | ||
backend: snapshot.record.backend, | ||
}; | ||
}); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comparing this to the base method and wondering if you can use it and just update the response? Something like:
createRecord(store, type, snapshot){
return super.createRecord(...arguments).then(() => {
return { id: name, name, backend: snapshot.record.backend };
});
}
{{else if (eq @attr.options.editType "yield")}} | ||
{{yield}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
if (this.args.showHelpText === false) { | ||
return false; | ||
} | ||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ternary might be cleaner here:
return this.args.showHelpText === false ? false : true;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! Thank you. I knew there was a cleaner way.
@tracked ttlTime = ''; | ||
@tracked notAfter = ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if these props need to be initialized to empty strings? Is there somewhere that expects the value to always be a string, as in maybe does a charAt
or calls some other method on the prototype without first checking for existence?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. They are supposed to be strings, and ttl specifically says empty, though not_after doesn't seem to care. But the api seems to handle this. The only thing I think calling them out as strings does here, it let the next developer know these are not numbers but strings. But it's a toss up. I'll ahead and remove the default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't feel strongly about it but was curious. Since you are defining them as tracked properties it doesn't hurt to give them an initial value.
<MessageError @errorMessage={{this.errorBanner}} class="has-top-margin-s" /> | ||
{{! ARG TODO write a test for namespace reminder }} | ||
<NamespaceReminder @mode={{if @model.isNew "create" "update"}} @noun="PKI role" /> | ||
{{! This is the code from FormFieldGroupsLoop. However, because we need to pass the attr into the yielded component, I'm unable to use that component.}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I recall discussing this and maybe I didn't have the full context at the time but slightly modifying FormFieldGroupsLoop
will prevent having to copy the code out.
Since you added the yield to FormField
you can yield that up from the FormFieldGroupsLoop
as well. Update both instances to something like:
<FormField data-test-field={{true}} @attr={{attr}} @model={{@model}}>
{{yield attr}}
</FormField
Then you can use the RadioSelectTtlOrString
component which will render in the yield block of FormField
:
<FormFieldGroupsLoop @model={{this.model}} @mode={{this.mode}} as |attr|>
<RadioSelectTtlOrString @model={{@model}} @attr={{attr}} />
</FormFieldGroupsLoop>
It looks like you also need modelValidations
and showHelpText
passed in so you could add those as args to the groups loop as well.
In a situation where you might have multiple different attr types that yield you can just do a check in the block and display the proper component.
<FormFieldGroupsLoop @model={{this.model}} @mode={{this.mode}} as |attr|>
{{#if attr.type "someType"}}
<RadioSelectTtlOrString @model={{@model}} @attr={{attr}} />
{{else if attr.type "someOtherType"}}
<SomeOtherComponent />
{{/if}}
</FormFieldGroupsLoop>
@@ -19,5 +23,9 @@ export default class RolesIndexRoute extends Route { | |||
throw err; | |||
} | |||
}); | |||
return RSVP.hash({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since modelFor
does not return a promise you could return an object in the then
of query:
return this.store
.query('pki/pki-role-engine', { backend: this.secretMountPath.currentPath })
.then((model) => {
return { model, parentModel: this.modelFor('roles') };
})
.catch((err) => {
if (err.httpStatus === 404) {
return [];
} else {
throw err;
}
});
I don't mind using RSVP.hash
though too. It just might not be immediately clear to someone who is unfamiliar with the method.
I would avoid using let
to assign those variables since they are not being reassigned if you decide to leave as is.
@@ -6,8 +16,8 @@ | |||
</ToolbarActions> | |||
</Toolbar> | |||
|
|||
{{#if (gt this.model.length 0)}} | |||
{{#each this.model as |pkiRole|}} | |||
{{#if (gt this.model.model.length 0)}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can change the key specified in RSVP.hash
to something other than model
* dynamically render the secretlistheader in the parent route. * start getting form setup even without openAPi working * add in create and cancel * making openAPI work * add default openAPI params * wip for new component with two radio options a ttl and input * handle createRecord on pki-roles-form * remove tooltips and cleanup * move formfieldgroupsloop back to non addon * cleanup * move secretListHeader * broadcast from radioSelectTtlOrString to parent * cleanup * cleanup from pr comments * more cleanup * addressing Jordans comments * use formFieldGroupsLoop move into addon. * cleanup
This PR handles the PKI role creation for the default values only. The values hidden behind the Toggle options are more complicated and will have some design implications I wanted to keep in a separate PR (stay tuned).
Below is a video. The form correctly sends the default params on the network request, including the custom yield param (
ttl
andnot_after
).roles_create.mov
Notes:
secretListHeader
to the respective index routes will be the new pattern. The struggle with this, and why I originally had it on the parent "roles" route, is that the models for theroles
vs theroles/index
are different. Theroles
route is the secret-engine mount model and theroles/index
route is the list of roles. To solve for this, I added amodelFor
in the roles/index route. Please comment if you see any issues with this.editType: yield
to the model and then yield out whatever you want betweenformFields
.ex:
TODO: