Website UI design (#4829)

**Fixed different issues** :
 
- Multiple CSS fixes: font-size, colors, margins, z-index ...
- Fixed hover on contributor avatars
- Added link to contributors in footer
- Made the year in the footer dynamic (2023 --> 2024)
- Added name of contributor in "Thank you" section of Contributor page
- Added footer in small screens
- Made Activity Log Responsive 
- Fixed bug in "saving issues to DB", title was null everywhere. I
needed to implement an "upsert" behaviour to update the existing
database on init

**To be noted :** 

There is the following bug on production happening on mobile when you
refresh a second time :

<img width="1440" alt="Screenshot 2024-04-05 at 01 30 58"
src="https://github.com/twentyhq/twenty/assets/102751374/b935b07a-63dc-463d-8dcb-070ad4ef6db0">


It seems to be related to the following issue on mdx :
[https://github.com/hashicorp/next-mdx-remote/issues/350](https://github.com/hashicorp/next-mdx-remote/issues/350)

I added the following code that fixed this bug for me in development
(this needs to be tested in production) :

```
const serialized = await serialize(content, {
    mdxOptions: {
      development: process.env.NODE_ENV === 'development',
    }
  })
```

---------

Co-authored-by: Ady Beraud <a.beraud96@gmail.com>
This commit is contained in:
Ady Beraud
2024-04-05 08:41:08 +02:00
committed by GitHub
parent e8c58ae541
commit b82519301c
25 changed files with 140 additions and 53 deletions

View File

@ -1,10 +1,20 @@
'use client'; 'use client';
import { ResponsiveTimeRange } from '@nivo/calendar'; import styled from '@emotion/styled';
import { TimeRange } from '@nivo/calendar';
import { CardContainer } from '@/app/_components/contributors/CardContainer'; import { CardContainer } from '@/app/_components/contributors/CardContainer';
import { Title } from '@/app/_components/contributors/Title'; import { Title } from '@/app/_components/contributors/Title';
const CalendarContentContainer = styled.div`
@media (max-width: 890px) {
overflow-x: auto;
&::-webkit-scrollbar {
display: none;
}
}
`;
export const ActivityLog = ({ export const ActivityLog = ({
data, data,
}: { }: {
@ -16,17 +26,20 @@ export const ActivityLog = ({
return ( return (
<CardContainer> <CardContainer>
<Title>Activity</Title> <Title>Activity</Title>
<div style={{ width: '100%', height: '214px' }}> <CalendarContentContainer>
<ResponsiveTimeRange <TimeRange
height={150}
width={725}
data={data} data={data}
emptyColor="#F4EFFF" emptyColor="#F4EFFF"
colors={['#E9DFFF', '#B28FFE', '#915FFD']} colors={['#E9DFFF', '#B28FFE', '#915FFD']}
dayBorderWidth={2} weekdayTicks={[]}
dayBorderColor="#ffffff" weekdayLegendOffset={0}
dayBorderWidth={0}
dayRadius={4} dayRadius={4}
daySpacing={2} daySpacing={4}
/> />
</div> </CalendarContentContainer>
</CardContainer> </CardContainer>
); );
}; };

View File

@ -52,6 +52,8 @@ const AvatarItem = styled.div`
transition: transition:
opacity 0.3s ease, opacity 0.3s ease,
visibility 0.3s; visibility 0.3s;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
} }
&:hover .username { &:hover .username {

View File

@ -11,7 +11,6 @@ export const CardContainer = styled.div`
background-color: #fafafa; background-color: #fafafa;
@media (max-width: 810px) { @media (max-width: 810px) {
gap: 16px;
padding: 24px; padding: 24px;
} }
`; `;

View File

@ -9,11 +9,11 @@ const Container = styled.div`
width: 100%; width: 100%;
max-width: 898px; max-width: 898px;
padding: 40px; padding: 40px;
gap: 40px; gap: 40px;
@media (max-width: 809px) { @media (max-width: 809px) {
width: 100%; width: 100%;
padding: 40px 24px 40px 24px; padding: 40px 24px 40px 24px;
gap: 24px;
} }
`; `;

View File

@ -4,13 +4,19 @@ import styled from '@emotion/styled';
const Title = styled.h2` const Title = styled.h2`
font-size: 56px; font-size: 56px;
font-weight: 600; font-weight: bold;
color: #b3b3b3; color: #b3b3b3;
margin-bottom: 0px; margin-bottom: 32px;
margin-top: 64px; margin-top: 64px;
text-align: center;
display: flex;
justify-items: center;
align-items: center;
flex-direction: column;
@media (max-width: 810px) { @media (max-width: 810px) {
font-size: 28px; font-size: 32px;
margin-bottom: 22px;
} }
`; `;
@ -18,7 +24,8 @@ export const Header = () => {
return ( return (
<> <>
<Title> <Title>
Our amazing <br /> <span style={{ color: 'black' }}>Contributors</span> Our amazing <br />
<span style={{ color: '#141414' }}>Contributors</span>
</Title> </Title>
</> </>
); );

View File

@ -10,6 +10,10 @@ const ProfileContainer = styled.div`
gap: 32px; gap: 32px;
width: 100%; width: 100%;
align-items: center; align-items: center;
@media (max-width: 600px) {
flex-direction: column;
align-items: start;
}
`; `;
const Avatar = styled.div` const Avatar = styled.div`
@ -33,6 +37,10 @@ const Details = styled.div`
flex-direction: column; flex-direction: column;
gap: 4px; gap: 4px;
@media (max-width: 810px) {
gap: 8px;
}
.username { .username {
font-size: 40px; font-size: 40px;
font-weight: 700; font-weight: 700;
@ -42,7 +50,7 @@ const Details = styled.div`
gap: 12px; gap: 12px;
@media (max-width: 810px) { @media (max-width: 810px) {
font-size: 24px; font-size: 32px;
line-height: 28.8px; line-height: 28.8px;
} }
} }

View File

@ -3,6 +3,7 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { CardContainer } from '@/app/_components/contributors/CardContainer'; import { CardContainer } from '@/app/_components/contributors/CardContainer';
import { Theme } from '@/app/_components/ui/theme/theme';
const Container = styled(CardContainer)` const Container = styled(CardContainer)`
flex-direction: row; flex-direction: row;
@ -21,8 +22,8 @@ const Container = styled(CardContainer)`
.title { .title {
font-size: 24px; font-size: 24px;
color: #b3b3b3; color: ${Theme.text.color.quarternary};
margin: 0; margin: 8px;
@media (max-width: 810px) { @media (max-width: 810px) {
font-size: 20px; font-size: 20px;
@ -32,7 +33,7 @@ const Container = styled(CardContainer)`
.value { .value {
font-size: 56px; font-size: 56px;
font-weight: 700; font-weight: 700;
color: #474747; color: ${Theme.text.color.secondary};
@media (max-width: 810px) { @media (max-width: 810px) {
font-size: 32px; font-size: 32px;
@ -72,7 +73,7 @@ export const ProfileInfo = ({
</div> </div>
<div className="separator"></div> <div className="separator"></div>
<div className="item"> <div className="item">
<p className="title">Rank</p> <p className="title">Ranking</p>
<span className="value">{rank}%</span> <span className="value">{rank}%</span>
</div> </div>
<div className="separator"></div> <div className="separator"></div>

View File

@ -3,6 +3,7 @@ import styled from '@emotion/styled';
import { format } from 'date-fns'; import { format } from 'date-fns';
import { PullRequestIcon } from '@/app/_components/ui/icons/SvgIcons'; import { PullRequestIcon } from '@/app/_components/ui/icons/SvgIcons';
import { Theme } from '@/app/_components/ui/theme/theme';
import { formatIntoRelativeDate } from '@/shared-utils/formatIntoRelativeDate'; import { formatIntoRelativeDate } from '@/shared-utils/formatIntoRelativeDate';
const StyledTooltip = styled(Tooltip)``; const StyledTooltip = styled(Tooltip)``;
@ -15,7 +16,7 @@ const Item = styled.div`
const StyledTitle = styled.a` const StyledTitle = styled.a`
font-size: 24px; font-size: 24px;
font-weight: 400; font-weight: 400;
color: #474747; color: ${Theme.text.color.secondary};
margin: 0; margin: 0;
text-decoration: none; text-decoration: none;
@ -27,6 +28,7 @@ const StyledTitle = styled.a`
const StyledPrLink = styled.a` const StyledPrLink = styled.a`
cursor: pointer; cursor: pointer;
text-decoration: none; text-decoration: none;
color: ${Theme.text.color.quarternary} !important;
&:hover { &:hover {
text-decoration: underline; text-decoration: underline;
@ -38,7 +40,8 @@ const StyledDescription = styled.div`
font-size: 20px; font-size: 20px;
line-height: 28px; line-height: 28px;
font-weight: 500; font-weight: 500;
color: #b3b3b3; color: ${Theme.text.color.quarternary};
margin-top: 4px;
@media (max-width: 810px) { @media (max-width: 810px) {
font-size: 18px; font-size: 18px;

View File

@ -10,6 +10,7 @@ const List = styled.div`
display: flex; display: flex;
gap: 24px; gap: 24px;
flex-direction: column; flex-direction: column;
overflow: hidden;
`; `;
interface PullRequestsProps { interface PullRequestsProps {
list: { list: {

View File

@ -6,7 +6,6 @@ import { CardContainer } from '@/app/_components/contributors/CardContainer';
import { HeartIcon } from '@/app/_components/ui/icons/SvgIcons'; import { HeartIcon } from '@/app/_components/ui/icons/SvgIcons';
const StyledTitle = styled.div` const StyledTitle = styled.div`
display: flex;
font-size: 24px; font-size: 24px;
font-weight: 500; font-weight: 500;
gap: 8px; gap: 8px;
@ -18,20 +17,21 @@ const StyledTitle = styled.div`
const StyledHeartIcon = styled(HeartIcon)` const StyledHeartIcon = styled(HeartIcon)`
@media (max-width: 810px) { @media (max-width: 810px) {
display: inline-block !important;
width: 16px !important; width: 16px !important;
height: 16px !important; height: 16px !important;
} }
`; `;
interface ThankYouProps { interface ThankYouProps {
authorId: string; username: string;
} }
export const ThankYou = ({ authorId }: ThankYouProps) => { export const ThankYou = ({ username }: ThankYouProps) => {
return ( return (
<CardContainer> <CardContainer>
<StyledTitle> <StyledTitle>
Thank you @{authorId} <StyledHeartIcon color="#333333" size="18px" /> Thank you @{username} <StyledHeartIcon color="#333333" size="18px" />
</StyledTitle> </StyledTitle>
</CardContainer> </CardContainer>
); );

View File

@ -11,7 +11,7 @@ const Container = styled.div`
gap: 26px; gap: 26px;
@media (max-width: 809px) { @media (max-width: 809px) {
width: 100%; width: 100%;
padding: 0px 12px 0px 12px; padding: 0px 12px 40px 12px;
} }
`; `;

View File

@ -9,17 +9,17 @@ const StyledLineContainer = styled.div`
@media (max-width: 810px) { @media (max-width: 810px) {
width: auto; width: auto;
margin: 24px 0;
display: block; display: block;
margin: 24px 0px 64px;
} }
`; `;
const StyledLine = styled.div` const StyledLine = styled.div`
height: 1px; height: 1px;
background-color: #d9d9d9; background-color: #d9d9d9;
margin-bottom: 48px; margin-bottom: 80px;
margin-left: 148px; margin-left: 148px;
margin-top: 48px; margin-top: 40px;
width: 100%; width: 100%;
@media (max-width: 810px) { @media (max-width: 810px) {

View File

@ -6,6 +6,7 @@ import { compileMDX } from 'next-mdx-remote/rsc';
import remarkBehead from 'remark-behead'; import remarkBehead from 'remark-behead';
import gfm from 'remark-gfm'; import gfm from 'remark-gfm';
import { Theme } from '@/app/_components/ui/theme/theme';
import { ReleaseNote } from '@/app/releases/api/route'; import { ReleaseNote } from '@/app/releases/api/route';
const StyledContainer = styled.div` const StyledContainer = styled.div`
@ -16,7 +17,6 @@ const StyledContainer = styled.div`
@media (max-width: 810px) { @media (max-width: 810px) {
width: auto; width: auto;
margin: 24px 0;
display: block; display: block;
} }
`; `;
@ -35,17 +35,19 @@ const StyledVersion = styled.div`
font-size: 20px; font-size: 20px;
flex-flow: row; flex-flow: row;
justify-content: space-between; justify-content: space-between;
margin-bottom: 24px;
} }
`; `;
const StyledRelease = styled.span` const StyledRelease = styled.span`
color: #141414; color: ${Theme.text.color.quarternary};
line-height: 140%;
`; `;
const StyledDate = styled.span` const StyledDate = styled.span`
color: #474747; color: ${Theme.text.color.secondary};
font-size: 16px;
font-weight: 400; font-weight: 400;
font-size: ${Theme.font.size.sm};
`; `;
const StlyedContent = styled.div` const StlyedContent = styled.div`
@ -54,16 +56,20 @@ const StlyedContent = styled.div`
gap: 64px; gap: 64px;
h3 { h3 {
color: #141414; color: ${Theme.text.color.primary};
font-weight: 700;
font-size: 40px; font-size: 40px;
margin: 0; margin: 0;
} }
p { p {
color: #474747; color: ${Theme.text.color.secondary};
font-family: ${Theme.font.family};
font-size: 16px; font-size: 16px;
line-height: 28.8px; line-height: 28.8px;
font-weight: 400; font-weight: 400;
margin: 40px 0px;
text-align: justify;
} }
img { img {
@ -73,16 +79,16 @@ const StlyedContent = styled.div`
@media (max-width: 810px) { @media (max-width: 810px) {
h3 { h3 {
font-size: 24px; font-size: 24px;
margin: 24px 0 40px;
} }
} }
`; `;
const gabarito = Gabarito({ const gabarito = Gabarito({
weight: ['400', '500'], weight: ['400', '500', '600', '700'],
subsets: ['latin'], subsets: ['latin'],
display: 'swap', display: 'swap',
adjustFontFallback: false, adjustFontFallback: false,
variable: '--font-gabarito',
}); });
export const Release = async ({ release }: { release: ReleaseNote }) => { export const Release = async ({ release }: { release: ReleaseNote }) => {
@ -92,6 +98,7 @@ export const Release = async ({ release }: { release: ReleaseNote }) => {
source: release.content, source: release.content,
options: { options: {
mdxOptions: { mdxOptions: {
development: process.env.NODE_ENV === 'development',
remarkPlugins: [gfm, [remarkBehead, { depth: 2 }]], remarkPlugins: [gfm, [remarkBehead, { depth: 2 }]],
}, },
}, },

View File

@ -139,7 +139,9 @@ export const PullRequestIcon = ({ size = 'S', color = 'rgb(179,179,179)' }) => {
export const HeartIcon = ({ size = 'S', color = 'rgb(179,179,179)' }) => { export const HeartIcon = ({ size = 'S', color = 'rgb(179,179,179)' }) => {
const dimension = getSize(size); const dimension = getSize(size);
return ( return (
<div style={{ width: dimension, height: dimension }}> <span
style={{ width: dimension, height: dimension, display: 'inline-block' }}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 20" fill="none"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 20" fill="none">
<path <path
d="M18.513 10.572L11.013 18L3.513 10.572C3.0183 10.0906 2.62864 9.51201 2.36854 8.87263C2.10845 8.23325 1.98356 7.54694 2.00173 6.85693C2.01991 6.16691 2.18076 5.48813 2.47415 4.86333C2.76755 4.23853 3.18713 3.68125 3.70648 3.22657C4.22583 2.7719 4.8337 2.42968 5.49181 2.22147C6.14991 2.01327 6.844 1.94358 7.53036 2.0168C8.21673 2.09001 8.8805 2.30455 9.47987 2.6469C10.0792 2.98925 10.6012 3.45199 11.013 4.00599C11.4265 3.45602 11.9491 2.99731 12.5481 2.6586C13.1471 2.31988 13.8095 2.10844 14.4939 2.03751C15.1784 1.96658 15.8701 2.03769 16.5258 2.24639C17.1815 2.45508 17.787 2.79687 18.3045 3.25036C18.8221 3.70385 19.2404 4.25928 19.5334 4.88189C19.8264 5.50449 19.9877 6.18088 20.0073 6.8687C20.0269 7.55653 19.9043 8.24099 19.6471 8.87924C19.39 9.5175 19.0039 10.0958 18.513 10.578" d="M18.513 10.572L11.013 18L3.513 10.572C3.0183 10.0906 2.62864 9.51201 2.36854 8.87263C2.10845 8.23325 1.98356 7.54694 2.00173 6.85693C2.01991 6.16691 2.18076 5.48813 2.47415 4.86333C2.76755 4.23853 3.18713 3.68125 3.70648 3.22657C4.22583 2.7719 4.8337 2.42968 5.49181 2.22147C6.14991 2.01327 6.844 1.94358 7.53036 2.0168C8.21673 2.09001 8.8805 2.30455 9.47987 2.6469C10.0792 2.98925 10.6012 3.45199 11.013 4.00599C11.4265 3.45602 11.9491 2.99731 12.5481 2.6586C13.1471 2.31988 13.8095 2.10844 14.4939 2.03751C15.1784 1.96658 15.8701 2.03769 16.5258 2.24639C17.1815 2.45508 17.787 2.79687 18.3045 3.25036C18.8221 3.70385 19.2404 4.25928 19.5334 4.88189C19.8264 5.50449 19.9877 6.18088 20.0073 6.8687C20.0269 7.55653 19.9043 8.24099 19.6471 8.87924C19.39 9.5175 19.0039 10.0958 18.513 10.578"
@ -149,7 +151,7 @@ export const HeartIcon = ({ size = 'S', color = 'rgb(179,179,179)' }) => {
strokeLinejoin="round" strokeLinejoin="round"
/> />
</svg> </svg>
</div> </span>
); );
}; };

View File

@ -30,7 +30,7 @@ const ExternalLinkItem = styled.a`
`; `;
const ActivePage = styled.span` const ActivePage = styled.span`
color: ${Theme.text.color.secondary}; color: ${Theme.text.color.primary};
font-weight: ${Theme.font.weight.medium}; font-weight: ${Theme.font.weight.medium};
`; `;

View File

@ -9,7 +9,7 @@ const Container = styled.div`
padding: 0px 96px 0px 96px; padding: 0px 96px 0px 96px;
@media (max-width: 809px) { @media (max-width: 809px) {
width: 100%; width: 100%;
padding: 0px 12px 0px 12px; padding: 0px 24px 0px 24px;
} }
`; `;

View File

@ -19,7 +19,7 @@ const FooterContainer = styled.div`
color: rgb(129, 129, 129); color: rgb(129, 129, 129);
gap: 32px; gap: 32px;
@media (max-width: 809px) { @media (max-width: 809px) {
display: none; padding: 36px 24px;
} }
`; `;
@ -28,6 +28,9 @@ const LeftSideFooter = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16px; gap: 16px;
@media (max-width: 809px) {
display: none;
}
`; `;
const RightSideFooter = styled.div` const RightSideFooter = styled.div`
@ -35,6 +38,10 @@ const RightSideFooter = styled.div`
justify-content: space-between; justify-content: space-between;
gap: 48px; gap: 48px;
height: 146px; height: 146px;
@media (max-width: 809px) {
flex-direction: column;
height: fit-content;
}
`; `;
const RightSideFooterColumn = styled.div` const RightSideFooterColumn = styled.div`
@ -96,6 +103,9 @@ export const FooterDesktop = () => {
</RightSideFooterColumn> </RightSideFooterColumn>
<RightSideFooterColumn> <RightSideFooterColumn>
<RightSideFooterColumnTitle>Other</RightSideFooterColumnTitle> <RightSideFooterColumnTitle>Other</RightSideFooterColumnTitle>
<RightSideFooterLink href="/contributors">
Contributors
</RightSideFooterLink>
<RightSideFooterLink href="/oss-friends"> <RightSideFooterLink href="/oss-friends">
OSS Friends OSS Friends
</RightSideFooterLink> </RightSideFooterLink>
@ -120,7 +130,7 @@ export const FooterDesktop = () => {
> >
<div> <div>
<span style={{ fontFamily: 'Inter, sans-serif' }}>©</span> <span style={{ fontFamily: 'Inter, sans-serif' }}>©</span>
2023 Twenty PBC {new Date().getFullYear()} Twenty PBC
</div> </div>
<div <div
style={{ style={{

View File

@ -119,22 +119,26 @@ export const LinkNextToCTA = styled.a`
export const HamburgerContainer = styled.div` export const HamburgerContainer = styled.div`
height: 44px; height: 44px;
width: 44px; width: 44px;
cursor: pointer;
position: relative; position: relative;
input { input {
cursor: pointer;
height: 44px; height: 44px;
width: 44px; width: 44px;
opacity: 0; opacity: 0;
z-index: 1;
} }
#line1 { #line1 {
transition: transform 0.5s; transition: transform 0.5s;
transition-timing-function: ease-in-out; transition-timing-function: ease-in-out;
z-index: 0;
} }
#line2 { #line2 {
transition: transform 0.5s; transition: transform 0.5s;
transition-timing-function: ease-in-out; transition-timing-function: ease-in-out;
z-index: 0;
} }
#menu-input:checked ~ #line1 { #menu-input:checked ~ #line1 {
@ -154,6 +158,7 @@ export const HamburgerLine1 = styled.div`
width: 20px; width: 20px;
border-radius: 10px; border-radius: 10px;
background-color: rgb(179, 179, 179); background-color: rgb(179, 179, 179);
z-index: 0;
`; `;
export const HamburgerLine2 = styled.div` export const HamburgerLine2 = styled.div`
@ -164,6 +169,7 @@ export const HamburgerLine2 = styled.div`
width: 20px; width: 20px;
border-radius: 10px; border-radius: 10px;
background-color: rgb(179, 179, 179); background-color: rgb(179, 179, 179);
z-index: 0;
`; `;
export const NavOpen = styled.div` export const NavOpen = styled.div`

View File

@ -29,7 +29,7 @@ export interface Directory {
async function getFiles( async function getFiles(
filePath: string, filePath: string,
basePath: string, basePath: string,
position: number = 0, position = 0,
): Promise<Directory> { ): Promise<Directory> {
const entries = fs.readdirSync(filePath, { withFileTypes: true }); const entries = fs.readdirSync(filePath, { withFileTypes: true });
@ -99,13 +99,14 @@ async function parseFrontMatterAndCategory(
return parsedDirectory; return parsedDirectory;
} }
export async function compileMDXFile(filePath: string, addToc: boolean = true) { export async function compileMDXFile(filePath: string, addToc = true) {
const fileContent = fs.readFileSync(filePath, 'utf8'); const fileContent = fs.readFileSync(filePath, 'utf8');
const compiled = await compileMDX<{ title: string; position?: number }>({ const compiled = await compileMDX<{ title: string; position?: number }>({
source: fileContent, source: fileContent,
options: { options: {
parseFrontmatter: true, parseFrontmatter: true,
mdxOptions: { mdxOptions: {
development: process.env.NODE_ENV === 'development',
remarkPlugins: [gfm], remarkPlugins: [gfm],
rehypePlugins: [rehypeSlug, ...(addToc ? [toc] : [])], rehypePlugins: [rehypeSlug, ...(addToc ? [toc] : [])],
}, },

View File

@ -127,7 +127,7 @@ export default async function ({ params }: { params: { slug: string } }) {
}[] }[]
} }
/> />
<ThankYou authorId={contributor.login} /> <ThankYou username={contributor.id} />
</ContentContainer> </ContentContainer>
</> </>
); );

View File

@ -15,6 +15,7 @@ export async function savePRsToDB(
if (pr.author == null) { if (pr.author == null) {
continue; continue;
} }
await insertMany( await insertMany(
userModel, userModel,
[ [
@ -43,7 +44,7 @@ export async function savePRsToDB(
authorId: pr.author.login, authorId: pr.author.login,
}, },
], ],
{ onConflictKey: 'id' }, { onConflictKey: 'id', onConflictUpdateObject: { title: pr.title } },
); );
for (const label of pr.labels.nodes) { for (const label of pr.labels.nodes) {

View File

@ -47,9 +47,7 @@ const Contributors = async () => {
<Background /> <Background />
<ContentContainer> <ContentContainer>
<Header /> <Header />
<div> <AvatarGrid users={fitlerContributors as Contributor[]} />
<AvatarGrid users={fitlerContributors as Contributor[]} />
</div>
</ContentContainer> </ContentContainer>
</> </>
); );

View File

@ -76,10 +76,25 @@ const findAll = (model: SQLiteTableWithColumns<any>) => {
const insertMany = async ( const insertMany = async (
model: SQLiteTableWithColumns<any>, model: SQLiteTableWithColumns<any>,
data: any, data: any,
options?: { onConflictKey?: string }, options?: {
onConflictKey?: string;
onConflictUpdateObject?: any;
},
) => { ) => {
if (isSqliteDriver) { if (isSqliteDriver) {
const query = sqliteDb.insert(model).values(data); const query = sqliteDb.insert(model).values(data);
if (options?.onConflictUpdateObject) {
if (options?.onConflictKey) {
return query
.onConflictDoUpdate({
target: [model[options.onConflictKey]],
set: options.onConflictUpdateObject,
})
.execute();
}
}
if (options?.onConflictKey) { if (options?.onConflictKey) {
return query return query
.onConflictDoNothing({ .onConflictDoNothing({
@ -87,10 +102,23 @@ const insertMany = async (
}) })
.execute(); .execute();
} }
return query.execute(); return query.execute();
} }
if (isPgDriver) { if (isPgDriver) {
const query = pgDb.insert(model).values(data); const query = pgDb.insert(model).values(data);
if (options?.onConflictUpdateObject) {
if (options?.onConflictKey) {
return query
.onConflictDoUpdate({
target: [model[options.onConflictKey]],
set: options.onConflictUpdateObject,
})
.execute();
}
}
if (options?.onConflictKey) { if (options?.onConflictKey) {
return query return query
.onConflictDoNothing({ .onConflictDoNothing({

View File

@ -9,7 +9,7 @@ export const pgUsers = pgTable('users', {
export const pgPullRequests = pgTable('pullRequests', { export const pgPullRequests = pgTable('pullRequests', {
id: text('id').primaryKey(), id: text('id').primaryKey(),
name: text('title'), title: text('title'),
body: text('body'), body: text('body'),
url: text('url'), url: text('url'),
createdAt: text('createdAt'), createdAt: text('createdAt'),

View File

@ -9,7 +9,7 @@ export const sqlLiteUsers = sqliteTable('users', {
export const sqlLitePullRequests = sqliteTable('pullRequests', { export const sqlLitePullRequests = sqliteTable('pullRequests', {
id: text('id').primaryKey(), id: text('id').primaryKey(),
name: text('title'), title: text('title'),
body: text('body'), body: text('body'),
url: text('url'), url: text('url'),
createdAt: text('createdAt'), createdAt: text('createdAt'),