feat(monorepo): migrated to turbo repo + pnpm

pull/12/head
Guus van Meerveld 1 year ago
parent b6feb85690
commit e393391051
Signed by: Guusvanmeerveld
GPG Key ID: 2BA7D7912771966E

@ -2,22 +2,32 @@
!/nginx
!/package.json
!/pnpm-lock.yaml
!/pnpm-workspace.yaml
!/turbo.json
!/.npmrc
!/entrypoint.sh
!/packages/server/src
!/packages/server/public
!/packages/server/package.json
!/packages/server/yarn.lock
!/packages/server/.yarnrc
!/packages/server/tsconfig.build.json
!/packages/server/tsconfig.json
!/packages/tsconfig/*
!/packages/autodiscover/src
!/packages/autodiscover/package.json
!/packages/autodiscover/rollup.config.ts
!/packages/autodiscover/tsconfig.json
!/apps/server/src
!/apps/server/public
!/apps/server/package.json
!/apps/server/tsconfig.build.json
!/apps/server/tsconfig.json
!/packages/client/src
!/packages/client/index.html
!/packages/client/splashscreen.html
!/packages/client/tsconfig.json
!/packages/client/tsconfig.node.json
!/packages/client/vite.config.ts
!/packages/client/package.json
!/packages/client/.yarnrc
!/packages/client/yarn.lock
!/apps/client/src
!/apps/client/.env
!/apps/client/index.html
!/apps/client/splashscreen.html
!/apps/client/tsconfig.json
!/apps/client/tsconfig.node.json
!/apps/client/vite.config.ts
!/apps/client/package.json

@ -1,56 +0,0 @@
name: Test and deploy Client
on:
push:
branches:
- main
paths:
- packages/client/**
- .github/workflows/deploy-client.yml
jobs:
test:
name: Test client
runs-on: ubuntu-latest
steps:
- name: Setup
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: "16.x"
cache: "yarn"
- name: Install NPM dependencies
working-directory: ./packages/client
run: yarn install
- name: Lint source
working-directory: ./packages/client
run: yarn lint
- name: Build client
working-directory: ./packages/client
run: yarn run build
- name: Check size
working-directory: ./packages/client
run: yarn run size
docker:
name: Build Docker image
runs-on: ubuntu-latest
needs: test
steps:
- name: Setup
uses: actions/checkout@v2
- name: Build and push to Docker hub
uses: guusvanmeerveld/actions/docker@main
with:
username: guusvanmeerveld
token: ${{ secrets.DOCKERHUB_TOKEN }}
tags: guusvanmeerveld/dust-mail:git-client
context: packages/client
platforms: linux/amd64,linux/arm64

@ -0,0 +1,84 @@
name: Test and deploy Server
on:
push:
branches:
- main
paths:
- apps/server/**
- .github/workflows/deploy-commit.yml
- Dockerfile
- entrypoint.sh
- nginx/**
- .dockerignore
- apps/**
- packages/**
jobs:
test:
name: Test server
runs-on: ubuntu-latest
steps:
- name: Setup
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: "12.x"
cache: "pnpm"
- name: Install NPM dependencies
run: pnpm install
- name: Run full suite
run: pnpm run deploy
docker:
name: Build Docker image
runs-on: ubuntu-latest
needs: test
steps:
- name: Setup
uses: actions/checkout@v2
- name: Build base image
uses: guusvanmeerveld/actions/docker@main
with:
username: guusvanmeerveld
token: ${{ secrets.DOCKERHUB_TOKEN }}
tags: dust-mail/base
push: false
context: .
file: Dockerfile.base
platforms: linux/amd64,linux/arm64
- name: Build server image
uses: guusvanmeerveld/actions/docker@main
with:
username: guusvanmeerveld
token: ${{ secrets.DOCKERHUB_TOKEN }}
tags: guusvanmeerveld/dust-mail:git-server
context: .
file: apps/server/Dockerfile
platforms: linux/amd64,linux/arm64
- name: Build client image
uses: guusvanmeerveld/actions/docker@main
with:
username: guusvanmeerveld
token: ${{ secrets.DOCKERHUB_TOKEN }}
tags: guusvanmeerveld/dust-mail:git-client
context: .
file: apps/client/Dockerfile
platforms: linux/amd64,linux/arm64
- name: Build standalone image
uses: guusvanmeerveld/actions/docker@main
with:
username: guusvanmeerveld
token: ${{ secrets.DOCKERHUB_TOKEN }}
tags: guusvanmeerveld/dust-mail:git-standalone
context: .
file: Dockerfile
platforms: linux/amd64,linux/arm64

@ -1,58 +0,0 @@
name: Test and deploy Server
on:
push:
branches:
- main
paths:
- packages/server/**
- .github/workflows/deploy-server.yml
jobs:
test:
name: Test server
runs-on: ubuntu-latest
steps:
- name: Setup
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: "12.x"
cache: "yarn"
- name: Install NPM dependencies
working-directory: ./packages/server
run: yarn install
- name: Lint source
working-directory: ./packages/server
run: yarn run lint
- name: Build server
working-directory: ./packages/server
run: yarn run build
# - name: Run normal tests
# run: yarn --cwd packages/server run test
# - name: Run end-to-end tests
# run: yarn --cwd packages/server run test:e2e
docker:
name: Build Docker image
runs-on: ubuntu-latest
needs: test
steps:
- name: Setup
uses: actions/checkout@v2
- name: Build and push to Docker hub
uses: guusvanmeerveld/actions/docker@main
with:
username: guusvanmeerveld
token: ${{ secrets.DOCKERHUB_TOKEN }}
tags: guusvanmeerveld/dust-mail:git-server
context: packages/server
platforms: linux/amd64,linux/arm64

@ -1,30 +0,0 @@
name: Deploy Standalone
on:
push:
branches:
- main
paths:
- .github/workflows/deploy-standalone.yml
- Dockerfile
- entrypoint.sh
- nginx/**
- .dockerignore
- packages/server/**
- packages/client/**
jobs:
docker:
name: Build Docker image
runs-on: ubuntu-latest
steps:
- name: Setup
uses: actions/checkout@v2
- name: Build and push to Docker hub
uses: guusvanmeerveld/actions/docker@main
with:
username: guusvanmeerveld
token: ${{ secrets.DOCKERHUB_TOKEN }}
tags: guusvanmeerveld/dust-mail:git-standalone
platforms: linux/amd64,linux/arm64

@ -1,34 +0,0 @@
name: Publish Mail-Discover package to NPM
on:
push:
branches:
- main
paths:
- .github/workflows/release-discover.yml
release:
types: [created]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Setup Checkout
uses: actions/checkout@v2
- name: Setup NodeJS v12
uses: actions/setup-node@v2
with:
node-version: 12
cache: "yarn"
- name: Install Dependencies
run: yarn --cwd packages/mail-discover install
- name: Build package
run: yarn --cwd packages/mail-discover build
- name: Publish package
run: yarn --cwd packages/mail-discover publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

@ -84,21 +84,6 @@ jobs:
context: .
platforms: linux/amd64,linux/arm64
deploy_to_heroku:
name: Deploy to Heroku
runs-on: ubuntu-latest
steps:
- name: Setup
uses: actions/checkout@v2
- name: Push to Heroku
uses: akhileshns/heroku-deploy@v3.12.12
with:
heroku_api_key: ${{secrets.HEROKU_API_KEY}}
heroku_app_name: "dust-mail"
heroku_email: "${{secrets.HEROKU_EMAIL}}"
appdir: "packages/server"
deploy_to_pages:
name: Build pages
runs-on: ubuntu-latest
@ -110,21 +95,20 @@ jobs:
uses: actions/setup-node@v2
with:
node-version: "16.x"
cache: "yarn"
cache: "pnpm"
- name: Install NPM dependencies
working-directory: ./packages/client
run: yarn install
run: pnpm install
- name: Build client
working-directory: ./packages/client
run: yarn run build
working-directory: ./apps/client
run: pnpm run build
- name: Deploy to pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./packages/client/dist
publish_dir: ./apps/client/dist
cname: dust-mail.guusvanmeerveld.dev
release_assets:
@ -149,7 +133,7 @@ jobs:
uses: actions/setup-node@v2
with:
node-version: "16.x"
cache: "yarn"
cache: "pnpm"
- name: Setup Rust
uses: actions-rs/toolchain@v1
@ -161,14 +145,13 @@ jobs:
- name: Setup Rust cache
uses: Swatinem/rust-cache@v1
with:
working-directory: ./packages/client/src-tauri
working-directory: ./apps/client/src-tauri
- name: Install NPM dependencies
working-directory: ./packages/client
run: yarn install
run: pnpm install
- name: Fetch crates
working-directory: ./packages/client/src-tauri
working-directory: ./apps/client/src-tauri
run: cargo fetch --locked
- name: Install dependencies (linux only)
@ -183,5 +166,5 @@ jobs:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
with:
projectPath: packages/client
projectPath: apps/client
releaseId: ${{ needs.create_release.outputs.release_id }}

@ -1,32 +0,0 @@
name: Mail-Discover Tests
on:
push:
branches:
- main
paths:
- packages/mail-discover/**
- .github/workflows/test-discover.yml
jobs:
test:
runs-on: ubuntu-latest
name: Run tests
steps:
- name: Setup Checkout
uses: actions/checkout@v2
- name: Setup NodeJS v12
uses: actions/setup-node@v2
with:
node-version: 12
cache: "yarn"
- name: Install Dependencies
run: yarn --cwd packages/mail-discover install
- name: Build package
run: yarn --cwd packages/mail-discover run build
- name: Run tests
run: yarn --cwd packages/mail-discover run test

3
.gitignore vendored

@ -1,2 +1,3 @@
node_modules
dist
dist
.turbo

@ -1,5 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
yarn --cwd packages/client run lint
yarn --cwd packages/server run lint
pnpm run lint

@ -0,0 +1 @@
strict-peer-dependencies=false

@ -33,8 +33,8 @@
"request": "launch",
"env": {
"PORT": "4000",
"GOOGLE_CLIENT_ID": "1005771905136-j5775tafg4buo3a2sjca1rqpc2mo7c2j.apps.googleusercontent.com",
"GOOGLE_CLIENT_SECRET": "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"
"GOOGLE_CLIENT_ID": "1005771905136-i50pkn5dfpbqder32mlb6h67tst8d89h.apps.googleusercontent.com",
"GOOGLE_CLIENT_SECRET": "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"
},
"command": "yarn run start:debug",
"cwd": "${workspaceFolder}/packages/server"

@ -2,48 +2,19 @@
# This Dockerfile combines both the client and the server into a single container
#
ARG BASE_IMAGE=node:16-alpine
FROM dust-mail/base as deployer
# Build client
FROM $BASE_IMAGE AS client-builder
WORKDIR /repo
WORKDIR /app
COPY ./packages/client/package.json ./packages/client/yarn.lock ./packages/client/.yarnrc ./
RUN yarn install --frozen-lockfile
COPY ./packages/client .
ENV NODE_ENV "production"
ENV VITE_DEFAULT_SERVER "/api"
ENV VITE_APP_NAME "Dust-Mail"
RUN yarn build
# Build server
FROM $BASE_IMAGE AS server-builder
WORKDIR /app
COPY ./packages/server/package.json ./packages/server/yarn.lock ./packages/server/.yarnrc ./
RUN yarn install --frozen-lockfile
COPY ./packages/server .
RUN yarn build
RUN yarn install --production --ignore-scripts --prefer-offline
RUN pnpm --filter @dust-mail/client --prod deploy /app/client
RUN pnpm --filter @dust-mail/server --prod deploy /app/server
# Run nginx + api
FROM nginx:stable-alpine as runner
RUN apk add --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/v3.11/main/ nodejs=12.22.6-r0
COPY --from=client-builder /app/dist /client
COPY --from=deployer /app/client/dist /client
COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
@ -55,12 +26,11 @@ ENV NODE_ENV "production"
ENV BASE_PATH "api"
COPY --from=server-builder /app/dist ./dist
COPY --from=server-builder /app/node_modules ./node_modules
COPY --from=server-builder /app/package.json ./package.json
COPY --from=deployer /app/server/dist ./dist
COPY --from=deployer /app/server/node_modules ./node_modules
COPY entrypoint.sh .
COPY packages/server/public public
COPY apps/server/public public
CMD [ "./entrypoint.sh" ]

@ -0,0 +1,23 @@
ARG BASE_IMAGE=node:16-alpine
# Builder
FROM $BASE_IMAGE
RUN apk add --no-cache curl git
RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
WORKDIR /repo
COPY pnpm-lock.yaml ./
RUN pnpm fetch
COPY apps ./apps
COPY packages ./packages
COPY package.json pnpm-workspace.yaml .npmrc turbo.json ./
RUN pnpm install -r --offline --ignore-scripts
RUN pnpm run build

@ -0,0 +1,11 @@
FROM dust-mail/base as deployer
WORKDIR /repo
RUN pnpm --filter @dust-mail/client --prod deploy /app
FROM nginx:alpine AS runner
COPY --from=deployer /app/dist /usr/share/nginx/html
EXPOSE 80

@ -38,7 +38,8 @@
"@tauri-apps/api": "^1.0.2",
"axios": "^0.27.2",
"js-md5": "^0.7.3",
"preact": "^10.5.15",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-query": "^3.39.1",
"react-router-dom": "6",
"slate": "^0.81.1",
@ -48,24 +49,27 @@
},
"devDependencies": {
"@babel/plugin-transform-react-jsx-source": "^7.18.6",
"@preact/preset-vite": "^2.1.5",
"@rollup/plugin-alias": "^3.1.9",
"@size-limit/preset-app": "^7.0.8",
"@tauri-apps/cli": "^1.0.4",
"@types/jest": "^28.1.4",
"@types/js-md5": "^0.4.3",
"@types/node": "^17.0.35",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"@typescript-eslint/eslint-plugin": "^5.30.7",
"@typescript-eslint/parser": "^5.30.7",
"@vitejs/plugin-react": "^2.0.0",
"eslint": "^8.20.0",
"eslint-plugin-jsx-a11y": "^6.6.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-react-hooks": "^4.6.0",
"@dust-mail/tsconfig": "workspace:*",
"prettier": "^2.7.1",
"size-limit": "^7.0.8",
"typescript": "^4.5.4",
"vite": "^2.9.9",
"vite": "^3.0.3",
"vite-plugin-pwa": "^0.12.2",
"vite-tsconfig-paths": "^3.4.1",
"workbox-window": "^6.5.3"

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Before

Width:  |  Height:  |  Size: 1019 B

After

Width:  |  Height:  |  Size: 1019 B

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Before

Width:  |  Height:  |  Size: 279 KiB

After

Width:  |  Height:  |  Size: 279 KiB

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

@ -1,8 +1,8 @@
{
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
"build": {
"beforeBuildCommand": "yarn build",
"beforeDevCommand": "yarn dev",
"beforeBuildCommand": "pnpm build",
"beforeDevCommand": "pnpm dev",
"devPath": "http://localhost:3000/",
"distDir": "../dist",
"withGlobalTauri": true

@ -8,9 +8,8 @@ import {
homepage
} from "../../package.json";
import { FunctionalComponent } from "preact";
import { useEffect } from "preact/hooks";
import { FC } from "react";
import { useEffect } from "react";
import Box from "@mui/material/Box";
import IconButton from "@mui/material/IconButton";
@ -34,7 +33,7 @@ import modalStyles from "@styles/modal";
import useStore from "@utils/hooks/useStore";
import useTheme from "@utils/hooks/useTheme";
const Contributor: FunctionalComponent<{
const Contributor: FC<{
name: string;
url: string;
email: string;
@ -59,7 +58,7 @@ const Contributor: FunctionalComponent<{
</ListItem>
);
const About: FunctionalComponent = () => {
const About: FC = () => {
const theme = useTheme();
const isOpen = useStore((state) => state.showAbout);

@ -1,9 +1,6 @@
import useLocalStorageState from "use-local-storage-state";
import { FunctionalComponent } from "preact";
import { memo } from "preact/compat";
import { useEffect, useMemo } from "preact/hooks";
import { useEffect, useMemo, memo, FC, MouseEvent } from "react";
import Divider from "@mui/material/Divider";
import ListItem from "@mui/material/ListItem";
@ -19,7 +16,7 @@ import MailBox from "@interfaces/box";
import findBoxInPrimaryBoxesList from "@utils/findBoxInPrimaryBoxesList";
import useSelectedBox from "@utils/hooks/useSelectedBox";
const UnMemoizedBoxesList: FunctionalComponent<{
const UnMemoizedBoxesList: FC<{
switchBox?: (e: MouseEvent) => void;
}> = ({ switchBox: switchBoxCb }) => {
const [boxes] = useLocalStorageState<{ name: string; id: string }[]>("boxes");

@ -1,12 +1,10 @@
import useLocalStorageState from "use-local-storage-state";
import { FunctionalComponent } from "preact";
import { ChangeEvent } from "preact/compat";
import { ChangeEvent, FC } from "react";
import Switch from "@mui/material/Switch";
const DarkModeSwitch: FunctionalComponent = () => {
const DarkModeSwitch: FC = () => {
const [darkMode, setDarkMode] = useLocalStorageState<boolean>("darkMode");
const handleChange = (e: ChangeEvent<HTMLInputElement>): void => {

@ -1,13 +1,13 @@
import Loading from "./Loading";
import { FunctionComponent } from "preact";
import { FC, ReactNode } from "react";
import About from "@components/About";
import MessageComposer from "@components/Message/Composer";
import Navbar from "@components/Navbar";
import Settings from "@components/Settings";
const Layout: FunctionComponent<{ withNavbar?: boolean }> = ({
const Layout: FC<{ withNavbar?: boolean; children?: ReactNode }> = ({
children,
withNavbar
}) => {

@ -1,11 +1,11 @@
import { FunctionalComponent } from "preact";
import { FC } from "react";
import Box from "@mui/material/Box";
import LinearProgress from "@mui/material/LinearProgress";
import useStore from "@utils/hooks/useStore";
const Loading: FunctionalComponent = () => {
const Loading: FC = () => {
const fetching = useStore((state) => state.fetching);
if (fetching)

@ -2,10 +2,7 @@ import create from "zustand";
import { description } from "../../../package.json";
import { FunctionalComponent } from "preact";
import { memo, TargetedEvent } from "preact/compat";
import { useEffect, useState } from "preact/hooks";
import { useEffect, useState, FC, memo, KeyboardEvent, FormEvent } from "react";
import Alert from "@mui/material/Alert";
import AlertTitle from "@mui/material/AlertTitle";
@ -57,7 +54,7 @@ const createLoginSettingsStore = create<Store>((set) => ({
/**
* Creates two input fields for the username and password
*/
const Credentials: FunctionalComponent<{
const Credentials: FC<{
error?: APIError;
required?: boolean;
setError: (error?: APIError) => void;
@ -126,7 +123,7 @@ const Credentials: FunctionalComponent<{
);
};
const UnMemoizedServerPropertiesColumn: FunctionalComponent<{
const UnMemoizedServerPropertiesColumn: FC<{
type: ServerType;
}> = ({ type }) => {
const setSetting = createLoginSettingsStore((state) => state.setProperty);
@ -185,7 +182,6 @@ const UnMemoizedServerPropertiesColumn: FunctionalComponent<{
: 25
}`}
variant="outlined"
min="1"
type="number"
/>
@ -203,7 +199,7 @@ const UnMemoizedServerPropertiesColumn: FunctionalComponent<{
const ServerPropertiesColumn = memo(UnMemoizedServerPropertiesColumn);
const AdvancedLoginMenu: FunctionalComponent = () => {
const AdvancedLoginMenu: FC = () => {
const theme = useTheme();
const [isOpen, setOpen] = useState(false);
@ -283,7 +279,7 @@ const AdvancedLoginMenu: FunctionalComponent = () => {
);
};
const LoginForm: FunctionalComponent = () => {
const LoginForm: FC = () => {
const theme = useTheme();
const fetching = useStore((state) => state.fetching);
@ -304,7 +300,7 @@ const LoginForm: FunctionalComponent = () => {
/**
* Runs when the form should be submitted to the server
*/
const onSubmit = async (e?: TargetedEvent): Promise<void> => {
const onSubmit = async (e?: FormEvent): Promise<void> => {
if (e) e.preventDefault();
// Reject the form if there any fields empty

@ -1,12 +1,9 @@
import { WebviewWindow } from "@tauri-apps/api/window";
import useLocalStorageState from "use-local-storage-state";
import { FC, useEffect, useMemo, useState } from "react";
import { useQuery } from "react-query";
import { FunctionalComponent } from "preact";
import { useEffect, useMemo, useState } from "preact/hooks";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import CircularProgress from "@mui/material/CircularProgress";
@ -15,12 +12,13 @@ import Modal from "@mui/material/Modal";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import { LoginResponse } from "@interfaces/responses";
import modalStyles from "@styles/modal";
import useFetch from "@utils/hooks/useFetch";
import useLogin from "@utils/hooks/useLogin";
import useTheme from "@utils/hooks/useTheme";
import { LoginResponse } from "@interfaces/responses";
const oauthWindowLabel = "oauth2-login";
@ -88,7 +86,7 @@ const useTauriOAuth = (): ((oauthLink: string) => void) => {
};
};
const OtherLogins: FunctionalComponent = () => {
const OtherLogins: FC = () => {
const theme = useTheme();
const [isOpen, setOpen] = useState(false);
@ -141,45 +139,47 @@ const OtherLogins: FunctionalComponent = () => {
<Modal onClose={() => setOpen(false)} open={isOpen}>
<Box sx={modalStyles(theme)}>
<Stack direction="column" spacing={2}>
<Typography variant="h5" textAlign="center">
Other login methods
</Typography>
{isFetching && (
<Box sx={{ display: "flex", justifyContent: "center" }}>
<CircularProgress />
</Box>
)}
{error && (
<Typography textAlign="center">
No other login methods supported on this{" "}
{import.meta.env.VITE_APP_NAME} server.
<>
<Typography variant="h5" textAlign="center">
Other login methods
</Typography>
)}
<Container>
<Stack direction="column" spacing={2}>
{googleOAuthLink && (
<Button
onClick={() => {
if ("__TAURI_METADATA__" in window)
handleTauriOAuth(googleOAuthLink);
else if ("open" in window)
handleWebOAuth(googleOAuthLink);
}}
fullWidth
variant="outlined"
startIcon={
<img
height={30}
src="/logo/google.png"
alt="google-logo"
/>
}
>
Login with Google
</Button>
)}
</Stack>
</Container>
{isFetching && (
<Box sx={{ display: "flex", justifyContent: "center" }}>
<CircularProgress />
</Box>
)}
{error && (
<Typography textAlign="center">
No other login methods supported on this{" "}
{import.meta.env.VITE_APP_NAME} server.
</Typography>
)}
<Container>
<Stack direction="column" spacing={2}>
{googleOAuthLink && (
<Button
onClick={() => {
if ("__TAURI_METADATA__" in window)
handleTauriOAuth(googleOAuthLink);
else if ("open" in window)
handleWebOAuth(googleOAuthLink);
}}
fullWidth
variant="outlined"
startIcon={
<img
height={30}
src="/logo/google.png"
alt="google-logo"
/>
}
>
Login with Google
</Button>
)}
</Stack>
</Container>
</>
</Stack>
</Box>
</Modal>

@ -2,9 +2,8 @@ import useLocalStorageState from "use-local-storage-state";
import { repository } from "../../../package.json";
import { FunctionalComponent } from "preact";
import { useState } from "preact/hooks";
import { FC } from "react";
import { useState } from "react";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
@ -21,7 +20,7 @@ import modalStyles from "@styles/modal";
import useTheme from "@utils/hooks/useTheme";
const LoginSettingsMenu: FunctionalComponent = () => {
const LoginSettingsMenu: FC = () => {
const theme = useTheme();
const [isOpen, setOpen] = useState(false);

@ -1,4 +1,4 @@
import { FunctionalComponent } from "preact";
import { FC } from "react";
import SpeedDial from "@mui/material/SpeedDial";
import SpeedDialAction from "@mui/material/SpeedDialAction";
@ -7,7 +7,7 @@ import SpeedDialIcon from "@mui/material/SpeedDialIcon";
import useMessageActions from "@utils/hooks/useMessageActions";
import useSelectedMessage from "@utils/hooks/useSelectedMessage";
const MessageActionButton: FunctionalComponent = () => {
const MessageActionButton: FC = () => {
const [selectedMessage] = useSelectedMessage();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion

@ -4,12 +4,17 @@ import useLocalStorageState from "use-local-storage-state";
import { Descendant, createEditor, Transforms, Text, Editor } from "slate";
import { Editable, Slate, withReact } from "slate-react";
import {
useCallback,
useEffect,
useMemo,
useState,
FC,
ReactNode,
KeyboardEvent
} from "react";
import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
import { ComponentChildren, FunctionalComponent, JSX } from "preact";
import { useCallback, useEffect, useMemo, useState } from "preact/hooks";
import Box from "@mui/material/Box";
import Modal from "@mui/material/Modal";
import Stack from "@mui/material/Stack";
@ -78,21 +83,24 @@ const toggleMark = (editor: Editor, format: keyof Omit<CustomText, "text">) => {
}
};
const CodeElement: FunctionalComponent<{
const CodeElement: FC<{
attributes: Record<string, unknown>;
children?: ReactNode;
}> = (props) => (
<pre {...props.attributes}>
<code>{props.children}</code>
</pre>
);
const DefaultElement: FunctionalComponent<{
const DefaultElement: FC<{
attributes: Record<string, unknown>;
children?: ReactNode;
}> = (props) => <p {...props.attributes}>{props.children}</p>;
const Leaf: FunctionalComponent<{
const Leaf: FC<{
leaf: Omit<CustomText, "text">;
attributes: Record<string, unknown>;
children?: ReactNode;
}> = (props) => (
<span
{...props.attributes}
@ -102,9 +110,7 @@ const Leaf: FunctionalComponent<{
</span>
);
const TextEditor: FunctionalComponent<{ initialValue?: string }> = ({
initialValue
}) => {
const TextEditor: FC<{ initialValue?: string }> = ({ initialValue }) => {
const [value, setValue] = useState<Descendant[]>([
{
type: "paragraph",
@ -116,7 +122,7 @@ const TextEditor: FunctionalComponent<{ initialValue?: string }> = ({
(props: {
element: CustomElement;
attributes: Record<string, unknown>;
children: ComponentChildren;
children: ReactNode;
}) => JSX.Element
>((props) => {
switch (props.element.type) {
@ -129,8 +135,8 @@ const TextEditor: FunctionalComponent<{ initialValue?: string }> = ({
const renderLeaf = useCallback<
(props: {
leaf: { bold: boolean };
children: ComponentChildren;
leaf: CustomText;
children?: ReactNode;
attributes: Record<string, unknown>;
}) => JSX.Element
>((props) => {
@ -174,7 +180,7 @@ const TextEditor: FunctionalComponent<{ initialValue?: string }> = ({
);
};
const MessageComposer: FunctionalComponent = () => {
const MessageComposer: FC = () => {
const theme = useTheme();
const location = useLocation();

@ -1,9 +1,7 @@
import { useInfiniteQuery } from "react-query";
import { FunctionalComponent } from "preact";
import useLocalStorageState from "use-local-storage-state";
import { memo } from "preact/compat";
import { useEffect, useRef, useState } from "preact/hooks";
import { useEffect, useRef, useState, memo, FC } from "react";
import { useInfiniteQuery } from "react-query";
import { AxiosError } from "axios";