Enable updating revision drafts through commands & leverage with Scale Rules#423
Enable updating revision drafts through commands & leverage with Scale Rules#423MicroFish91 merged 22 commits intomainfrom
Scale Rules#423Conversation
9da09cc to
fc5b808
Compare
Scale RulesScale Rules
|
|
||
| public shouldPrompt(context: IAddScaleRuleContext): boolean { | ||
| return context.queueName === undefined; | ||
| return !context.queueName; |
There was a problem hiding this comment.
Changed a lot of these to just a ! because I feel like there are other falsey values besides undefined that I would like to prevent as valid input.
|
Just a sidenote: This would be a great place where we have a follow up action for the activity log. Underneath Add HTTP Scale Rule, it would awesome to have the Deploy/Update command underneath it to make it more obvious that they are unsaved changes. |
|
Also should change it from "creating revision" to "updating container app" or "deploying to container app" |
Yeah good call, I'll update this in a separate PR... there's another small change I want to make to the deploy command anyway Added: #427 |
| @@ -51,22 +50,15 @@ export class RevisionDraftFileSystem implements FileSystemProvider { | |||
| } | |||
|
|
|||
| // Create | |||
There was a problem hiding this comment.
Did you want to leave all the //CRUD comments in here? I don't really mind but it's also kind of unnecessary.
| public async execute(context: IAddScaleRuleContext, progress: Progress<{ message?: string | undefined; increment?: number | undefined }>): Promise<void> { | ||
| let adding: string | undefined; | ||
| let added: string | undefined; | ||
| if (context.containerApp.revisionsMode === KnownActiveRevisionsMode.Single) { |
There was a problem hiding this comment.
nit: I think you could have a "resourceName" variable here that is either "container app" or "revision" and replace that in the adding and added strings. It's just a little messy to see these long sentences written out twice (at least in GitHub)
| this.updateRevisionDraftWithTemplate(); | ||
|
|
||
| // Artificial delay to make the activity log look like it's performing an action | ||
| await delay(1000); |
There was a problem hiding this comment.
I feel like a second is a little bit long to block a user for something that's artificial.
My understanding is that it's so that you can see Adding scale rule... appear, but even if they don't see that progress message, they can still see that the "Added scale rule to container app (draft)` completed successfully, right?
I don't know if we need that progress message since it's instantaneous to begin with.
There was a problem hiding this comment.
If we do want to keep the delay though, I think we should put the delay in updateRevisionDraftWithTemplate so that all of the actions behave similarily.
| const { subscription, containerApp, revision } = item; | ||
|
|
||
| // Branching path reasoning: https://github.com/microsoft/vscode-azurecontainerapps/blob/main/src/commands/revisionDraft/README.md | ||
| let scale: Scale | undefined; |
There was a problem hiding this comment.
We're going to have to duplicate this logic a lot (any time we add/update the draft). I think we should go ahead and extract this out as a util function.
The function should just return revision or containerApp depending on the revision type.
| readonly containerApp: ContainerAppModel, | ||
| readonly revision: Revision | ||
| ) { | ||
| if (this.hasUnsavedChanges()) { |
There was a problem hiding this comment.
It may be easier to discuss this offline, but I'll write a short blurb and we can discuss further.
But I think RevisionsDraftModel should have a function to set the properties based on if it has unsaved changes or not. That way, the ScaleRuleGroupItem (and any other item that needs this logic) doesn't have to have the branching logic in its constructor.
RevisionDraftModel should also have two abstract methods: setProperties and setPropertiesDraft (or something like that-- maybe setTreeItem?) that does the assignments.
So I think that would look something like this:
// For tree items that depend on the container app's revision draft template
export abstract class RevisionsDraftModel {
hasUnsavedChanges: () => boolean | Promise<boolean>;
abstract function setProperties(): void;
abstract function setPropertiesDraft(): void;
constructor(...) {
this.hasUnsavedChanges() ? this.setPropertiesDraft() : this.setProperties();
}
}
There was a problem hiding this comment.
After some testing, ran into some limitations with doing it this way, will discuss more offline
| } | ||
|
|
||
| private get parentResource(): ContainerAppModel | Revision { | ||
| return this.containerApp.revisionsMode === KnownActiveRevisionsMode.Single ? this.containerApp : this.revision; |
There was a problem hiding this comment.
Another spot we can use the util to choose between app or revision.
ab5bfb2 to
fe93023
Compare
…inerapps into mwf/wire-scale-rule
| }); | ||
| if (scaleRuleExists) { | ||
| return localize('scaleRuleExists', 'The scale rule "{0}" already exists in container app "{1}". Please enter a unique name.', name, containerAppName); | ||
| private async validateNameAvailable(context: IAddScaleRuleContext, name: string): Promise<string | undefined> { |
There was a problem hiding this comment.
Heads up, I also added validation that always does a network call to ensure we aren't working with stale data when we run our verification logic.
| * the container app tree item without further changes, it is easier to just use the container app template | ||
| * as the primary source of truth when in single revision mode. | ||
| */ | ||
| if (item instanceof ContainerAppItem || item.containerApp.revisionsMode === KnownActiveRevisionsMode.Single) { |
There was a problem hiding this comment.
We like to avoid using instanceof if we can. Here it can be replaced with an isContainerAppItem function.
https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
| return; | ||
| } | ||
|
|
||
| file.contents = newContent; |
There was a problem hiding this comment.
I think it'd be worth extracting this out to an updateFile function or something similar. You do it above as well, and I could potentially see what we set here being updated in the future.
Could also include
this.draftStore.set(uri.path, file);
this.fireSoon({ type: FileChangeType.Changed, uri });
// Any new changes to the draft file can cause the states of a container app's children to change (e.g. displaying "Unsaved changes")
ext.state.notifyChildrenChanged(file.containerAppId);
to be included in the function. I can't really think of an instance where we update and don't fire an event.
There was a problem hiding this comment.
Good catch, I think that separate function is already written actually. I think I can just call this.writeFile() with the new contents
| await delay(1000); | ||
|
|
||
| ext.outputChannel.appendLog(added); | ||
| const resourceName = context.containerApp.revisionsMode === KnownActiveRevisionsMode.Single ? context.containerApp.name : this.baseItem.revision.name; |
There was a problem hiding this comment.
I don't really have a preference, but if you wanted to keep it as "revision "revision.name"" or "container app "containerApp.name"", you could include that as part of the resourceName logic.
There was a problem hiding this comment.
I think I get what you mean, but let me know if I was off with the change I made
| containerApp: ContainerAppModel; | ||
|
|
||
| scaleRules: ScaleRule[]; | ||
| parentResourceName: string; |
There was a problem hiding this comment.
Kind of a weird name to me. I get that getParentResource is the command being invoked, but parentResourceName is always referring to the container app name, right? Since the parent of the scale rule is the scale rule group item this was especially confusing to me.
Can we just call it containerAppName? Or can we not just get the CA name from the container app model? I think whether or not we're using the template or revision, the containerApp.name property should be correct.
There was a problem hiding this comment.
No, so in general the parent resource name could be the container app name or the revision name, so we don't know which one it is until we actually build the context. It's following the same naming convention as used for the util which returns a container app model or revision model. We might still be able to come up with a better name though, since it's definitely not a direct parent and I see why that could be confusing
There was a problem hiding this comment.
Potentially I could add parentResource: ContainerAppItem | Revision and just access the name property later when I need it. Felt like overkill to tack the whole thing on at the time, but it would make it a lot less confusing for situations like this where the name parent is a bit ambiguous 🤔
There was a problem hiding this comment.
Maybe just a comment about that then? I personally felt like it was pretty confusing.
| /** | ||
| * Can be implemented by any tree item that has the potential to show up as a RevisionDraftItem's descendant | ||
| */ | ||
| export abstract class RevisionDraftDescendantBase implements RevisionsDraftModel { |
There was a problem hiding this comment.
I feel like that this should implement RevisionsItemModel as well. viewProperties isn't declared here, but all of the RevisionDraftDescendants have it. It should define these types a bit more since I could see that being an easy property to forget for future items.
There was a problem hiding this comment.
The interface RevisionsDraftModel could also just implement RevisionsItemModel as well to achieve this effect.
There was a problem hiding this comment.
Yeah good catch, I should have included that as well
There was a problem hiding this comment.
Unfortunately ContainerAppItem uses RevisionsDraftModel without RevisionsItemModel which is why I left them uncoupled, but I agree that the base item should include both
96c2fbf to
0fe631d
Compare

Addresses 2/3 of #420
Closes #254
Summary:
Scale Rulesto update the revision draft template rather than deploy a new revisionAdd scale rule...improvements (this was my first big feature and going back I noticed a lot of things I wanted to change or fix 😮💨)Future:
+ Create a secretrelated logic from this PR, will add it in the follow-up oneAdd scale rule...a little bit more in the near future, mostly to clean up the validate input logicScale RulesDemo:
Note: It works basically the same for multiple revisions mode. I was kind of lazy about recording that demo, but I at least tested the same ops in multiple revisions mode and it behaved the same way as in single revisions mode minus it being attached to a draft node.