From 8b48130d5f6b7f7bc0de7546a2edcc2d2ecbc225 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sat, 7 Oct 2023 22:42:49 -0700 Subject: [PATCH] Refactored teams components. --- .../(main)/reports/retention/RetentionTable.js | 6 +++--- src/app/(main)/settings/layout.tsx | 6 +++++- .../settings/profile/{page.js => page.tsx} | 5 +++++ src/app/(main)/settings/teams/TeamJoinForm.js | 6 ++++-- src/app/(main)/settings/teams/TeamLeaveButton.js | 2 +- src/app/(main)/settings/teams/TeamsDataTable.js | 4 +++- src/app/(main)/settings/teams/TeamsTable.js | 8 ++++---- .../settings/teams/[id]/TeamWebsiteAddForm.js | 6 ++++-- .../(main)/settings/teams/{page.js => page.tsx} | 5 +++++ src/app/(main)/settings/users/page.tsx | 4 ---- ...ebsitesDataTable.js => WebsitesDataTable.tsx} | 15 +++++++++++++-- .../(main)/settings/websites/WebsitesHeader.js | 4 ++-- .../settings/websites/{page.js => page.tsx} | 9 +++++---- src/app/(main)/websites/WebsitesBrowse.js | 7 ++++--- src/app/(main)/websites/page.js | 12 ------------ src/app/(main)/websites/page.tsx | 16 ++++++++++++++++ src/components/common/DataTable.tsx | 2 +- src/pages/api/teams/index.ts | 2 -- 18 files changed, 75 insertions(+), 44 deletions(-) rename src/app/(main)/settings/profile/{page.js => page.tsx} (65%) rename src/app/(main)/settings/teams/{page.js => page.tsx} (69%) rename src/app/(main)/settings/websites/{WebsitesDataTable.js => WebsitesDataTable.tsx} (79%) rename src/app/(main)/settings/websites/{page.js => page.tsx} (66%) delete mode 100644 src/app/(main)/websites/page.js create mode 100644 src/app/(main)/websites/page.tsx diff --git a/src/app/(main)/reports/retention/RetentionTable.js b/src/app/(main)/reports/retention/RetentionTable.js index 4be7296f..a71fae6f 100644 --- a/src/app/(main)/reports/retention/RetentionTable.js +++ b/src/app/(main)/reports/retention/RetentionTable.js @@ -6,7 +6,9 @@ import { useMessages, useLocale } from 'components/hooks'; import { formatDate } from 'lib/date'; import styles from './RetentionTable.module.css'; -export function RetentionTable() { +const DAYS = [1, 2, 3, 4, 5, 6, 7, 14, 21, 28]; + +export function RetentionTable({ days = DAYS }) { const { formatMessage, labels } = useMessages(); const { locale } = useLocale(); const { report } = useContext(ReportContext); @@ -16,8 +18,6 @@ export function RetentionTable() { return ; } - const days = [1, 2, 3, 4, 5, 6, 7, 14, 21, 28]; - const rows = data.reduce((arr, row) => { const { date, visitors, day } = row; if (day === 0) { diff --git a/src/app/(main)/settings/layout.tsx b/src/app/(main)/settings/layout.tsx index e30b8108..42e9b62f 100644 --- a/src/app/(main)/settings/layout.tsx +++ b/src/app/(main)/settings/layout.tsx @@ -9,7 +9,7 @@ export default function SettingsLayout({ children }) { const { user } = useUser(); const pathname = usePathname(); const { formatMessage, labels } = useMessages(); - const cloudMode = Boolean(process.env.cloudMode); + const cloudMode = !!process.env.cloudMode; const items = [ { key: 'websites', label: formatMessage(labels.websites), url: '/settings/websites' }, @@ -20,6 +20,10 @@ export default function SettingsLayout({ children }) { const getKey = () => items.find(({ url }) => pathname === url)?.key; + if (cloudMode) { + return null; + } + return (
{!cloudMode && ( diff --git a/src/app/(main)/settings/profile/page.js b/src/app/(main)/settings/profile/page.tsx similarity index 65% rename from src/app/(main)/settings/profile/page.js rename to src/app/(main)/settings/profile/page.tsx index c1ea676b..d7a3ad92 100644 --- a/src/app/(main)/settings/profile/page.js +++ b/src/app/(main)/settings/profile/page.tsx @@ -1,5 +1,6 @@ import ProfileHeader from './ProfileHeader'; import ProfileSettings from './ProfileSettings'; +import { Metadata } from 'next'; export default function () { return ( @@ -9,3 +10,7 @@ export default function () { ); } + +export const metadata: Metadata = { + title: 'Profile Settings | umami', +}; diff --git a/src/app/(main)/settings/teams/TeamJoinForm.js b/src/app/(main)/settings/teams/TeamJoinForm.js index 23abcf00..498169d0 100644 --- a/src/app/(main)/settings/teams/TeamJoinForm.js +++ b/src/app/(main)/settings/teams/TeamJoinForm.js @@ -10,6 +10,7 @@ import { } from 'react-basics'; import useApi from 'components/hooks/useApi'; import useMessages from 'components/hooks/useMessages'; +import { setValue } from 'store/cache'; export function TeamJoinForm({ onSave, onClose }) { const { formatMessage, labels, getMessage } = useMessages(); @@ -20,8 +21,9 @@ export function TeamJoinForm({ onSave, onClose }) { const handleSubmit = async data => { mutate(data, { onSuccess: async () => { - onSave(); - onClose(); + setValue('teams', Date.now()); + onSave?.(); + onClose?.(); }, }); }; diff --git a/src/app/(main)/settings/teams/TeamLeaveButton.js b/src/app/(main)/settings/teams/TeamLeaveButton.js index 8cc85487..7b98f082 100644 --- a/src/app/(main)/settings/teams/TeamLeaveButton.js +++ b/src/app/(main)/settings/teams/TeamLeaveButton.js @@ -13,7 +13,7 @@ export function TeamLeaveButton({ teamId, teamName, onLeave }) { diff --git a/src/app/(main)/settings/teams/TeamsDataTable.js b/src/app/(main)/settings/teams/TeamsDataTable.js index 41287f48..49a2fb5b 100644 --- a/src/app/(main)/settings/teams/TeamsDataTable.js +++ b/src/app/(main)/settings/teams/TeamsDataTable.js @@ -3,10 +3,12 @@ import DataTable from 'components/common/DataTable'; import TeamsTable from 'app/(main)/settings/teams/TeamsTable'; import useApi from 'components/hooks/useApi'; import useFilterQuery from 'components/hooks/useFilterQuery'; +import useCache from 'store/cache'; export function TeamsDataTable() { const { get } = useApi(); - const queryResult = useFilterQuery(['teams'], params => { + const modified = useCache(state => state?.websites); + const queryResult = useFilterQuery(['teams', { modified }], params => { return get(`/teams`, { ...params, }); diff --git a/src/app/(main)/settings/teams/TeamsTable.js b/src/app/(main)/settings/teams/TeamsTable.js index 79ddf118..07199167 100644 --- a/src/app/(main)/settings/teams/TeamsTable.js +++ b/src/app/(main)/settings/teams/TeamsTable.js @@ -21,18 +21,18 @@ export function TeamsTable({ data = [] }) { {row => { const { id, name, teamUser } = row; const owner = teamUser.find(({ role }) => role === ROLES.teamOwner); - const showDelete = user.id === owner?.userId; + const isOwner = user.id === owner?.userId; return ( <> - {showDelete && } - {!showDelete && } + {isOwner && } + {!isOwner && } diff --git a/src/app/(main)/settings/teams/[id]/TeamWebsiteAddForm.js b/src/app/(main)/settings/teams/[id]/TeamWebsiteAddForm.js index b2e22442..ba13fbd1 100644 --- a/src/app/(main)/settings/teams/[id]/TeamWebsiteAddForm.js +++ b/src/app/(main)/settings/teams/[id]/TeamWebsiteAddForm.js @@ -3,12 +3,13 @@ import { useState } from 'react'; import { Button, Form, FormButtons, GridColumn, Loading, SubmitButton, Toggle } from 'react-basics'; import useMessages from 'components/hooks/useMessages'; import WebsitesDataTable from '../../websites/WebsitesDataTable'; +import Empty from 'components/common/Empty'; export function TeamWebsiteAddForm({ teamId, onSave, onClose }) { const { formatMessage, labels } = useMessages(); const { get, post, useQuery, useMutation } = useApi(); const { mutate, error } = useMutation(data => post(`/teams/${teamId}/websites`, data)); - const { data: websites } = useQuery(['websites'], () => get('/websites')); + const { data: websites, isLoading } = useQuery(['websites'], () => get('/websites')); const [selected, setSelected] = useState([]); const hasData = websites && websites.data.length > 0; @@ -30,7 +31,8 @@ export function TeamWebsiteAddForm({ teamId, onSave, onClose }) { return ( <> - {!hasData && } + {isLoading && !hasData && } + {!isLoading && !hasData && } {hasData && (
diff --git a/src/app/(main)/settings/teams/page.js b/src/app/(main)/settings/teams/page.tsx similarity index 69% rename from src/app/(main)/settings/teams/page.js rename to src/app/(main)/settings/teams/page.tsx index 6af7eab2..0cdb6f7d 100644 --- a/src/app/(main)/settings/teams/page.js +++ b/src/app/(main)/settings/teams/page.tsx @@ -1,5 +1,6 @@ import TeamsDataTable from './TeamsDataTable'; import TeamsHeader from './TeamsHeader'; +import { Metadata } from 'next'; export default function () { if (process.env.cloudMode) { @@ -13,3 +14,7 @@ export default function () { ); } + +export const metadata: Metadata = { + title: 'Teams Settings | umami', +}; diff --git a/src/app/(main)/settings/users/page.tsx b/src/app/(main)/settings/users/page.tsx index bc0032d5..00ebe98c 100644 --- a/src/app/(main)/settings/users/page.tsx +++ b/src/app/(main)/settings/users/page.tsx @@ -2,10 +2,6 @@ import UsersDataTable from './UsersDataTable'; import { Metadata } from 'next'; export default function () { - if (process.env.cloudMode) { - return null; - } - return ; } export const metadata: Metadata = { diff --git a/src/app/(main)/settings/websites/WebsitesDataTable.js b/src/app/(main)/settings/websites/WebsitesDataTable.tsx similarity index 79% rename from src/app/(main)/settings/websites/WebsitesDataTable.js rename to src/app/(main)/settings/websites/WebsitesDataTable.tsx index 9de7d2e4..6e716291 100644 --- a/src/app/(main)/settings/websites/WebsitesDataTable.js +++ b/src/app/(main)/settings/websites/WebsitesDataTable.tsx @@ -1,4 +1,5 @@ 'use client'; +import { ReactNode } from 'react'; import WebsitesTable from 'app/(main)/settings/websites/WebsitesTable'; import useUser from 'components/hooks/useUser'; import useApi from 'components/hooks/useApi'; @@ -6,10 +7,20 @@ import DataTable from 'components/common/DataTable'; import useFilterQuery from 'components/hooks/useFilterQuery'; import useCache from 'store/cache'; +export interface WebsitesDataTableProps { + allowEdit?: boolean; + allowView?: boolean; + showActions?: boolean; + showTeam?: boolean; + includeTeams?: boolean; + onlyTeams?: boolean; + children?: ReactNode; +} + function useWebsites({ includeTeams, onlyTeams }) { const { user } = useUser(); const { get } = useApi(); - const modified = useCache(state => state?.websites); + const modified = useCache((state: any) => state?.websites); return useFilterQuery( ['websites', { includeTeams, onlyTeams, modified }], @@ -32,7 +43,7 @@ export function WebsitesDataTable({ includeTeams, onlyTeams, children, -}) { +}: WebsitesDataTableProps) { const queryResult = useWebsites({ includeTeams, onlyTeams }); return ( diff --git a/src/app/(main)/settings/websites/WebsitesHeader.js b/src/app/(main)/settings/websites/WebsitesHeader.js index 6ce58d1e..61bfb886 100644 --- a/src/app/(main)/settings/websites/WebsitesHeader.js +++ b/src/app/(main)/settings/websites/WebsitesHeader.js @@ -3,12 +3,12 @@ import useMessages from 'components/hooks/useMessages'; import PageHeader from 'components/layout/PageHeader'; import WebsiteAddButton from './WebsiteAddButton'; -export function WebsitesHeader() { +export function WebsitesHeader({ showActions = true }) { const { formatMessage, labels } = useMessages(); return ( - {!process.env.cloudMode && } + {!process.env.cloudMode && showActions && } ); } diff --git a/src/app/(main)/settings/websites/page.js b/src/app/(main)/settings/websites/page.tsx similarity index 66% rename from src/app/(main)/settings/websites/page.js rename to src/app/(main)/settings/websites/page.tsx index 6b9c754d..2c83dce0 100644 --- a/src/app/(main)/settings/websites/page.js +++ b/src/app/(main)/settings/websites/page.tsx @@ -1,11 +1,8 @@ import WebsitesDataTable from './WebsitesDataTable'; import WebsitesHeader from './WebsitesHeader'; +import { Metadata } from 'next'; export default function () { - if (process.env.cloudMode) { - return null; - } - return ( <> @@ -13,3 +10,7 @@ export default function () { ); } + +export const metadata: Metadata = { + title: 'Websites Settings | umami', +}; diff --git a/src/app/(main)/websites/WebsitesBrowse.js b/src/app/(main)/websites/WebsitesBrowse.js index 1fa44a6d..f1bab7bf 100644 --- a/src/app/(main)/websites/WebsitesBrowse.js +++ b/src/app/(main)/websites/WebsitesBrowse.js @@ -1,5 +1,5 @@ 'use client'; -import WebsiteList from '../settings/websites/WebsitesDataTable'; +import WebsitesDataTable from '../settings/websites/WebsitesDataTable'; import { useMessages } from 'components/hooks'; import { useState } from 'react'; import { Item, Tabs } from 'react-basics'; @@ -12,6 +12,7 @@ const TABS = { export function WebsitesBrowse() { const { formatMessage, labels } = useMessages(); const [tab, setTab] = useState(TABS.myWebsites); + const allowEdit = !process.env.cloudMode; return ( <> @@ -19,9 +20,9 @@ export function WebsitesBrowse() { {formatMessage(labels.myWebsites)} {formatMessage(labels.teamWebsites)} - {tab === TABS.myWebsites && } + {tab === TABS.myWebsites && } {tab === TABS.teamWebsites && ( - + )} ); diff --git a/src/app/(main)/websites/page.js b/src/app/(main)/websites/page.js deleted file mode 100644 index 07c82a50..00000000 --- a/src/app/(main)/websites/page.js +++ /dev/null @@ -1,12 +0,0 @@ -'use client'; -import WebsitesHeader from '../../(main)/settings/websites/WebsitesHeader'; -import WebsitesBrowse from './WebsitesBrowse'; - -export default function WebsitesPage() { - return ( - <> - - - - ); -} diff --git a/src/app/(main)/websites/page.tsx b/src/app/(main)/websites/page.tsx new file mode 100644 index 00000000..a1542510 --- /dev/null +++ b/src/app/(main)/websites/page.tsx @@ -0,0 +1,16 @@ +import WebsitesHeader from 'app/(main)/settings/websites/WebsitesHeader'; +import WebsitesBrowse from './WebsitesBrowse'; +import { Metadata } from 'next'; + +export default function WebsitesPage() { + return ( + <> + + + + ); +} + +export const metadata: Metadata = { + title: 'Websites | umami', +}; diff --git a/src/components/common/DataTable.tsx b/src/components/common/DataTable.tsx index df1468fb..3efee024 100644 --- a/src/components/common/DataTable.tsx +++ b/src/components/common/DataTable.tsx @@ -45,7 +45,7 @@ export function DataTable({ const noResults = Boolean(!isLoading && query && !hasData); const handleSearch = query => { - setParams({ ...params, query }); + setParams({ ...params, query, page: params.query ? page : 1 }); }; const handlePageChange = page => { diff --git a/src/pages/api/teams/index.ts b/src/pages/api/teams/index.ts index 5ad7321e..4a9f4bb4 100644 --- a/src/pages/api/teams/index.ts +++ b/src/pages/api/teams/index.ts @@ -14,8 +14,6 @@ export interface TeamsRequestBody { name: string; } -export interface MyTeamsRequestQuery extends SearchFilter {} - const schema = { GET: yup.object().shape({ ...pageInfo,