mirror of
https://github.com/plausible/analytics.git
synced 2024-11-26 23:27:54 +03:00
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:
parent
d2dc06ec96
commit
1128ff4bfa
@ -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
|
||||
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user