Feat: API Playground (#10376)
/claim #10283 --------- Co-authored-by: Félix Malfait <felix@twenty.com> Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
@ -0,0 +1,59 @@
|
||||
import { PageHeader } from '@/ui/layout/page/components/PageHeader';
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbProps,
|
||||
} from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import '@scalar/api-reference-react/style.css';
|
||||
import { IconButton, IconX, useIsMobile } from 'twenty-ui';
|
||||
|
||||
type FullScreenContainerProps = {
|
||||
children: JSX.Element | JSX.Element[];
|
||||
links: BreadcrumbProps['links'];
|
||||
exitFullScreen(): void;
|
||||
};
|
||||
|
||||
const StyledFullScreen = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100dvw;
|
||||
height: 100dvh;
|
||||
background: ${({ theme }) => theme.background.noisy};
|
||||
`;
|
||||
|
||||
const StyledMainContainer = styled.div`
|
||||
border-top: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export const FullScreenContainer = ({
|
||||
children,
|
||||
links,
|
||||
exitFullScreen,
|
||||
}: FullScreenContainerProps) => {
|
||||
const isMobile = useIsMobile();
|
||||
const { t } = useLingui();
|
||||
|
||||
const handleExitFullScreen = () => {
|
||||
exitFullScreen();
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledFullScreen>
|
||||
<PageHeader title={<Breadcrumb links={links} />}>
|
||||
<IconButton
|
||||
Icon={IconX}
|
||||
dataTestId="close-button"
|
||||
size={isMobile ? 'medium' : 'small'}
|
||||
variant="secondary"
|
||||
accent="default"
|
||||
onClick={handleExitFullScreen}
|
||||
ariaLabel={t`Exit Full Screen`}
|
||||
/>
|
||||
</PageHeader>
|
||||
<StyledMainContainer>{children}</StyledMainContainer>
|
||||
</StyledFullScreen>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,45 @@
|
||||
import { FullScreenContainer } from '@/ui/layout/fullscreen/components/FullScreenContainer';
|
||||
import styled from '@emotion/styled';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { ComponentDecorator, ComponentWithRouterDecorator } from 'twenty-ui';
|
||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||
|
||||
const meta: Meta<typeof FullScreenContainer> = {
|
||||
title: 'UI/Layout/FullScreenContainer',
|
||||
component: FullScreenContainer,
|
||||
decorators: [
|
||||
ComponentDecorator,
|
||||
I18nFrontDecorator,
|
||||
ComponentWithRouterDecorator,
|
||||
],
|
||||
};
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof FullScreenContainer>;
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
children: <StyledContainer>This is full-screen content</StyledContainer>,
|
||||
links: [
|
||||
{
|
||||
children: 'Layout',
|
||||
href: '/',
|
||||
},
|
||||
{
|
||||
children: 'FullScreen',
|
||||
href: '/',
|
||||
},
|
||||
],
|
||||
exitFullScreen: () => {},
|
||||
},
|
||||
decorators: [ComponentDecorator],
|
||||
};
|
||||
@ -0,0 +1,19 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
|
||||
|
||||
export const useShowFullscreen = () => {
|
||||
const { isMatchingLocation } = useIsMatchingLocation();
|
||||
|
||||
return useMemo(() => {
|
||||
if (
|
||||
isMatchingLocation('settings/' + SettingsPath.RestPlayground + '/*') ||
|
||||
isMatchingLocation('settings/' + SettingsPath.GraphQLPlayground)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}, [isMatchingLocation]);
|
||||
};
|
||||
@ -8,6 +8,7 @@ import { useIsSettingsPage } from '@/navigation/hooks/useIsSettingsPage';
|
||||
import { OBJECT_SETTINGS_WIDTH } from '@/settings/data-model/constants/ObjectSettings';
|
||||
import { SignInAppNavigationDrawerMock } from '@/sign-in-background-mock/components/SignInAppNavigationDrawerMock';
|
||||
import { SignInBackgroundMockPage } from '@/sign-in-background-mock/components/SignInBackgroundMockPage';
|
||||
import { useShowFullscreen } from '@/ui/layout/fullscreen/hooks/useShowFullscreen';
|
||||
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
|
||||
import { NAV_DRAWER_WIDTHS } from '@/ui/navigation/navigation-drawer/constants/NavDrawerWidths';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
@ -69,6 +70,7 @@ export const DefaultLayout = () => {
|
||||
const theme = useTheme();
|
||||
const windowsWidth = useScreenSize().width;
|
||||
const showAuthModal = useShowAuthModal();
|
||||
const useShowFullScreen = useShowFullscreen();
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -90,7 +92,7 @@ export const DefaultLayout = () => {
|
||||
<StyledPageContainer
|
||||
animate={{
|
||||
marginLeft:
|
||||
isSettingsPage && !isMobile
|
||||
isSettingsPage && !isMobile && !useShowFullScreen
|
||||
? (windowsWidth -
|
||||
(OBJECT_SETTINGS_WIDTH +
|
||||
NAV_DRAWER_WIDTHS.menu.desktop.expanded +
|
||||
@ -102,7 +104,7 @@ export const DefaultLayout = () => {
|
||||
>
|
||||
{showAuthModal ? (
|
||||
<StyledAppNavigationDrawerMock />
|
||||
) : (
|
||||
) : useShowFullScreen ? null : (
|
||||
<StyledAppNavigationDrawer />
|
||||
)}
|
||||
{showAuthModal ? (
|
||||
|
||||
@ -1,15 +1,44 @@
|
||||
import { ActivityRichTextEditor } from '@/activities/components/ActivityRichTextEditor';
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { lazy, Suspense } from 'react';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
const ActivityRichTextEditor = lazy(() =>
|
||||
import('@/activities/components/ActivityRichTextEditor').then((module) => ({
|
||||
default: module.ActivityRichTextEditor,
|
||||
})),
|
||||
);
|
||||
|
||||
const StyledShowPageActivityContainer = styled.div`
|
||||
margin-top: ${({ theme }) => theme.spacing(6)};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledSkeletonContainer = styled.div`
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const LoadingSkeleton = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledSkeletonContainer>
|
||||
<SkeletonTheme
|
||||
baseColor={theme.background.tertiary}
|
||||
highlightColor={theme.background.transparent.lighter}
|
||||
borderRadius={theme.border.radius.sm}
|
||||
>
|
||||
<Skeleton height={200} />
|
||||
</SkeletonTheme>
|
||||
</StyledSkeletonContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export const ShowPageActivityContainer = ({
|
||||
targetableObject,
|
||||
}: {
|
||||
@ -28,14 +57,16 @@ export const ShowPageActivityContainer = ({
|
||||
componentInstanceId={`scroll-wrapper-tab-list-${targetableObject.id}`}
|
||||
>
|
||||
<StyledShowPageActivityContainer>
|
||||
<ActivityRichTextEditor
|
||||
activityId={targetableObject.id}
|
||||
activityObjectNameSingular={
|
||||
targetableObject.targetObjectNameSingular as
|
||||
| CoreObjectNameSingular.Note
|
||||
| CoreObjectNameSingular.Task
|
||||
}
|
||||
/>
|
||||
<Suspense fallback={<LoadingSkeleton />}>
|
||||
<ActivityRichTextEditor
|
||||
activityId={targetableObject.id}
|
||||
activityObjectNameSingular={
|
||||
targetableObject.targetObjectNameSingular as
|
||||
| CoreObjectNameSingular.Note
|
||||
| CoreObjectNameSingular.Task
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
</StyledShowPageActivityContainer>
|
||||
</ScrollWrapper>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user