-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Updated empty states across settings #5874
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
base: master
Are you sure you want to change the base?
Conversation
|
| has_shared_links? = | ||
| Repo.exists?( | ||
| from(l in Plausible.Site.SharedLink, | ||
| where: | ||
| l.site_id == ^site.id and | ||
| l.name not in ^Plausible.Sites.shared_link_special_names() | ||
| ) | ||
| ) | ||
|
|
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 added this so that I can hide the setting subtitle when the empty state is shown. I'm not sure this is the right place to put it, and it works but requires a page refresh for it to take effect.
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.
Hey @sanne-san - this is unfortunately, not the most lucky problem to have. Looks like we have a lot to unpack with regards to how we've been randomly migrating settings sections to live views.
A smol background story: settings were originally all static, standard HTML forms etc. With need of having many dynamic forms over the time (and us getting a safe-ish playground to learn LiveView the hard way), we've started turning them into live views. Because rewriting everything was risky we've started embedding live views (modules operating on @socket / websocket) in static templates (as in "rendered once", a.k.a "dead" - using @conn / HTTP) bit by bit, where needed. Live views are where react-like diffs are applied. That's why you're struggling with refresh - the part that renders the tile and its slots is static 💀.
Normally it'd best to move the <.tile></.tile> element to the live view that's embedded underneath - PlausibleWeb.Live.SharedLinkSettings in this case. But there are cans of worms ahead: you'll get the compiler complain about site_role missing. You can of course provide it in the live view's mount() function (either execute the query or pass it down via the session params in the static template and assign it to the socket).
But it also turns out that the tile component is a bit complicated - in an attempt of generic handling of toggling features and/or upgrade CTAs in case of insufficient subscriptions, it is why it wants the site_role assign provided. It also needs @conn - which we don't have access to in live views.. And SharedLinks is indeed a feature that's not available to everyone, so we need some handling of billing availability still.
With Goals, Funnels, CustomProps it might get even weirder, since we have live views embedding live views there and they're separate processes so they'd need to exchange messages with each other 🙈
I wouldn't recommend getting there now; sounds like a massive undertaking to hide the subtitle. 😬
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.
Maybe it's possible to remove the :subtitle slot from static template and render its markup in live view, verbatim? Just so we don't have to deal with all the tile problems.
- Add show_content? attribute to generic tile component - Ensure content is hidden when toggled off - Avoid rendering border and empty space when toggled off - Fix formatting
6ff4770 to
779dd92
Compare
| Add funnel | ||
| </.button> | ||
| </.filter_bar> | ||
| <%= if String.trim(@filter_text) != "" || Enum.count(@funnels) > 0 do %> |
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.
or is perfectly valid here since both left and right hand side expressions return a boolean
| has_shared_links? = | ||
| Repo.exists?( | ||
| from(l in Plausible.Site.SharedLink, | ||
| where: | ||
| l.site_id == ^site.id and | ||
| l.name not in ^Plausible.Sites.shared_link_special_names() | ||
| ) | ||
| ) | ||
|
|
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.
Hey @sanne-san - this is unfortunately, not the most lucky problem to have. Looks like we have a lot to unpack with regards to how we've been randomly migrating settings sections to live views.
A smol background story: settings were originally all static, standard HTML forms etc. With need of having many dynamic forms over the time (and us getting a safe-ish playground to learn LiveView the hard way), we've started turning them into live views. Because rewriting everything was risky we've started embedding live views (modules operating on @socket / websocket) in static templates (as in "rendered once", a.k.a "dead" - using @conn / HTTP) bit by bit, where needed. Live views are where react-like diffs are applied. That's why you're struggling with refresh - the part that renders the tile and its slots is static 💀.
Normally it'd best to move the <.tile></.tile> element to the live view that's embedded underneath - PlausibleWeb.Live.SharedLinkSettings in this case. But there are cans of worms ahead: you'll get the compiler complain about site_role missing. You can of course provide it in the live view's mount() function (either execute the query or pass it down via the session params in the static template and assign it to the socket).
But it also turns out that the tile component is a bit complicated - in an attempt of generic handling of toggling features and/or upgrade CTAs in case of insufficient subscriptions, it is why it wants the site_role assign provided. It also needs @conn - which we don't have access to in live views.. And SharedLinks is indeed a feature that's not available to everyone, so we need some handling of billing availability still.
With Goals, Funnels, CustomProps it might get even weirder, since we have live views embedding live views there and they're separate processes so they'd need to exchange messages with each other 🙈
I wouldn't recommend getting there now; sounds like a massive undertaking to hide the subtitle. 😬
| Add funnel | ||
| </.button> | ||
| </.filter_bar> | ||
| <%= if String.trim(@filter_text) != "" || Enum.count(@funnels) > 0 do %> |
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 the String.trim(@filter_text) != "" condition is redundant here as it's always true when Enum.count(@funnels) > 0 is true. The search input isn't rendered without any funnels, so there cannot be any text in there either, right? Or is there a specific case that I'm missing here?
| <% else %> | ||
| <p class="mt-12 mb-8 text-sm text-center"> | ||
| <span :if={String.trim(@filter_text) != ""}> | ||
| <%= if String.trim(@filter_text) != "" do %> |
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 render function is getting a bit hard to read with the nested if/else conditionals. How about we extract some functions? I'm thinking:
def render(assigns) do
assigns = assign(assigns, :searching?, String.trim(assigns.filter_text) != "")
~H"""
<%= if Enum.count(@funnels) > 0 do %>
# ... keep the filter bar, add button, table
<% else %>
<.no_search_results :if={@searching?}/>
<.create_first_funnel :if={not @searching?}
<% end %>
"""
end
defp no_search_results(assigns) do
~H"""
<p class="mt-12 mb-8 text-sm text-center">
No funnels found for this site. Please refine or
<.styled_link phx-click="reset-filter-text" id="reset-filter-hint">
reset your search.
</.styled_link>
</p>
"""
end| Set up a few goals first (e.g. <b>"Signup"</b>, <b>"Visit /"</b>, or <b>"Scroll 50% on /blog/*"</b>) and return here to build your first funnel! | ||
| </h3> | ||
| <p class="text-center text-sm mt-1 text-gray-500 dark:text-gray-400 leading-5 text-pretty"> | ||
| Set up a few goals like <span class="font-medium text-indigo-600 dark:text-gray-100">Signup</span>, <span class="font-medium text-indigo-600 dark:text-gray-100">Visit /</span>, or |
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.
Could we extract a small inline text component (perhaps <.highlighted> in PlausibleWeb.Components.Generic?) to not have to repeat these classnames for every element? Or if it's something that will definitely not be reused, it could also be a private function in this file. WDYT?
| Add goal | ||
| </.button> | ||
| </.filter_bar> | ||
| <%= if String.trim(@filter_text) != "" || Enum.count(@goals) > 0 do %> |
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.
Ditto: String.trim(@filter_text) != "" || irrelevant?
| <% else %> | ||
| <p class="mt-12 mb-8 text-center text-sm"> | ||
| <span :if={String.trim(@filter_text) != ""}> | ||
| <%= if String.trim(@filter_text) != "" do %> |
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.
Maybe follow the same logic here too (as I suggested for funnels), extracting the components?
| Add property | ||
| </.button> | ||
| </.filter_bar> | ||
| <%= if String.trim(@filter_text) != "" || (is_list(@props) && length(@props) > 0) do %> |
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.
Ditto: String.trim(@filter_text) != "" || irrelevant?
| <% else %> | ||
| <p class="mt-12 mb-8 text-center text-sm"> | ||
| <span :if={String.trim(@filter_text) != ""}> | ||
| <%= if String.trim(@filter_text) != "" do %> |
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.
Ditto: I think extracting functions (like in goals and funnels) could make the render function more readable.
Changes
Tests
Dark mode