mirror of
https://github.com/kremalicious/umami.git
synced 2024-06-28 16:57:52 +02:00
Return team websites under dashboard.
This commit is contained in:
parent
f4aa8f9661
commit
a84d9a4c7c
1
assets/bar-chart.svg
Normal file
1
assets/bar-chart.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg height="512" viewBox="0 0 24 24" width="512" xmlns="http://www.w3.org/2000/svg"><path d="m7 13v9a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1-1v-9a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1zm7-12h-4a1 1 0 0 0 -1 1v20a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1v-20a1 1 0 0 0 -1-1zm8 5h-4a1 1 0 0 0 -1 1v15a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1v-15a1 1 0 0 0 -1-1z"/></svg>
|
After Width: | Height: | Size: 328 B |
|
@ -1,5 +1,7 @@
|
||||||
import { Icons } from 'react-basics';
|
import { Icons } from 'react-basics';
|
||||||
import AddUser from 'assets/add-user.svg';
|
import AddUser from 'assets/add-user.svg';
|
||||||
|
import Bars from 'assets/bars.svg';
|
||||||
|
import BarChart from 'assets/bar-chart.svg';
|
||||||
import Bolt from 'assets/bolt.svg';
|
import Bolt from 'assets/bolt.svg';
|
||||||
import Calendar from 'assets/calendar.svg';
|
import Calendar from 'assets/calendar.svg';
|
||||||
import Clock from 'assets/clock.svg';
|
import Clock from 'assets/clock.svg';
|
||||||
|
@ -22,6 +24,8 @@ import Visitor from 'assets/visitor.svg';
|
||||||
const icons = {
|
const icons = {
|
||||||
...Icons,
|
...Icons,
|
||||||
AddUser,
|
AddUser,
|
||||||
|
Bars,
|
||||||
|
BarChart,
|
||||||
Bolt,
|
Bolt,
|
||||||
Calendar,
|
Calendar,
|
||||||
Clock,
|
Clock,
|
||||||
|
|
|
@ -18,7 +18,9 @@ export function Dashboard({ userId }) {
|
||||||
const { showCharts, limit, editing } = dashboard;
|
const { showCharts, limit, editing } = dashboard;
|
||||||
const [max, setMax] = useState(limit);
|
const [max, setMax] = useState(limit);
|
||||||
const { get, useQuery } = useApi();
|
const { get, useQuery } = useApi();
|
||||||
const { data, isLoading, error } = useQuery(['websites'], () => get('/websites', { userId }));
|
const { data, isLoading, error } = useQuery(['websites'], () =>
|
||||||
|
get('/websites', { userId, includeTeams: 1 }),
|
||||||
|
);
|
||||||
const hasData = data && data.length !== 0;
|
const hasData = data && data.length !== 0;
|
||||||
const { dir } = useLocale();
|
const { dir } = useLocale();
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Menu, Icon, Text, PopupTrigger, Popup, Item, Button } from 'react-basics';
|
import { TooltipPopup, Icon, Text, Flexbox, Popup, Item, Button } from 'react-basics';
|
||||||
import Icons from 'components/icons';
|
import Icons from 'components/icons';
|
||||||
import { saveDashboard } from 'store/dashboard';
|
import { saveDashboard } from 'store/dashboard';
|
||||||
import useMessages from 'hooks/useMessages';
|
import useMessages from 'hooks/useMessages';
|
||||||
|
@ -6,40 +6,30 @@ import useMessages from 'hooks/useMessages';
|
||||||
export function DashboardSettingsButton() {
|
export function DashboardSettingsButton() {
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
|
|
||||||
const menuOptions = [
|
const handleToggleCharts = () => {
|
||||||
{
|
saveDashboard(state => ({ showCharts: !state.showCharts }));
|
||||||
label: formatMessage(labels.toggleCharts),
|
};
|
||||||
value: 'charts',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: formatMessage(labels.editDashboard),
|
|
||||||
value: 'order',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
function handleSelect(value) {
|
const handleEdit = () => {
|
||||||
if (value === 'charts') {
|
saveDashboard({ editing: true });
|
||||||
saveDashboard(state => ({ showCharts: !state.showCharts }));
|
};
|
||||||
}
|
|
||||||
if (value === 'order') {
|
|
||||||
saveDashboard({ editing: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PopupTrigger>
|
<Flexbox gap={10}>
|
||||||
<Button>
|
<TooltipPopup label={formatMessage(labels.toggleCharts)} position="bottom">
|
||||||
|
<Button onClick={handleToggleCharts}>
|
||||||
|
<Icon>
|
||||||
|
<Icons.BarChart />
|
||||||
|
</Icon>
|
||||||
|
</Button>
|
||||||
|
</TooltipPopup>
|
||||||
|
<Button onClick={handleEdit}>
|
||||||
<Icon>
|
<Icon>
|
||||||
<Icons.Edit />
|
<Icons.Edit />
|
||||||
</Icon>
|
</Icon>
|
||||||
<Text>{formatMessage(labels.edit)}</Text>
|
<Text>{formatMessage(labels.edit)}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Popup alignment="end">
|
</Flexbox>
|
||||||
<Menu variant="popup" items={menuOptions} onSelect={handleSelect}>
|
|
||||||
{({ label, value }) => <Item key={value}>{label}</Item>}
|
|
||||||
</Menu>
|
|
||||||
</Popup>
|
|
||||||
</PopupTrigger>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,9 @@ export default async (
|
||||||
return unauthorized(res);
|
return unauthorized(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
const websites = await getUserWebsites(userId);
|
const { includeTeams } = req.query;
|
||||||
|
|
||||||
|
const websites = await getUserWebsites(userId, { includeTeams });
|
||||||
|
|
||||||
return ok(res, websites);
|
return ok(res, websites);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,64 @@ export async function getUserTeams(userId: string): Promise<
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getUserWebsites(userId: string): Promise<Website[]> {
|
export async function getUserWebsites(
|
||||||
|
userId: string,
|
||||||
|
options?: { includeTeams: boolean },
|
||||||
|
): Promise<Website[]> {
|
||||||
|
const { rawQuery } = prisma;
|
||||||
|
|
||||||
|
if (options?.includeTeams) {
|
||||||
|
const websites = await rawQuery(
|
||||||
|
`
|
||||||
|
select
|
||||||
|
website_id as "id",
|
||||||
|
name,
|
||||||
|
domain,
|
||||||
|
share_id as "shareId",
|
||||||
|
reset_at as "resetAt",
|
||||||
|
user_id as "userId",
|
||||||
|
created_at as "createdAt",
|
||||||
|
updated_at as "updatedAt",
|
||||||
|
deleted_at as "deletedAt",
|
||||||
|
null as "teamId",
|
||||||
|
null as "teamName"
|
||||||
|
from website
|
||||||
|
where user_id = {{userId::uuid}}
|
||||||
|
and deleted_at is null
|
||||||
|
union
|
||||||
|
select
|
||||||
|
w.website_id as "id",
|
||||||
|
w.name,
|
||||||
|
w.domain,
|
||||||
|
w.share_id as "shareId",
|
||||||
|
w.reset_at as "resetAt",
|
||||||
|
w.user_id as "userId",
|
||||||
|
w.created_at as "createdAt",
|
||||||
|
w.updated_at as "updatedAt",
|
||||||
|
w.deleted_at as "deletedAt",
|
||||||
|
t.team_id as "teamId",
|
||||||
|
t.name as "teamName"
|
||||||
|
from website w
|
||||||
|
inner join team_website tw
|
||||||
|
on tw.website_id = w.website_id
|
||||||
|
inner join team t
|
||||||
|
on t.team_id = tw.team_id
|
||||||
|
inner join team_user tu
|
||||||
|
on tu.team_id = tw.team_id
|
||||||
|
where tu.user_id = {{userId::uuid}}
|
||||||
|
and w.deleted_at is null
|
||||||
|
`,
|
||||||
|
{ userId },
|
||||||
|
);
|
||||||
|
|
||||||
|
return websites.reduce((arr, item) => {
|
||||||
|
if (!arr.find(({ id }) => id === item.id)) {
|
||||||
|
return arr.concat(item);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
return prisma.client.website.findMany({
|
return prisma.client.website.findMany({
|
||||||
where: {
|
where: {
|
||||||
userId,
|
userId,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user