mirror of
https://github.com/kremalicious/umami.git
synced 2024-11-22 18:00:17 +01:00
Replaced SettingsTable with DataTable.
This commit is contained in:
parent
0d9b6e8355
commit
9bb89c7e8b
@ -1,3 +1,4 @@
|
|||||||
|
'use client';
|
||||||
import { useState, useMemo } from 'react';
|
import { useState, useMemo } from 'react';
|
||||||
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
|
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
@ -7,7 +8,6 @@ import useDashboard, { saveDashboard } from 'store/dashboard';
|
|||||||
import useMessages from 'components/hooks/useMessages';
|
import useMessages from 'components/hooks/useMessages';
|
||||||
import useApi from 'components/hooks/useApi';
|
import useApi from 'components/hooks/useApi';
|
||||||
import styles from './DashboardEdit.module.css';
|
import styles from './DashboardEdit.module.css';
|
||||||
import Page from 'components/layout/Page';
|
|
||||||
|
|
||||||
const dragId = 'dashboard-website-ordering';
|
const dragId = 'dashboard-website-ordering';
|
||||||
|
|
||||||
@ -17,11 +17,7 @@ export function DashboardEdit() {
|
|||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const [order, setOrder] = useState(websiteOrder || []);
|
const [order, setOrder] = useState(websiteOrder || []);
|
||||||
const { get, useQuery } = useApi();
|
const { get, useQuery } = useApi();
|
||||||
const {
|
const { data: result } = useQuery(['websites'], () => get('/websites', { includeTeams: 1 }));
|
||||||
data: result,
|
|
||||||
isLoading,
|
|
||||||
error,
|
|
||||||
} = useQuery(['websites'], () => get('/websites', { includeTeams: 1 }));
|
|
||||||
const { data: websites } = result || {};
|
const { data: websites } = result || {};
|
||||||
|
|
||||||
const ordered = useMemo(() => {
|
const ordered = useMemo(() => {
|
||||||
@ -59,7 +55,7 @@ export function DashboardEdit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page loading={isLoading} error={error}>
|
<>
|
||||||
<div className={styles.buttons}>
|
<div className={styles.buttons}>
|
||||||
<Button onClick={handleSave} variant="action" size="small">
|
<Button onClick={handleSave} variant="action" size="small">
|
||||||
{formatMessage(labels.save)}
|
{formatMessage(labels.save)}
|
||||||
@ -105,7 +101,7 @@ export function DashboardEdit() {
|
|||||||
</Droppable>
|
</Droppable>
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
</div>
|
</div>
|
||||||
</Page>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
'use client';
|
|
||||||
import Shell from './Shell';
|
import Shell from './Shell';
|
||||||
import NavBar from './NavBar';
|
import NavBar from './NavBar';
|
||||||
import Page from 'components/layout/Page';
|
import Page from 'components/layout/Page';
|
||||||
|
@ -4,7 +4,6 @@ import { useMessages } from 'components/hooks';
|
|||||||
import useUser from 'components/hooks/useUser';
|
import useUser from 'components/hooks/useUser';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Flexbox,
|
|
||||||
GridColumn,
|
GridColumn,
|
||||||
GridTable,
|
GridTable,
|
||||||
Icon,
|
Icon,
|
||||||
@ -43,7 +42,7 @@ export function ReportsTable({ data = [], onDelete, showDomain }) {
|
|||||||
{row => {
|
{row => {
|
||||||
const { id, name, userId, website } = row;
|
const { id, name, userId, website } = row;
|
||||||
return (
|
return (
|
||||||
<Flexbox gap={10}>
|
<>
|
||||||
<LinkButton href={`/reports/${id}`}>{formatMessage(labels.view)}</LinkButton>
|
<LinkButton href={`/reports/${id}`}>{formatMessage(labels.view)}</LinkButton>
|
||||||
{(user.id === userId || user.id === website?.userId) && (
|
{(user.id === userId || user.id === website?.userId) && (
|
||||||
<ModalTrigger>
|
<ModalTrigger>
|
||||||
@ -64,7 +63,7 @@ export function ReportsTable({ data = [], onDelete, showDomain }) {
|
|||||||
</Modal>
|
</Modal>
|
||||||
</ModalTrigger>
|
</ModalTrigger>
|
||||||
)}
|
)}
|
||||||
</Flexbox>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</GridColumn>
|
</GridColumn>
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
min-height: 50vh;
|
min-height: 50vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import useMessages from 'components/hooks/useMessages';
|
|||||||
import useUser from 'components/hooks/useUser';
|
import useUser from 'components/hooks/useUser';
|
||||||
import { ROLES } from 'lib/constants';
|
import { ROLES } from 'lib/constants';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { Button, Flexbox, GridColumn, GridTable, Icon, Icons, Text } from 'react-basics';
|
import { Button, GridColumn, GridTable, Icon, Icons, Text } from 'react-basics';
|
||||||
import TeamDeleteButton from './TeamDeleteButton';
|
import TeamDeleteButton from './TeamDeleteButton';
|
||||||
import TeamLeaveButton from './TeamLeaveButton';
|
import TeamLeaveButton from './TeamLeaveButton';
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ export function TeamsTable({ data = [] }) {
|
|||||||
const showDelete = user.id === owner?.userId;
|
const showDelete = user.id === owner?.userId;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flexbox gap={10}>
|
<>
|
||||||
<Link href={`/settings/teams/${id}`}>
|
<Link href={`/settings/teams/${id}`}>
|
||||||
<Button>
|
<Button>
|
||||||
<Icon>
|
<Icon>
|
||||||
@ -35,7 +35,7 @@ export function TeamsTable({ data = [] }) {
|
|||||||
</Link>
|
</Link>
|
||||||
{showDelete && <TeamDeleteButton teamId={id} teamName={name} />}
|
{showDelete && <TeamDeleteButton teamId={id} teamName={name} />}
|
||||||
{!showDelete && <TeamLeaveButton teamId={id} teamName={name} />}
|
{!showDelete && <TeamLeaveButton teamId={id} teamName={name} />}
|
||||||
</Flexbox>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</GridColumn>
|
</GridColumn>
|
||||||
|
@ -1,46 +1,25 @@
|
|||||||
import { Loading, useToasts } from 'react-basics';
|
|
||||||
import useApi from 'components/hooks/useApi';
|
import useApi from 'components/hooks/useApi';
|
||||||
import useMessages from 'components/hooks/useMessages';
|
|
||||||
import useApiFilter from 'components/hooks/useApiFilter';
|
|
||||||
import TeamMembersTable from './TeamMembersTable';
|
import TeamMembersTable from './TeamMembersTable';
|
||||||
|
import useFilterQuery from 'components/hooks/useFilterQuery';
|
||||||
|
import DataTable from 'components/common/DataTable';
|
||||||
|
|
||||||
export function TeamMembers({ teamId, readOnly }) {
|
export function TeamMembers({ teamId, readOnly }) {
|
||||||
const { showToast } = useToasts();
|
const { get } = useApi();
|
||||||
const { formatMessage, messages } = useMessages();
|
const { getProps } = useFilterQuery(
|
||||||
const { filter, page, pageSize, handleFilterChange, handlePageChange, handlePageSizeChange } =
|
['team:users', teamId],
|
||||||
useApiFilter();
|
params => {
|
||||||
const { get, useQuery } = useApi();
|
return get(`/teams/${teamId}/users`, {
|
||||||
const { data, isLoading, refetch } = useQuery(
|
...params,
|
||||||
['teams:users', teamId, filter, page, pageSize],
|
});
|
||||||
() =>
|
},
|
||||||
get(`/teams/${teamId}/users`, {
|
{ enabled: !!teamId },
|
||||||
filter,
|
|
||||||
page,
|
|
||||||
pageSize,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
return <Loading icon="dots" style={{ minHeight: 300 }} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSave = async () => {
|
|
||||||
await refetch();
|
|
||||||
showToast({ message: formatMessage(messages.saved), variant: 'success' });
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TeamMembersTable
|
<DataTable {...getProps()}>
|
||||||
onSave={handleSave}
|
{({ data }) => <TeamMembersTable data={data} readOnly={readOnly} />}
|
||||||
teamId={teamId}
|
</DataTable>
|
||||||
data={data}
|
|
||||||
readOnly={readOnly}
|
|
||||||
onFilterChange={handleFilterChange}
|
|
||||||
onPageChange={handlePageChange}
|
|
||||||
onPageSizeChange={handlePageSizeChange}
|
|
||||||
filterValue={filter}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,67 +1,36 @@
|
|||||||
|
import { GridColumn, GridTable } from 'react-basics';
|
||||||
import useMessages from 'components/hooks/useMessages';
|
import useMessages from 'components/hooks/useMessages';
|
||||||
import useUser from 'components/hooks/useUser';
|
import useUser from 'components/hooks/useUser';
|
||||||
import { ROLES } from 'lib/constants';
|
import { ROLES } from 'lib/constants';
|
||||||
import TeamMemberRemoveButton from './TeamMemberRemoveButton';
|
import TeamMemberRemoveButton from './TeamMemberRemoveButton';
|
||||||
import SettingsTable from 'components/common/SettingsTable';
|
|
||||||
|
|
||||||
export function TeamMembersTable({
|
export function TeamMembersTable({ data = [], teamId, readOnly, onChange }) {
|
||||||
data = [],
|
|
||||||
teamId,
|
|
||||||
onSave,
|
|
||||||
readOnly,
|
|
||||||
filterValue,
|
|
||||||
onFilterChange,
|
|
||||||
onPageChange,
|
|
||||||
onPageSizeChange,
|
|
||||||
}) {
|
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
|
|
||||||
const columns = [
|
const roles = {
|
||||||
{ name: 'username', label: formatMessage(labels.username) },
|
[ROLES.teamOwner]: formatMessage(labels.teamOwner),
|
||||||
{ name: 'role', label: formatMessage(labels.role) },
|
[ROLES.teamMember]: formatMessage(labels.teamMember),
|
||||||
{ name: 'action', label: ' ' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const cellRender = (row, data, key) => {
|
|
||||||
if (key === 'username') {
|
|
||||||
return row?.username;
|
|
||||||
}
|
|
||||||
if (key === 'role') {
|
|
||||||
return formatMessage(
|
|
||||||
labels[
|
|
||||||
Object.keys(ROLES).find(key => ROLES[key] === row?.teamUser[0]?.role) || labels.unknown
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return data[key];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsTable
|
<GridTable data={data}>
|
||||||
data={data}
|
<GridColumn name="username" label={formatMessage(labels.username)} />
|
||||||
columns={columns}
|
<GridColumn name="role" label={formatMessage(labels.role)}>
|
||||||
cellRender={cellRender}
|
{row => roles[row?.teamUser?.[0]?.role]}
|
||||||
showSearch={true}
|
</GridColumn>
|
||||||
showPaging={true}
|
<GridColumn name="action" label=" " alignment="end">
|
||||||
onFilterChange={onFilterChange}
|
{row => {
|
||||||
onPageChange={onPageChange}
|
return (
|
||||||
onPageSizeChange={onPageSizeChange}
|
!readOnly &&
|
||||||
filterValue={filterValue}
|
row?.teamUser?.[0]?.role !== ROLES.teamOwner &&
|
||||||
>
|
user?.id !== row?.id && (
|
||||||
{row => {
|
<TeamMemberRemoveButton teamId={teamId} userId={row.id} onSave={onChange} />
|
||||||
return (
|
)
|
||||||
!readOnly && (
|
);
|
||||||
<TeamMemberRemoveButton
|
}}
|
||||||
teamId={teamId}
|
</GridColumn>
|
||||||
userId={row.id}
|
</GridTable>
|
||||||
disabled={user.id === row?.user?.id || row.role === ROLES.teamOwner}
|
|
||||||
onSave={onSave}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</SettingsTable>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Item, Loading, Tabs, useToasts } from 'react-basics';
|
import { Item, Loading, Tabs, useToasts, Flexbox } from 'react-basics';
|
||||||
import PageHeader from 'components/layout/PageHeader';
|
import PageHeader from 'components/layout/PageHeader';
|
||||||
import { ROLES } from 'lib/constants';
|
import { ROLES } from 'lib/constants';
|
||||||
import useUser from 'components/hooks/useUser';
|
import useUser from 'components/hooks/useUser';
|
||||||
@ -46,7 +46,7 @@ export function TeamSettings({ teamId }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Flexbox direction="column">
|
||||||
<PageHeader title={values?.name} />
|
<PageHeader title={values?.name} />
|
||||||
<Tabs selectedKey={tab} onSelect={setTab} style={{ marginBottom: 30 }}>
|
<Tabs selectedKey={tab} onSelect={setTab} style={{ marginBottom: 30 }}>
|
||||||
<Item key="details">{formatMessage(labels.details)}</Item>
|
<Item key="details">{formatMessage(labels.details)}</Item>
|
||||||
@ -58,7 +58,7 @@ export function TeamSettings({ teamId }) {
|
|||||||
)}
|
)}
|
||||||
{tab === 'members' && <TeamMembers teamId={teamId} readOnly={!canEdit} />}
|
{tab === 'members' && <TeamMembers teamId={teamId} readOnly={!canEdit} />}
|
||||||
{tab === 'websites' && <TeamWebsites teamId={teamId} readOnly={!canEdit} />}
|
{tab === 'websites' && <TeamWebsites teamId={teamId} readOnly={!canEdit} />}
|
||||||
</>
|
</Flexbox>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,75 +1,49 @@
|
|||||||
import {
|
import { ActionForm, Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics';
|
||||||
ActionForm,
|
|
||||||
Button,
|
|
||||||
Icon,
|
|
||||||
Icons,
|
|
||||||
Loading,
|
|
||||||
Modal,
|
|
||||||
ModalTrigger,
|
|
||||||
Text,
|
|
||||||
useToasts,
|
|
||||||
} from 'react-basics';
|
|
||||||
import TeamWebsitesTable from './TeamWebsitesTable';
|
import TeamWebsitesTable from './TeamWebsitesTable';
|
||||||
import TeamAddWebsiteForm from './TeamAddWebsiteForm';
|
import TeamAddWebsiteForm from './TeamAddWebsiteForm';
|
||||||
import useApi from 'components/hooks/useApi';
|
import useApi from 'components/hooks/useApi';
|
||||||
import useMessages from 'components/hooks/useMessages';
|
import useMessages from 'components/hooks/useMessages';
|
||||||
import useApiFilter from 'components/hooks/useApiFilter';
|
import useUser from 'components/hooks/useUser';
|
||||||
|
import useFilterQuery from 'components/hooks/useFilterQuery';
|
||||||
|
import DataTable from 'components/common/DataTable';
|
||||||
|
|
||||||
export function TeamWebsites({ teamId }) {
|
export function TeamWebsites({ teamId }) {
|
||||||
const { showToast } = useToasts();
|
|
||||||
const { formatMessage, labels, messages } = useMessages();
|
const { formatMessage, labels, messages } = useMessages();
|
||||||
const { filter, page, pageSize, handleFilterChange, handlePageChange, handlePageSizeChange } =
|
const { user } = useUser();
|
||||||
useApiFilter();
|
const { get } = useApi();
|
||||||
const { get, useQuery } = useApi();
|
const { getProps, refetch } = useFilterQuery(
|
||||||
const { data, isLoading, refetch } = useQuery(
|
['team:websites', teamId],
|
||||||
['teams:websites', teamId, filter, page, pageSize],
|
params => {
|
||||||
() =>
|
return get(`/teams/${teamId}/websites`, {
|
||||||
get(`/teams/${teamId}/websites`, {
|
...params,
|
||||||
filter,
|
});
|
||||||
page,
|
},
|
||||||
pageSize,
|
{ enabled: !!user },
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
const hasData = data && data.length !== 0;
|
|
||||||
|
|
||||||
if (isLoading) {
|
const handleWebsiteAdd = () => {
|
||||||
return <Loading icon="dots" style={{ minHeight: 300 }} />;
|
refetch();
|
||||||
}
|
|
||||||
|
|
||||||
const handleSave = async () => {
|
|
||||||
await refetch();
|
|
||||||
showToast({ message: formatMessage(messages.saved), variant: 'success' });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const addButton = (
|
|
||||||
<ModalTrigger>
|
|
||||||
<Button variant="primary">
|
|
||||||
<Icon>
|
|
||||||
<Icons.Plus />
|
|
||||||
</Icon>
|
|
||||||
<Text>{formatMessage(labels.addWebsite)}</Text>
|
|
||||||
</Button>
|
|
||||||
<Modal title={formatMessage(labels.addWebsite)}>
|
|
||||||
{close => <TeamAddWebsiteForm teamId={teamId} onSave={handleSave} onClose={close} />}
|
|
||||||
</Modal>
|
|
||||||
</ModalTrigger>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
<ActionForm description={formatMessage(messages.teamWebsitesInfo)}>{addButton}</ActionForm>
|
<ActionForm description={formatMessage(messages.teamWebsitesInfo)}>
|
||||||
{hasData && (
|
<ModalTrigger>
|
||||||
<TeamWebsitesTable
|
<Button variant="primary">
|
||||||
teamId={teamId}
|
<Icon>
|
||||||
data={data}
|
<Icons.Plus />
|
||||||
onSave={handleSave}
|
</Icon>
|
||||||
onFilterChange={handleFilterChange}
|
<Text>{formatMessage(labels.addWebsite)}</Text>
|
||||||
onPageChange={handlePageChange}
|
</Button>
|
||||||
onPageSizeChange={handlePageSizeChange}
|
<Modal title={formatMessage(labels.addWebsite)}>
|
||||||
filterValue={filter}
|
{close => (
|
||||||
/>
|
<TeamAddWebsiteForm teamId={teamId} onSave={handleWebsiteAdd} onClose={close} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</Modal>
|
||||||
|
</ModalTrigger>
|
||||||
|
</ActionForm>
|
||||||
|
<DataTable {...getProps()}>{({ data }) => <TeamWebsitesTable data={data} />}</DataTable>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,65 +1,41 @@
|
|||||||
import useMessages from 'components/hooks/useMessages';
|
import useMessages from 'components/hooks/useMessages';
|
||||||
import useUser from 'components/hooks/useUser';
|
import useUser from 'components/hooks/useUser';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { Button, Icon, Icons, Text } from 'react-basics';
|
import { Button, GridColumn, GridTable, Icon, Icons, Text } from 'react-basics';
|
||||||
import TeamWebsiteRemoveButton from '../TeamWebsiteRemoveButton';
|
import TeamWebsiteRemoveButton from '../TeamWebsiteRemoveButton';
|
||||||
import SettingsTable from 'components/common/SettingsTable';
|
|
||||||
|
|
||||||
export function TeamWebsitesTable({
|
export function TeamWebsitesTable({ data = [], onSave }) {
|
||||||
data = [],
|
|
||||||
onSave,
|
|
||||||
filterValue,
|
|
||||||
onFilterChange,
|
|
||||||
onPageChange,
|
|
||||||
onPageSizeChange,
|
|
||||||
openExternal = false,
|
|
||||||
}) {
|
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
|
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
const columns = [
|
|
||||||
{ name: 'name', label: formatMessage(labels.name) },
|
|
||||||
{ name: 'domain', label: formatMessage(labels.domain) },
|
|
||||||
{ name: 'action', label: ' ' },
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsTable
|
<GridTable data={data}>
|
||||||
columns={columns}
|
<GridColumn name="name" label={formatMessage(labels.name)} />
|
||||||
data={data}
|
<GridColumn name="domain" label={formatMessage(labels.domain)} />
|
||||||
showSearch={true}
|
<GridColumn name="action" label=" " alignment="end">
|
||||||
showPaging={true}
|
{row => {
|
||||||
onFilterChange={onFilterChange}
|
const { id: teamId, teamUser } = row.teamWebsite[0].team;
|
||||||
onPageChange={onPageChange}
|
const { id: websiteId, userId } = row;
|
||||||
onPageSizeChange={onPageSizeChange}
|
const owner = teamUser[0];
|
||||||
filterValue={filterValue}
|
const canRemove = user.id === userId || user.id === owner.userId;
|
||||||
>
|
return (
|
||||||
{row => {
|
<>
|
||||||
const { id: teamId, teamUser } = row.teamWebsite[0].team;
|
<Link href={`/websites/${websiteId}`}>
|
||||||
const { id: websiteId, name, domain, userId } = row;
|
<Button>
|
||||||
const owner = teamUser[0];
|
<Icon>
|
||||||
const canRemove = user.id === userId || user.id === owner.userId;
|
<Icons.External />
|
||||||
|
</Icon>
|
||||||
row.name = name;
|
<Text>{formatMessage(labels.view)}</Text>
|
||||||
row.domain = domain;
|
</Button>
|
||||||
|
</Link>
|
||||||
return (
|
{canRemove && (
|
||||||
<>
|
<TeamWebsiteRemoveButton teamId={teamId} websiteId={websiteId} onSave={onSave} />
|
||||||
<Link href={`/websites/${websiteId}`} target={openExternal ? '_blank' : null}>
|
)}
|
||||||
<Button>
|
</>
|
||||||
<Icon>
|
);
|
||||||
<Icons.External />
|
}}
|
||||||
</Icon>
|
</GridColumn>
|
||||||
<Text>{formatMessage(labels.view)}</Text>
|
</GridTable>
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
{canRemove && (
|
|
||||||
<TeamWebsiteRemoveButton teamId={teamId} websiteId={websiteId} onSave={onSave} />
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</SettingsTable>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Button, Text, Icon, Icons, GridTable, GridColumn, Flexbox } from 'react-basics';
|
import { Button, Text, Icon, Icons, GridTable, GridColumn } from 'react-basics';
|
||||||
import { formatDistance } from 'date-fns';
|
import { formatDistance } from 'date-fns';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { ROLES } from 'lib/constants';
|
import { ROLES } from 'lib/constants';
|
||||||
@ -36,7 +36,7 @@ export function UsersTable({ data = [] }) {
|
|||||||
{row => {
|
{row => {
|
||||||
const { id, username } = row;
|
const { id, username } = row;
|
||||||
return (
|
return (
|
||||||
<Flexbox gap={10}>
|
<>
|
||||||
<Link href={`/settings/users/${id}`}>
|
<Link href={`/settings/users/${id}`}>
|
||||||
<Button>
|
<Button>
|
||||||
<Icon>
|
<Icon>
|
||||||
@ -46,7 +46,7 @@ export function UsersTable({ data = [] }) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
<UserDeleteButton userId={id} username={username} />
|
<UserDeleteButton userId={id} username={username} />
|
||||||
</Flexbox>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</GridColumn>
|
</GridColumn>
|
||||||
|
@ -6,7 +6,7 @@ import DataTable from 'components/common/DataTable';
|
|||||||
import useFilterQuery from 'components/hooks/useFilterQuery';
|
import useFilterQuery from 'components/hooks/useFilterQuery';
|
||||||
import WebsitesHeader from './WebsitesHeader';
|
import WebsitesHeader from './WebsitesHeader';
|
||||||
|
|
||||||
export function WebsitesList({
|
export function Websites({
|
||||||
showHeader = true,
|
showHeader = true,
|
||||||
showEditButton = true,
|
showEditButton = true,
|
||||||
showTeam,
|
showTeam,
|
||||||
@ -40,4 +40,4 @@ export function WebsitesList({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WebsitesList;
|
export default Websites;
|
@ -1,5 +1,5 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { Button, Text, Icon, Icons, GridTable, GridColumn, Flexbox } from 'react-basics';
|
import { Button, Text, Icon, Icons, GridTable, GridColumn } from 'react-basics';
|
||||||
import useMessages from 'components/hooks/useMessages';
|
import useMessages from 'components/hooks/useMessages';
|
||||||
import useUser from 'components/hooks/useUser';
|
import useUser from 'components/hooks/useUser';
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ export function WebsitesTable({ data = [], showTeam, showEditButton }) {
|
|||||||
} = row;
|
} = row;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flexbox gap={10}>
|
<>
|
||||||
{showEditButton && (!showTeam || ownerId === user.id) && (
|
{showEditButton && (!showTeam || ownerId === user.id) && (
|
||||||
<Link href={`/settings/websites/${id}`}>
|
<Link href={`/settings/websites/${id}`}>
|
||||||
<Button>
|
<Button>
|
||||||
@ -48,7 +48,7 @@ export function WebsitesTable({ data = [], showTeam, showEditButton }) {
|
|||||||
<Text>{formatMessage(labels.view)}</Text>
|
<Text>{formatMessage(labels.view)}</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</Flexbox>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</GridColumn>
|
</GridColumn>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import WebsitesList from 'app/(app)/settings/websites/WebsitesList';
|
import Websites from './Websites';
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
if (process.env.cloudMode) {
|
if (process.env.cloudMode) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <WebsitesList />;
|
return <Websites />;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import WebsiteList from 'app/(app)/settings/websites/WebsitesList';
|
import WebsiteList from '../settings/websites/Websites';
|
||||||
import { useMessages } from 'components/hooks';
|
import { useMessages } from 'components/hooks';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Item, Tabs } from 'react-basics';
|
import { Item, Tabs } from 'react-basics';
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.body td {
|
.body td {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
min-height: 70px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
import Empty from 'components/common/Empty';
|
|
||||||
import useMessages from 'components/hooks/useMessages';
|
|
||||||
import { useState } from 'react';
|
|
||||||
import {
|
|
||||||
SearchField,
|
|
||||||
Table,
|
|
||||||
TableBody,
|
|
||||||
TableCell,
|
|
||||||
TableColumn,
|
|
||||||
TableHeader,
|
|
||||||
TableRow,
|
|
||||||
} from 'react-basics';
|
|
||||||
import styles from './SettingsTable.module.css';
|
|
||||||
import Pager from 'components/common/Pager';
|
|
||||||
|
|
||||||
export function SettingsTable({
|
|
||||||
columns = [],
|
|
||||||
data,
|
|
||||||
children,
|
|
||||||
cellRender,
|
|
||||||
showSearch,
|
|
||||||
showPaging,
|
|
||||||
onFilterChange,
|
|
||||||
onPageChange,
|
|
||||||
onPageSizeChange,
|
|
||||||
filterValue,
|
|
||||||
}) {
|
|
||||||
const { formatMessage, labels, messages } = useMessages();
|
|
||||||
const [filter, setFilter] = useState(filterValue);
|
|
||||||
const { data: value, page, count, pageSize } = data;
|
|
||||||
|
|
||||||
const handleFilterChange = value => {
|
|
||||||
setFilter(value);
|
|
||||||
onFilterChange(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{showSearch && (value.length > 0 || filterValue) && (
|
|
||||||
<SearchField
|
|
||||||
onChange={handleFilterChange}
|
|
||||||
delay={1000}
|
|
||||||
value={filter}
|
|
||||||
autoFocus={true}
|
|
||||||
placeholder={formatMessage(labels.search)}
|
|
||||||
style={{ maxWidth: '300px', marginBottom: '10px' }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{value.length === 0 && filterValue && (
|
|
||||||
<Empty message={formatMessage(messages.noResultsFound)} />
|
|
||||||
)}
|
|
||||||
{value.length > 0 && (
|
|
||||||
<Table columns={columns} rows={value}>
|
|
||||||
<TableHeader className={styles.header}>
|
|
||||||
{(column, index) => {
|
|
||||||
return (
|
|
||||||
<TableColumn key={index} className={styles.cell} style={columns[index].style}>
|
|
||||||
{column.label}
|
|
||||||
</TableColumn>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody className={styles.body}>
|
|
||||||
{(row, keys, rowIndex) => {
|
|
||||||
row.action = children(row, keys, rowIndex);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TableRow key={rowIndex} data={row} keys={keys} className={styles.row}>
|
|
||||||
{(data, key, colIndex) => {
|
|
||||||
return (
|
|
||||||
<TableCell
|
|
||||||
key={colIndex}
|
|
||||||
className={styles.cell}
|
|
||||||
style={columns[colIndex].style}
|
|
||||||
>
|
|
||||||
<label className={styles.label}>{columns[colIndex].label}</label>
|
|
||||||
{cellRender ? cellRender(row, data, key, colIndex) : data[key]}
|
|
||||||
</TableCell>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</TableBody>
|
|
||||||
{showPaging && (
|
|
||||||
<Pager
|
|
||||||
page={page}
|
|
||||||
pageSize={pageSize}
|
|
||||||
count={count}
|
|
||||||
onPageChange={onPageChange}
|
|
||||||
onPageSizeChange={onPageSizeChange}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Table>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SettingsTable;
|
|
@ -1,44 +0,0 @@
|
|||||||
.cell {
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.row .cell:last-child {
|
|
||||||
gap: 10px;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
display: none;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 992px) {
|
|
||||||
.header .cell {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
display: block;
|
|
||||||
min-width: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.row .cell {
|
|
||||||
padding-left: 0;
|
|
||||||
flex-basis: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 1200px) {
|
|
||||||
.row {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header .cell:last-child {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.row .cell:last-child {
|
|
||||||
padding-left: 0;
|
|
||||||
flex-basis: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +1,4 @@
|
|||||||
|
'use client';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Banner, Loading } from 'react-basics';
|
import { Banner, Loading } from 'react-basics';
|
||||||
|
@ -5,7 +5,7 @@ import styles from './PageHeader.module.css';
|
|||||||
export interface PageHeaderProps {
|
export interface PageHeaderProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
children: ReactNode;
|
children?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PageHeader({ title, className, children }: PageHeaderProps) {
|
export function PageHeader({ title, className, children }: PageHeaderProps) {
|
||||||
|
@ -12,7 +12,6 @@ export * from 'components/common/HoverTooltip';
|
|||||||
export * from 'components/common/LinkButton';
|
export * from 'components/common/LinkButton';
|
||||||
export * from 'components/common/MobileMenu';
|
export * from 'components/common/MobileMenu';
|
||||||
export * from 'components/common/Pager';
|
export * from 'components/common/Pager';
|
||||||
export * from 'components/common/SettingsTable';
|
|
||||||
export * from 'components/common/UpdateNotice';
|
export * from 'components/common/UpdateNotice';
|
||||||
export * from 'components/common/WorldMap';
|
export * from 'components/common/WorldMap';
|
||||||
|
|
||||||
@ -113,5 +112,5 @@ export * from 'app/(app)/settings/websites/[id]/WebsiteDeleteForm';
|
|||||||
export * from 'app/(app)/settings/websites/[id]/WebsiteEditForm';
|
export * from 'app/(app)/settings/websites/[id]/WebsiteEditForm';
|
||||||
export * from 'app/(app)/settings/websites/[id]/WebsiteResetForm';
|
export * from 'app/(app)/settings/websites/[id]/WebsiteResetForm';
|
||||||
export * from 'app/(app)/settings/websites/WebsiteSettings';
|
export * from 'app/(app)/settings/websites/WebsiteSettings';
|
||||||
export * from 'app/(app)/settings/websites/WebsitesList';
|
export * from './app/(app)/settings/websites/Websites';
|
||||||
export * from 'app/(app)/settings/websites/WebsitesTable';
|
export * from 'app/(app)/settings/websites/WebsitesTable';
|
||||||
|
@ -189,7 +189,7 @@ function getPageFilters(filters: SearchFilter): [
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
...(pageSize > 0 && { take: pageSize, skip: pageSize * (page - 1) }),
|
...(pageSize > 0 && { take: +pageSize, skip: +pageSize * (page - 1) }),
|
||||||
...(orderBy && {
|
...(orderBy && {
|
||||||
orderBy: [
|
orderBy: [
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,7 @@ export default async (
|
|||||||
await useValidate(schema, req, res);
|
await useValidate(schema, req, res);
|
||||||
|
|
||||||
const { user } = req.auth;
|
const { user } = req.auth;
|
||||||
const { id: userId, page, query, includeTeams, onlyTeams } = req.query;
|
const { id: userId, page = 1, query = '', includeTeams, onlyTeams } = req.query;
|
||||||
|
|
||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
if (!user.isAdmin && user.id !== userId) {
|
if (!user.isAdmin && user.id !== userId) {
|
||||||
@ -38,8 +38,8 @@ export default async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const websites = await getWebsitesByUserId(userId, {
|
const websites = await getWebsitesByUserId(userId, {
|
||||||
page: +page,
|
page,
|
||||||
query: query as string,
|
query,
|
||||||
includeTeams,
|
includeTeams,
|
||||||
onlyTeams,
|
onlyTeams,
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user