Skip to content

Commit

Permalink
feat: quick actions
Browse files Browse the repository at this point in the history
  • Loading branch information
tea-artist committed Jan 30, 2024
1 parent 9c3e096 commit 008a4b6
Show file tree
Hide file tree
Showing 27 changed files with 229 additions and 90 deletions.
2 changes: 1 addition & 1 deletion apps/nestjs-backend/test/record.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ describe('OpenAPI RecordController (e2e)', () => {
expect(res2.records[0].fields[table.fields[0].id]).toEqual(value2);
});

it('should create a record when have error formula', async () => {
it('should create a record with order', async () => {
const viewResponse = await getViews(table.id);
const viewId = viewResponse[0].id;
const res = await createRecords(table.id, {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,47 +1,43 @@
import { Gauge, Home, PackageCheck } from '@teable-group/icons';
import { Gauge, PackageCheck } from '@teable-group/icons';
import { cn } from '@teable-group/ui-lib/shadcn';
import { Button } from '@teable-group/ui-lib/shadcn/ui/button';
import { Input } from '@teable-group/ui-lib/shadcn/ui/input';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { useTranslation } from 'react-i18next';
import { tableConfig } from '@/features/i18n/table.config';
import { TableList } from '../../table-list/TableList';
import { QuickAction } from './QuickAction';

export const BaseSideBar = () => {
const router = useRouter();
const { baseId } = router.query;
const { t } = useTranslation(tableConfig.i18nNamespaces);
const pageRoutes: {
href: string;
text: string;
shortCutKey: string;
Icon: React.FC<{ className?: string }>;
disabled?: boolean;
}[] = [
{
href: `/base/${baseId}`,
text: 'Home',
shortCutKey: '⌘H',
Icon: Home,
},
{
href: `/base/${baseId}/dashboard`,
text: 'Dashboard',
shortCutKey: '⌘D',
text: t('common:noun.dashboard'),
Icon: Gauge,
},
{
href: `/base/${baseId}/automation`,
text: 'Automation',
shortCutKey: '⌘A',
text: t('common:noun.automation'),
Icon: PackageCheck,
disabled: true,
},
];
return (
<>
<div className="flex flex-col gap-2 px-3">
<div>
<Input className="h-8" type="text" placeholder="Search" />
<QuickAction>{t('space:quickAction.title')}</QuickAction>
</div>
<ul>
{pageRoutes.map(({ href, text, shortCutKey, Icon }) => {
{pageRoutes.map(({ href, text, Icon, disabled }) => {
return (
<li key={href}>
<Button
Expand All @@ -52,12 +48,12 @@ export const BaseSideBar = () => {
'w-full justify-start text-sm px-2 my-[2px]',
href === router.pathname && 'bg-secondary'
)}
disabled={disabled}
>
<Link href={href} className="font-normal">
<Icon className="size-4 shrink-0" />
<p className="truncate">{text}</p>
<div className="grow basis-0"></div>
<p className="text-xs text-slate-500">{shortCutKey}</p>
</Link>
</Button>
</li>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { LaptopIcon } from '@radix-ui/react-icons';
import { Moon, Settings, Sun, Table2 } from '@teable-group/icons';
import { ThemeKey } from '@teable-group/sdk/context';
import { useBase, useTables, useTheme } from '@teable-group/sdk/hooks';
import {
CommandDialog,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
CommandSeparator,
Button,
} from '@teable-group/ui-lib/shadcn';
import { useRouter } from 'next/router';
import { useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { useSettingStore } from '@/features/app/components/setting/useSettingStore';
import { tableConfig } from '@/features/i18n/table.config';

export const QuickAction = ({ children }: React.PropsWithChildren) => {
const [open, setOpen] = useState(false);
const tables = useTables();
const base = useBase();
const setting = useSettingStore();
const router = useRouter();
const theme = useTheme();
const { t } = useTranslation(tableConfig.i18nNamespaces);

useHotkeys(`meta+k`, () => {
setOpen(!open);
});

return (
<>
<Button
className="w-full justify-between text-sm font-normal text-muted-foreground shadow-none"
size="sm"
variant="outline"
onClick={() => setOpen(true)}
>
{children}
<kbd className="flex h-5 items-center gap-1 rounded border bg-muted px-2 font-mono text-xs">
<span className="text-base"></span>
<span>K</span>
</kbd>
</Button>
<CommandDialog open={open} onOpenChange={setOpen}>
<CommandInput placeholder={t('space:quickAction.placeHolder')} />
<CommandList>
<CommandEmpty>{t('common:noResult')}</CommandEmpty>
<CommandGroup heading={t('common:noun.table')}>
{tables.map((table) => (
<CommandItem
className="flex gap-2"
key={table.id}
value={table.name}
onSelect={() => {
setOpen(false);
router.push({
pathname: '/base/[baseId]/[tableId]',
query: { baseId: base?.id, tableId: table.id },
});
}}
>
<span>{table.icon || <Table2 className="size-4 shrink-0" />}</span>
<span>{table.name}</span>
</CommandItem>
))}
</CommandGroup>
<CommandSeparator />
<CommandGroup heading={t('common:settings.setting.theme')}>
<CommandItem
className="flex gap-2"
onSelect={() => {
setOpen(false);
theme.setTheme(ThemeKey.Light);
}}
value={t('common:settings.setting.light')}
>
<Sun className="size-4" />
<span>{t('common:settings.setting.light')}</span>
</CommandItem>
<CommandItem
className="flex gap-2"
onSelect={() => {
setOpen(false);
theme.setTheme(ThemeKey.Dark);
}}
value={t('common:settings.setting.dark')}
>
<Moon className="size-4" />
<span>{t('common:settings.setting.dark')}</span>
</CommandItem>
<CommandItem
className="flex gap-2"
onSelect={() => {
setOpen(false);
theme.setTheme(null);
}}
value={t('common:settings.setting.system')}
>
<LaptopIcon className="size-4" />
<span>{t('common:settings.setting.system')}</span>
</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup heading={t('common:settings.title')}>
<CommandItem
className="flex gap-2"
onSelect={() => {
setOpen(false);
setting.setOpen(true);
}}
value={t('common:settings.title')}
>
<Settings className="size-4" />
<span>{t('common:settings.title')}</span>
</CommandItem>
</CommandGroup>
</CommandList>
</CommandDialog>
</>
);
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Home } from '@teable-group/icons';
import { cn } from '@teable-group/ui-lib/shadcn';
import { Button } from '@teable-group/ui-lib/shadcn/ui/button';
import { Input } from '@teable-group/ui-lib/shadcn/ui/input';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { SpaceList } from './SpaceList';
Expand All @@ -25,9 +24,6 @@ export const SpaceSideBar = () => {
return (
<>
<div className="flex flex-col gap-2 px-3">
<div>
<Input className="h-8" type="text" placeholder="Search" />
</div>
<ul>
{pageRoutes.map(({ href, text, shortCutKey, Icon }) => {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export function useAddView() {
const table = useTable();
const views = useViews();
const router = useRouter();
const viewName = views[views.length - 1]?.name + ' ' + views.length;
const viewName = views?.[views.length - 1]?.name + ' ' + views?.length;

return useCallback(
async (type: ViewType = ViewType.Grid, name?: string) => {
Expand Down
16 changes: 3 additions & 13 deletions apps/nextjs-app/src/features/app/components/SideBarFooter.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { Github, Settings } from '@teable-group/icons';
import { useSession } from '@teable-group/sdk';
import { Avatar, AvatarFallback, AvatarImage, Button } from '@teable-group/ui-lib/shadcn';
import React from 'react';
import { NotificationsManage } from '@/features/app/components/notifications/NotificationsManage';
import { SettingTrigger } from './setting/SettingTrigger';
import { SettingDialog } from './setting/SettingDialog';
import { UserNav } from './user/UserNav';

export const SideBarFooter: React.FC = () => {
const { user } = useSession();

return (
<div className="mx-2 mb-1 flex flex-col items-center gap-1">
<div className="m-2 flex flex-col items-center gap-1">
<div className="flex w-full justify-between">
<UserNav>
<Button variant="ghost" size={'xs'} className="w-full justify-start text-sm font-normal">
Expand All @@ -19,20 +18,11 @@ export const SideBarFooter: React.FC = () => {
<AvatarFallback>{user.name.slice(0, 1)}</AvatarFallback>
</Avatar>
{user.name}
<div className="grow basis-0"></div>
</Button>
</UserNav>
<SettingDialog />
<NotificationsManage />
</div>
<SettingTrigger>
<Button variant="ghost" size={'xs'} className="w-full justify-start text-sm font-normal">
<Settings className="size-5 shrink-0" />
Settings
<div className="grow basis-0"></div>
<p className="text-xs text-slate-500">10.2k</p>
<Github className="size-4 shrink-0" />
</Button>
</SettingTrigger>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
Dialog,
DialogContent,
DialogTrigger,
Tabs,
TabsContent,
TabsList,
Expand All @@ -11,12 +10,13 @@ import { useTranslation } from 'react-i18next';
import { System } from '@/features/app/components/setting/System';
import { Account } from './Account';
import { Notifications } from './Notifications';
import { useSettingStore } from './useSettingStore';

export const SettingTrigger: React.FC<{ children: React.ReactNode }> = ({ children }) => {
export const SettingDialog = () => {
const { t } = useTranslation('common');
const { open, setOpen } = useSettingStore();
return (
<Dialog>
<DialogTrigger asChild>{children}</DialogTrigger>
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="h-5/6 max-h-[800px] max-w-6xl">
<Tabs defaultValue="profile" className="flex min-h-[40rem] gap-4 pt-4">
<TabsList className="grid w-36 gap-2 bg-inherit text-left">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { create } from 'zustand';

interface ISettingState {
open: boolean;
setOpen: (open: boolean) => void;
}

export const useSettingStore = create<ISettingState>((set) => ({
open: false,
setOpen: (open: boolean) => {
set((state) => {
return {
...state,
open,
};
});
},
}));
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { SheetWraper } from '../../blocks/base/base-side-bar/SheetWraper';
import { SideBar } from '../../blocks/base/base-side-bar/SideBar';
import { PaneSkeleton } from './PaneSkeleton';

const ResizeblePanelsPrefix = 'react-resizable-panels';
const ResizablePanelsPrefix = 'react-resizable-panels';

enum ResizePart {
LEFT = 'left',
Expand All @@ -34,7 +34,7 @@ export const ResizablePane: React.FC<{

useEffect(() => {
const sizeString = localStorage.getItem(
`${ResizeblePanelsPrefix}:${LocalStorageKeys.SideBarSize}`
`${ResizablePanelsPrefix}:${LocalStorageKeys.SideBarSize}`
);
if (isString(sizeString)) {
const sizeObj = JSON.parse(sizeString);
Expand Down
13 changes: 10 additions & 3 deletions apps/nextjs-app/src/features/app/components/user/UserNav.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { ExitIcon } from '@radix-ui/react-icons';
import { useMutation } from '@tanstack/react-query';
import { Settings } from '@teable-group/icons';
import { signout } from '@teable-group/openapi';
import { useSession } from '@teable-group/sdk/hooks';
import {
Expand All @@ -7,16 +9,17 @@ import {
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuTrigger,
} from '@teable-group/ui-lib/shadcn';
import { useRouter } from 'next/router';
import React from 'react';
import { useSettingStore } from '../setting/useSettingStore';

export const UserNav: React.FC<React.PropsWithChildren> = (props) => {
const { children } = props;
const router = useRouter();
const { user } = useSession();
const setting = useSettingStore();
const { mutateAsync: loginOut, isLoading } = useMutation({
mutationFn: signout,
});
Expand All @@ -37,9 +40,13 @@ export const UserNav: React.FC<React.PropsWithChildren> = (props) => {
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={loginOutClick} disabled={isLoading}>
<DropdownMenuItem className="flex gap-2" onClick={() => setting.setOpen(true)}>
<Settings className="size-4 shrink-0" />
Settings
</DropdownMenuItem>
<DropdownMenuItem className="flex gap-2" onClick={loginOutClick} disabled={isLoading}>
<ExitIcon className="size-4 shrink-0" />
Log out
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
Expand Down
Loading

0 comments on commit 008a4b6

Please sign in to comment.