Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • Ategon/canvas
  • marius851000/canvas
  • sc07/canvas
3 results
Show changes
Commits on Source (236)
Showing
with 9577 additions and 8478 deletions
......@@ -6,6 +6,7 @@ packages/build
Dockerfile
# dotfiles
.git*
.gitignore
.vscode
**/.env*
\ No newline at end of file
**/.env*
.gitlab-ci.yml
\ No newline at end of file
{
"root": true,
"ignorePatterns": ["node_modules", "packages/**/dist"],
"plugins": ["simple-import-sort"],
"rules": {
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error"
}
}
stages:
- lint
- build
- test
- deploy
eslint client:
stage: lint
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- packages/client/src/**/*
image: node:23-alpine
script:
- npm i --include=dev
- npm -w packages/client run lint
artifacts:
reports:
codequality: packages/client/gl-codequality.json
eslint server:
stage: lint
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- packages/server/src/**/*
image: node:23-alpine
script:
- npm i --include=dev
- npm -w packages/server run lint
artifacts:
reports:
codequality: packages/server/gl-codequality.json
build wiki:
stage: build
trigger:
include: .gitlab/ci/wiki.yml
allow_failure: true
rules:
- if: $CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
deploy:
stage: deploy
trigger:
include: .gitlab/ci/deploy.yml
allow_failure: true
rules:
- if: $CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
variables:
REGISTRY: registry.sc07.dev
IMAGE_NAME: sc07/canvas:edge
publish:
stage: build
tags:
- red
interruptible: true
before_script:
- echo $PAT | docker login $REGISTRY -u $GITLAB_USER_LOGIN --password-stdin
script:
- |
docker build --tag $REGISTRY/$IMAGE_NAME \
--build-arg SENTRY_URL=$SENTRY_URL \
--build-arg SENTRY_ORG=$SENTRY_ORG \
--build-arg CLIENT_SENTRY_PROJECT=$CLIENT_SENTRY_PROJECT \
--build-arg CLIENT_SENTRY_DSN=$CLIENT_SENTRY_DSN \
--build-arg SERVER_SENTRY_PROJECT=$SERVER_SENTRY_PROJECT \
--build-arg SERVER_SENTRY_DSN=$SERVER_SENTRY_DSN \
--build-arg SENTRY_AUTH_TOKEN=$SENTRY_AUTH_TOKEN .
- docker push $REGISTRY/$IMAGE_NAME
deploy:
stage: deploy
tags:
- red
interruptible: true
script:
- cd $WORK_DIR
- docker compose pull
- docker compose up -d
# sync /doc/ to internal wiki repo for UI access
# see #151
build-wiki:
image: alpine
stage: build
before_script:
- apk add --no-cache git git-subtree
script:
- git config user.email "ci@sc07.company"
- git config user.name "ci"
- git remote remove gitlab-wiki || true
- git remote add gitlab-wiki "https://ci:$CI_TOKEN@sc07.dev/sc07/canvas.wiki.git"
- git status
- git checkout main
- git pull
- git push gitlab-wiki `git subtree split -P doc main`:main --force
version: 2
update-options:
rebase-strategy: all
reviewers:
- grant
vulnerability-alerts:
enabled: true
confidential: true
assignees:
- grant
updates:
- package-ecosystem: "npm"
directories:
- "/"
- "/packages/admin"
- "/packages/client"
- "/packages/lib"
- "/packages/server"
schedule:
interval: "daily"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
v23.5.0
FROM node:20-alpine AS base
FROM node:23-alpine AS base
# to be able to read git hash
RUN apk -U upgrade && apk add --no-cache git openssh
RUN git config --global --add safe.directory /home/node/app
FROM base as dev_dep
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
WORKDIR /home/node/app
# --- dependencies ---
COPY --chown=node:node package*.json ./
COPY --chown=node:node packages/admin/package*.json ./packages/admin/
COPY --chown=node:node packages/client/package*.json ./packages/client/
COPY --chown=node:node packages/lib/package*.json ./packages/lib/
COPY --chown=node:node packages/server/package*.json ./packages/server/
USER node
RUN npm install --include=dev
FROM base as dep
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
WORKDIR /home/node/app
# --- dependencies ---
COPY --chown=node:node package*.json ./
COPY --chown=node:node packages/admin/package*.json ./packages/admin/
COPY --chown=node:node packages/client/package*.json ./packages/client/
COPY --chown=node:node packages/lib/package*.json ./packages/lib/
COPY --chown=node:node packages/server/package*.json ./packages/server/
USER node
RUN npm install --omit=dev
#
# === BUILDER ===
......@@ -7,10 +39,20 @@ FROM node:20-alpine AS base
FROM base as build
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
WORKDIR /home/node/app
COPY --chown=node:node . .
USER node
RUN npm install --include=dev
# CLIENT_SENTRY_DSN will be baked into the client package
# SERVER_SENTRY_DSN is NOT baked in and must also be supplied to image on start
# SENTRY_{URL,ORG,PROJECT,AUTH_TOKEN} are used for sourcemap pushing
ARG CLIENT_SENTRY_DSN
ARG CLIENT_SENTRY_PROJECT
ARG SERVER_SENTRY_DSN
ARG SERVER_SENTRY_PROJECT
ARG SENTRY_URL
ARG SENTRY_ORG
ARG SENTRY_AUTH_TOKEN
COPY --from=dev_dep --chown=node:node /home/node/app/ ./
COPY --chown=node:node . .
# --- build lib ---
......@@ -20,16 +62,23 @@ RUN sed -i -e 's/"main": ".*"/"main": ".\/dist\/index.js"/' packages/lib/package
# --- build main client ---
ARG VITE_INCLUDE_EVENT_INFO
ARG SENTRY_DSN=$CLIENT_SENTRY_DSN
ARG SENTRY_PROJECT=$CLIENT_SENTRY_PROJECT
RUN npm -w packages/client run build
# --- build admin ---
ENV APP_ROOT /admin
RUN npm -w packages/admin run build
# --- build server ---
RUN npx -w packages/server prisma generate
ARG SENTRY_DSN=$SERVER_SENTRY_DSN
ARG SENTRY_PROJECT=$SERVER_SENTRY_PROJECT
RUN npm -w packages/server run build
RUN if [ -n "$SENTRY_AUTH_TOKEN" ]; then npm -w packages/server run sentry; fi
#
# === RUNNER ===
......@@ -37,7 +86,8 @@ RUN npm -w packages/server run build
FROM base as run
WORKDIR /home/node/app
COPY package*.json docker-start.sh ./
COPY --from=dep /home/node/app/ ./
COPY package*.json docker-start*.sh .git ./
# --- prepare lib ---
......@@ -65,7 +115,6 @@ COPY --from=build /home/node/app/packages/server/dist ./packages/server/dist
# --- finalize ---
RUN npm install --omit=dev
RUN npx -w packages/server prisma generate
# set runtime env variables
......@@ -74,7 +123,13 @@ ENV PORT 3000
ENV NODE_ENV production
ENV SERVE_CLIENT /home/node/app/packages/client
ENV SERVE_ADMIN /home/node/app/packages/admin
ENV PIXEL_LOG_PATH /home/node/app/pixel.log
VOLUME /home/node/app/pixel.log
EXPOSE 3000
# profiler port, only used if profiler is explicity running
EXPOSE 9229
ENTRYPOINT [ "/bin/sh" ]
CMD [ "./docker-start.sh" ]
\ No newline at end of file
---
title: Sentry
---
The frontend & backend are both equiped with [Sentry](https://sentry.io) error reporting to aid with debugging.
You can selfhost Sentry [using this guide](https://develop.sentry.dev/self-hosted/).
**Note:** if the Sentry DSN environment variable isn't present, Sentry will not be initialized and therefore will not send any information
**Note:** if the PROJECT, ORG, URL, AUTH_TOKEN is not provided sourcemaps will not be uploaded at build time
**Environment Variable Keys:**
- `build` used during the build phase (usually `npm run build`)
- `dev` used during development (usually `npm run dev`)
- `runtime` used during runtime/deployment
# Docker Building
Docker builds will take the build environment variables as `--build-arg`s, with a couple changes
- Frontend's `SENTRY_DSN` & `SENTRY_PROJECT` are renamed to `CLIENT_SENTRY_DSN` & `CLIENT_SENTRY_PROJECT` respectfully
- Backend's `SENTRY_DSN` & `SENTRY_PROJECT` are renamed to `SERVER_SENTRY_DSN` & `SERVER_SENTRY_PROJECT` respectfully
As each project has to be separated within Sentry, the DSN & project IDs will be different
_See `/Dockerfile` for how they're used_<br />
_See `/.gitlab/ci/deploy.yml` for an example of a `docker build` with the arguments_
# Frontend
With how Vite builds, the environment variables will be used during the build stage to generate the client
## Environment
| Environment | Uses | Description |
| ------------------- | ---------- | ---------------------------------------------------------------------------------------------- |
| `SENTRY_DSN` | build, dev | Frontend DSN, baked into the client as `__SENTRY_DSN__` (see `packages/client/vite.config.js`) |
| `SENTRY_PROJECT` | build | Project ID, used to send sourcemaps to Sentry |
| `SENTRY_ORG` | build | Project organization ID, used to send sourcemaps |
| `SENTRY_URL` | build | Sentry hostname (eg `https://sentry.io`) |
| `SENTRY_AUTH_TOKEN` | build | Auth token for sending the sourcemaps |
# Backend
## Environment
| Environment | Uses | Description |
| --------------------------- | ------------------- | --------------------------------------------------------------- |
| `SENTRY_DSN` | build, runtime, dev | Backend DSN |
| `SENTRY_TUNNEL_PROJECT_IDS` | runtime, dev | Comma-separated list of project IDs to allow through the tunnel |
| `SENTRY_PROJECT` | build | Project ID, used to send sourcemaps |
| `SENTRY_ORG` | build | Project organization ID, used to send sourcemaps |
| `SENTRY_URL` | build | Sentry hostname (eg `https://sentry.io`) |
| `SENTRY_AUTH_TOKEN` | build | Auth token for sending sourcemaps |
| `SENTRY_ENVIRONMENT` | runtime | Passed to Sentry to log what environment we're running in |
# Canvas
Documentation example
......@@ -9,16 +9,29 @@ services:
build: .
ports:
- "3000:3000"
# - "9229:9229"
environment:
- SESSION_SECRET=CHANGE ME TO RANDOM VALUE
- REDIS_HOST=redis://redis
- DATABASE_URL=postgres://postgres@postgres/canvas
- AUTH_ENDPOINT=https://auth.fediverse.events
- AUTH_CLIENT=canvas
- AUTH_SECRET=${AUTH_SECRET}
# - SCRIPT_TO_RUN=profiler
env_file:
- .env.local
depends_on:
- redis
- postgres
redis:
condition: service_healthy
postgres:
condition: service_healthy
worker:
image: sc07/canvas
build: .
environment:
- REDIS_HOST=redis://redis
- DATABASE_URL=postgres://postgres@postgres/canvas
env_file:
- .env.local
depends_on:
- canvas
command: ./docker-start-worker.sh
redis:
restart: always
image: redis:7-alpine
......
#!/bin/sh
npm -w packages/server run tool start_job_worker
\ No newline at end of file
......@@ -3,5 +3,8 @@
# This script runs when the docker image starts
# It just forces all migrations to run and then starts lol
# Allow running of other scripts via environment variable (eg. profiler)
SCRIPT_TO_RUN="${SCRIPT_TO_RUN:-start}"
npx -w packages/server npx prisma migrate deploy
npm -w packages/server run start
\ No newline at end of file
npm -w packages/server run $SCRIPT_TO_RUN
\ No newline at end of file
This diff is collapsed.
......@@ -10,6 +10,7 @@
],
"main": "src/index.ts",
"scripts": {
"lint": "eslint",
"dev:client": "npm run dev -w packages/client",
"dev:server": "npm run dev -w packages/server",
"prisma:studio": "npm run prisma:studio -w packages/server",
......@@ -24,14 +25,41 @@
"author": "",
"license": "ISC",
"devDependencies": {
"@tsconfig/recommended": "^1.0.2",
"dotenv": "^16.3.1",
"nodemon": "^3.0.1",
"prettier": "^3.0.1",
"@sentry/cli": "^2.40.0",
"@sentry/vite-plugin": "^2.22.7",
"@tsconfig/recommended": "^1.0.8",
"@tsconfig/vite-react": "^3.4.0",
"@types/react": "^19.0.3",
"@types/react-dom": "^19.0.2",
"@typescript-eslint/eslint-plugin": "^8.19.1",
"@typescript-eslint/parser": "^8.19.1",
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.20",
"dotenv": "^16.4.7",
"dotenv-cli": "^8.0.0",
"eslint": "^8.57.0",
"eslint-config-react-app": "^7.0.1",
"eslint-formatter-gitlab": "^5.1.0",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-simple-import-sort": "^12.1.1",
"nodemon": "^3.1.9",
"prettier": "^3.4.2",
"tailwindcss": "^3.4.17",
"ts-node": "^10.9.1",
"typescript": "^5.1.6"
"tsx": "^4.19.2",
"typescript": "^5.7.2",
"vite": "^6.0.7",
"vite-plugin-simple-html": "^0.2.0"
},
"dependencies": {
"@quixo3/prisma-session-store": "^3.1.13"
"@fortawesome/fontawesome-svg-core": "^6.7.2",
"@fortawesome/free-brands-svg-icons": "^6.7.2",
"@fortawesome/react-fontawesome": "^0.2.2",
"@quixo3/prisma-session-store": "^3.1.13",
"@sentry/react": "^8.48.0",
"next-themes": "^0.4.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-toastify": "^11.0.2"
}
}
......@@ -10,33 +10,17 @@
"preview": "vite preview"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.5.1",
"@fortawesome/free-solid-svg-icons": "^6.5.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@nextui-org/react": "^2.2.9",
"@fortawesome/free-solid-svg-icons": "^6.7.2",
"@nextui-org/react": "^2.6.11",
"framer-motion": "^11.0.5",
"localforage": "^1.10.0",
"match-sorter": "^6.3.4",
"next-themes": "^0.2.1",
"react": "^18.2.0",
"react-apexcharts": "^1.4.1",
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.1",
"sort-by": "^1.2.0"
"match-sorter": "^8.0.0",
"react-apexcharts": "^1.7.0",
"react-router-dom": "^7.1.1"
},
"devDependencies": {
"@types/react": "^18.2.56",
"@types/react-dom": "^18.2.19",
"@typescript-eslint/eslint-plugin": "^7.0.2",
"@typescript-eslint/parser": "^7.0.2",
"@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.17",
"eslint": "^8.56.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"eslint-plugin-react-refresh": "^0.4.16",
"postcss": "^8.4.35",
"tailwindcss": "^3.4.1",
"typescript": "^5.2.2",
"vite": "^5.1.4"
"typescript": "^5.7.2"
}
}
......@@ -15,7 +15,7 @@ const options: Props["options"] = {
chart: {
type: "area",
animations: {
easing: "linear",
// easing: "linear",
speed: 300,
},
sparkline: {
......
import { Spinner } from "@nextui-org/react";
export const LoadingOverlay = () => {
return (
<div className="absolute top-0 left-0 w-full h-full z-[9999] backdrop-blur-sm bg-black/30 text-white flex items-center justify-center">
<Spinner label="Loading..." />
</div>
);
};
import { useTheme } from "next-themes";
import { ToastContainer } from "react-toastify";
export const ToastWrapper = () => {
const { theme } = useTheme()
return (
<ToastContainer
position="bottom-right"
theme={theme}
/>
);
};
\ No newline at end of file
......@@ -9,6 +9,7 @@ import {
faCog,
faHashtag,
faHome,
faList,
faServer,
faShieldHalved,
faSquare,
......@@ -54,6 +55,12 @@ export const SidebarWrapper = () => {
isActive={pathname === "/"}
href="/"
/>
<SidebarItem
title="Audit Log"
icon={<FontAwesomeIcon icon={faList} />}
isActive={pathname === "/audit"}
href="/audit"
/>
<CollapseItems
icon={<FontAwesomeIcon icon={faChartBar} />}
title="Stats"
......@@ -124,10 +131,10 @@ export const SidebarWrapper = () => {
href="/chat/rooms"
/>
<SidebarItem
isActive={pathname === "/chat/settings"}
isActive={pathname === "/service/settings"}
title="Settings"
icon={<FontAwesomeIcon icon={faCog} />}
href="/chat/settings"
href="/service/settings"
/>
</SidebarMenu>
</div>
......