-
-
Notifications
You must be signed in to change notification settings - Fork 707
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
Add new enterprise settings tab Connected Apps #11937
Conversation
a815014
to
702e93e
Compare
I would have like to use a standard form to submit to the reflex but the whole enterprise settings tab is in a form already and HTML doesn't allow nested forms. While it does still work in browsers, it would have added much more HTML to set up a form with a hidden input field instead of just one additional data attribute. The whole page is rendered by the controller again but the reflex root attribute ensures that only parts of this tab are replaced. Otherwise unsaved data on other tabs could be replaced and the page actually becomes blank because AngularJS doesn't play well with the morph.
# frozen_string_literal: true | ||
|
||
module Admin | ||
class ConnectedAppReflex < ApplicationReflex |
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.
The StimulusReflex documentation mentions that singular and plural naming of reflexes is allowed and the choice depends on the circumstances. We use both in OFN. The plural seems to be useful when the reflex is listing or searching for collections, e.g. many orders. I decided to keep it simple and go with the singular. But over time, we may realise that any reflex could be expanded to deal with collections as well and then the plural would be better. To avoid renaming, we may introduce a convention but I don't see enough of a pattern yet.
@@ -1,11 +1,17 @@ | |||
%div | |||
%div{ data: {reflex: {root: ".connected-app__head, .connected-app__connection"}} } |
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.
The reflex root will be replaced later.
it "stores connection data on the app" do | ||
subject.perform_now | ||
|
||
expect(app.data).to eq({ "link" => "https://example.net/edit" }) |
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.
The URL will change on the live endpoint once it's implemented. We may not be able to do live recordings then because we don't want to add our test enterprise to the live database. Maybe we can have a test mode, let's see.
app/jobs/connect_app_job.rb
Outdated
|
||
return unless channel | ||
|
||
selector = "#edit_enterprise_#{enterprise.id} #connected_apps_panel div" |
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 you have multiple tabs open with other enterprises then you don't want to show this enterprise's information on another enterprise's page.
# Avoid race condition by sending before enqueuing job: | ||
cable_ready.morph(selector:, html:).broadcast |
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.
The change on the page is almost instant now. Previously, it was calling the edit action of the enterprises controller and there was a noticeable lag. That action renders lots of data, including a select box with all enterprises of the platform and all kind of options for every tab of the enterprise settings. In contrast, the partial is very small.
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.
Great implementation, well done!
It looks good too. The only thing is it would be good to use some CSS variables, which should help with the long-term maintenance of the stylesheet.
%h3= t ".title" | ||
%p= t ".tagline" |
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 like this bracket-less format, I can't believe we weren't doing this before!
Now if only we could make lazy-lookup the default, and go back to symbols it would be beautiful 💎
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.
We could add our own helper:
# I18n lazy translate
def lt(key, *args)
I18n.t(".#{key}", *args)
end
What do you think? Saves one character, I suppose:
= lt :tagline
And it wouldn't be well known. Not worth it.
margin-bottom: 1em; | ||
|
||
h3 { | ||
margin-bottom: 1em; |
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 would like to think we already have reasonable margins for h3 and p by default, but I guess not.
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 would have thought so, too. But they must be overridden somewhere. Maybe it will be better in the new design?
subject.save! | ||
subject.reload | ||
|
||
expect(subject.data).to eq({ "link" => "https://example.net" }) |
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.
Nice, I wonder if Rails has a way for it to be with_indifferent_access by default and therefore load the hash with symbol keys.
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.
We would need to add a few things:
https://gist.github.com/RobinDaugherty/5e7bc2a6e2369a29c77c
Or we just override a method on the model:
def data
data.try(:with_indifferent_access)
end
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 looked at this and we currently have only one single line of access to this data:
enterprise.connected_apps[0].data&.fetch("link", false)
And in this scenario it would only change "link"
to :link
which isn't making a real difference. I'll leave this.
border-left: 4px solid #008397; | ||
border-radius: 4px; |
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.
Ideally we'd use a variable for the colour. $color-3
is spree-blue in the old design, and the new teal in the new design.
Also, we can use a variable for border-radius. This helps ensure the left border is the same width as the radius.
border-left: 4px solid #008397; | |
border-radius: 4px; | |
border-left: $border-radius solid $color-3; | |
border-radius: $border-radius; |
This will look a bit different on the old design, but I think should be ok.
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.
There could also be a variable for box-shadow, but I have a PR in progress for that, so let's just leave it hardcoded here for now.
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.
Ah, good to know. So $color-3
is available in the old and new design? I guess, once the new design is released, we can do a simple search/replace.
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.
access_token: token, | ||
} | ||
|
||
response = WebhookDeliveryJob.perform_now(url, event, payload) |
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.
Yay, nice to see the WebhookDeliveryJob
in use!
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 just noticed this is a wrapper for WebhookDeliveryJob
. Would it make sense to subclass it I wonder? I can't think it would make much difference..
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.
In doubt, I tend to avoid inheritance. This job could be seen as a special webhook job which also captures the response. But it's also doing UX stuff and it may expand one day. Only part of it is the webhook functionality. So I think that composition is the better pattern here.
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.
Oops that was meant to be a 'request changes' for the CSS variables.
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.
Cool, I have to admit I accidentally missed the last two commits before.
But it all looks fine 👍
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.
Nice one, I like your use of a reflex.
|
||
module Admin | ||
class ConnectedAppReflex < ApplicationReflex | ||
def create |
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 know it's tested in a system spec, but I wonder if we should also have unit test for reflexes ?
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. I find unit tests good for testing individual methods with all the different code branches. But this method doesn't actually have any branching. And that means that the system spec is providing 100% code coverage. So I wouldn't bother at this point.
Actually, I overlooked one thing. The authorize!
call is a code branch. We could test permissions in a unit test. Same for find
and create!
which could raise errors. But that's well-known behaviour we deal with all the time.
What? Why?
Screencast.from.2023-12-15.16-31-13.webm
What should we test?
Testing requirement: the last step of testing needs the n8n workflow:
Production test only
I realised that the n8n workflows are all tied to the Australian production server and therefore we can't test it in staging. We may change that but for now, we can just merge this. It's feature-toggled.
Testing steps:
connected_apps
for user, enterprise or instance.Release notes
Changelog Category (reviewers may add a label for the release notes):
The title of the pull request will be included in the release notes.
Dependencies
This depends on a certain n8n workflow. The webhook URL is hardcoded.
Documentation updates