Update the internal /sites api to paginate results (#1824)

* Update the internal /sites api to paginate results and adapts site-switcher to it

* Update the Changelog

* Format internal controller

* Remove the `+ Add Site` link from the site-switcher in the dashboard

* Change camel to snake case and replace imports with fully qualified calls

* Remove trailing comma from site-switcher
This commit is contained in:
Andrea Mazzarella 2022-04-18 10:32:01 +01:00 committed by GitHub
parent d2dc06ec96
commit 1128ff4bfa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 18 deletions

View File

@ -33,6 +33,8 @@ All notable changes to this project will be documented in this file.
### Changed
- Cache the tracking script for 24 hours
- Move `entry_page` and `exit_page` to be part of the `Page` filter group
- Paginate /api/sites results and add a `View all` link to the site-switcher dropdown in the dashboard.
- Remove the `+ Add Site` link to the site-switcher dropdown in the dashboard.
## v1.4.1

View File

@ -23,7 +23,7 @@ export default class SiteSwitcher extends React.Component {
document.addEventListener("keydown", this.handleKeydown);
document.addEventListener('click', this.handleClick, false);
}
componentWillUnmount() {
this.siteSwitcherButton.current.removeEventListener("click", this.toggle);
document.removeEventListener("keydown", this.handleKeydown);
@ -38,7 +38,11 @@ export default class SiteSwitcher extends React.Component {
if (!response.ok) { throw response }
return response.json()
})
.then((sites) => this.setState({loading: false, sites: sites}))
.then((sites) => this.setState(
{
loading: false,
sites: sites.data.map(s => s.domain)
}))
.catch((e) => this.setState({loading: false, error: e}))
}
@ -55,7 +59,7 @@ export default class SiteSwitcher extends React.Component {
handleKeydown(e) {
if (!this.props.loggedIn) return;
const { site } = this.props;
const { sites } = this.state;
@ -73,7 +77,7 @@ export default class SiteSwitcher extends React.Component {
toggle(e) {
/**
* React doesn't seem to prioritise its own events when events are bubbling, and is unable to stop its events from propagating to the document's (root) event listeners which are attached on the DOM.
*
*
* A simple trick is to hook up our own click event listener via a ref node, which allows React to manage events in this situation better between the two.
*/
e.stopPropagation();
@ -143,12 +147,9 @@ export default class SiteSwitcher extends React.Component {
{ this.state.sites.map(this.renderSiteLink.bind(this)) }
</div>
<div className="border-t border-gray-200 dark:border-gray-500"></div>
<div className="py-1">
<a href='/sites/new' className="group flex items-center px-4 py-2 md:text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-900 hover:text-gray-900 dark:hover:text-gray-100 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-900 focus:text-gray-900 dark:focus:text-gray-100" role="menuitem">
<svg className="mr-2 h-4 w-4 text-gray-500 dark:text-gray-200 group-hover:text-gray-600 dark:group-hover:text-gray-400 group-focus:text-gray-500 dark:group-focus:text-gray-200" fill="none" stroke="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
Add Site
</a>
</div>
<a href='/sites' className="flex px-4 py-2 md:text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-900 hover:text-gray-900 dark:hover:text-gray-100 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-900 focus:text-gray-900 dark:focus:text-gray-100" role="menuitem">
View all
</a>
</React.Fragment>
)
}

View File

@ -11,14 +11,40 @@ defmodule PlausibleWeb.Api.InternalController do
end
end
def sites(conn, _) do
if conn.assigns[:current_user] do
user = Repo.preload(conn.assigns[:current_user], :sites)
json(conn, Enum.map(user.sites, & &1.domain))
def sites(conn, params) do
current_user = conn.assigns[:current_user]
if current_user do
sites =
sites_for(current_user, params)
|> buildResponse(conn)
json(conn, sites)
else
conn
|> put_status(401)
|> json(%{error: "You need to be logged in to request a list of sites"})
PlausibleWeb.Api.Helpers.unauthorized(
conn,
"You need to be logged in to request a list of sites"
)
end
end
defp sites_for(user, params) do
Repo.paginate(
from(
s in Plausible.Site,
join: sm in Plausible.Site.Membership,
on: sm.site_id == s.id,
where: sm.user_id == ^user.id,
order_by: s.domain
),
params
)
end
defp buildResponse({sites, pagination}, conn) do
%{
data: Enum.map(sites, &%{domain: &1.domain}),
pagination: Phoenix.Pagination.JSON.paginate(conn, pagination)
}
end
end

View File

@ -31,7 +31,9 @@ defmodule PlausibleWeb.Api.InternalControllerTest do
site2 = insert(:site, members: [user])
conn = get(conn, "/api/sites")
assert json_response(conn, 200) == [site.domain, site2.domain]
%{"data" => sites} = json_response(conn, 200)
assert Enum.map(sites, & &1["domain"]) == [site.domain, site2.domain]
end
end