Merge branch 'develop' of github.com:makeplane/plane into update-file-uploads

This commit is contained in:
pablohashescobar 2024-04-02 12:51:14 +05:30
commit d560d1f7df
40 changed files with 298 additions and 177 deletions

View File

@ -6,7 +6,6 @@ on:
branches: branches:
- master - master
- preview - preview
- develop
release: release:
types: [released, prereleased] types: [released, prereleased]

View File

@ -52,7 +52,7 @@ If you want more control over your data, prefer to self-host Plane, please refer
| Installation Methods | Documentation Link | | Installation Methods | Documentation Link |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Docker | [![Docker](https://img.shields.io/badge/docker-%230db7ed.svg?style=for-the-badge&logo=docker&logoColor=white)](https://docs.plane.so/docker-compose) | | Docker | [![Docker](https://img.shields.io/badge/docker-%230db7ed.svg?style=for-the-badge&logo=docker&logoColor=white)](https://docs.plane.so/self-hosting/methods/docker-compose) |
| Kubernetes | [![Kubernetes](https://img.shields.io/badge/kubernetes-%23326ce5.svg?style=for-the-badge&logo=kubernetes&logoColor=white)](https://docs.plane.so/kubernetes) | | Kubernetes | [![Kubernetes](https://img.shields.io/badge/kubernetes-%23326ce5.svg?style=for-the-badge&logo=kubernetes&logoColor=white)](https://docs.plane.so/kubernetes) |
`Instance admin` can configure instance settings using our [God-mode](https://docs.plane.so/instance-admin) feature. `Instance admin` can configure instance settings using our [God-mode](https://docs.plane.so/instance-admin) feature.

View File

@ -1,4 +1,4 @@
{ {
"name": "plane-api", "name": "plane-api",
"version": "0.16.0" "version": "0.17.0"
} }

View File

@ -5,11 +5,11 @@ x-app-env: &app-env
- NGINX_PORT=${NGINX_PORT:-80} - NGINX_PORT=${NGINX_PORT:-80}
- WEB_URL=${WEB_URL:-http://localhost} - WEB_URL=${WEB_URL:-http://localhost}
- DEBUG=${DEBUG:-0} - DEBUG=${DEBUG:-0}
- SENTRY_DSN=${SENTRY_DSN:-""} - SENTRY_DSN=${SENTRY_DSN}
- SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT:-"production"} - SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT:-"production"}
- CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS:-""} - CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS}
# Gunicorn Workers # Gunicorn Workers
- GUNICORN_WORKERS=${GUNICORN_WORKERS:-2} - GUNICORN_WORKERS=${GUNICORN_WORKERS:-1}
#DB SETTINGS #DB SETTINGS
- PGHOST=${PGHOST:-plane-db} - PGHOST=${PGHOST:-plane-db}
- PGDATABASE=${PGDATABASE:-plane} - PGDATABASE=${PGDATABASE:-plane}
@ -17,11 +17,11 @@ x-app-env: &app-env
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-plane} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-plane}
- POSTGRES_DB=${POSTGRES_DB:-plane} - POSTGRES_DB=${POSTGRES_DB:-plane}
- PGDATA=${PGDATA:-/var/lib/postgresql/data} - PGDATA=${PGDATA:-/var/lib/postgresql/data}
- DATABASE_URL=${DATABASE_URL:-postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${PGHOST}/${PGDATABASE}} - DATABASE_URL=${DATABASE_URL:-postgresql://plane:plane@plane-db/plane}
# REDIS SETTINGS # REDIS SETTINGS
- REDIS_HOST=${REDIS_HOST:-plane-redis} - REDIS_HOST=${REDIS_HOST:-plane-redis}
- REDIS_PORT=${REDIS_PORT:-6379} - REDIS_PORT=${REDIS_PORT:-6379}
- REDIS_URL=${REDIS_URL:-redis://${REDIS_HOST}:6379/} - REDIS_URL=${REDIS_URL:-redis://plane-redis:6379/}
# Application secret # Application secret
- SECRET_KEY=${SECRET_KEY:-60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5} - SECRET_KEY=${SECRET_KEY:-60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5}
# DATA STORE SETTINGS # DATA STORE SETTINGS
@ -39,7 +39,7 @@ x-app-env: &app-env
services: services:
web: web:
<<: *app-env <<: *app-env
image: ${DOCKERHUB_USER:-makeplane}/plane-frontend:${APP_RELEASE:-latest} image: ${DOCKERHUB_USER:-makeplane}/plane-frontend:${APP_RELEASE:-stable}
pull_policy: ${PULL_POLICY:-always} pull_policy: ${PULL_POLICY:-always}
restart: unless-stopped restart: unless-stopped
command: /usr/local/bin/start.sh web/server.js web command: /usr/local/bin/start.sh web/server.js web
@ -51,7 +51,7 @@ services:
space: space:
<<: *app-env <<: *app-env
image: ${DOCKERHUB_USER:-makeplane}/plane-space:${APP_RELEASE:-latest} image: ${DOCKERHUB_USER:-makeplane}/plane-space:${APP_RELEASE:-stable}
pull_policy: ${PULL_POLICY:-always} pull_policy: ${PULL_POLICY:-always}
restart: unless-stopped restart: unless-stopped
command: /usr/local/bin/start.sh space/server.js space command: /usr/local/bin/start.sh space/server.js space
@ -64,7 +64,7 @@ services:
api: api:
<<: *app-env <<: *app-env
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-latest} image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
pull_policy: ${PULL_POLICY:-always} pull_policy: ${PULL_POLICY:-always}
restart: unless-stopped restart: unless-stopped
command: ./bin/takeoff command: ./bin/takeoff
@ -78,7 +78,7 @@ services:
worker: worker:
<<: *app-env <<: *app-env
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-latest} image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
pull_policy: ${PULL_POLICY:-always} pull_policy: ${PULL_POLICY:-always}
restart: unless-stopped restart: unless-stopped
command: ./bin/worker command: ./bin/worker
@ -91,7 +91,7 @@ services:
beat-worker: beat-worker:
<<: *app-env <<: *app-env
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-latest} image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
pull_policy: ${PULL_POLICY:-always} pull_policy: ${PULL_POLICY:-always}
restart: unless-stopped restart: unless-stopped
command: ./bin/beat command: ./bin/beat
@ -104,7 +104,7 @@ services:
migrator: migrator:
<<: *app-env <<: *app-env
image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-latest} image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
pull_policy: ${PULL_POLICY:-always} pull_policy: ${PULL_POLICY:-always}
restart: no restart: no
command: > command: >
@ -118,7 +118,7 @@ services:
plane-db: plane-db:
<<: *app-env <<: *app-env
image: postgres:15.2-alpine image: postgres:15.5-alpine
pull_policy: if_not_present pull_policy: if_not_present
restart: unless-stopped restart: unless-stopped
command: postgres -c 'max_connections=1000' command: postgres -c 'max_connections=1000'
@ -126,7 +126,7 @@ services:
- pgdata:/var/lib/postgresql/data - pgdata:/var/lib/postgresql/data
plane-redis: plane-redis:
<<: *app-env <<: *app-env
image: redis:6.2.7-alpine image: redis:7.2.4-alpine
pull_policy: if_not_present pull_policy: if_not_present
restart: unless-stopped restart: unless-stopped
volumes: volumes:
@ -144,7 +144,7 @@ services:
# Comment this if you already have a reverse proxy running # Comment this if you already have a reverse proxy running
proxy: proxy:
<<: *app-env <<: *app-env
image: ${DOCKERHUB_USER:-makeplane}/plane-proxy:${APP_RELEASE:-latest} image: ${DOCKERHUB_USER:-makeplane}/plane-proxy:${APP_RELEASE:-stable}
pull_policy: ${PULL_POLICY:-always} pull_policy: ${PULL_POLICY:-always}
ports: ports:
- ${NGINX_PORT}:80 - ${NGINX_PORT}:80

View File

@ -17,16 +17,16 @@ function print_header() {
clear clear
cat <<"EOF" cat <<"EOF"
--------------------------------------- --------------------------------------------
____ _ ____ _ /////////
| _ \| | __ _ _ __ ___ | _ \| | __ _ _ __ ___ /////////
| |_) | |/ _` | '_ \ / _ \ | |_) | |/ _` | '_ \ / _ \ ///// /////
| __/| | (_| | | | | __/ | __/| | (_| | | | | __/ ///// /////
|_| |_|\__,_|_| |_|\___| |_| |_|\__,_|_| |_|\___| ////
////
--------------------------------------- --------------------------------------------
Project management tool from the future Project management tool from the future
--------------------------------------- --------------------------------------------
EOF EOF
} }
@ -66,7 +66,7 @@ function buildLocalImage() {
cd $PLANE_TEMP_CODE_DIR cd $PLANE_TEMP_CODE_DIR
if [ "$BRANCH" == "master" ]; if [ "$BRANCH" == "master" ];
then then
export APP_RELEASE=latest export APP_RELEASE=stable
fi fi
docker compose -f build.yml build --no-cache >&2 docker compose -f build.yml build --no-cache >&2
@ -99,17 +99,17 @@ function download() {
curl -H 'Cache-Control: no-cache, no-store' -s -o $PLANE_INSTALL_DIR/docker-compose.yaml https://raw.githubusercontent.com/makeplane/plane/$BRANCH/deploy/selfhost/docker-compose.yml?$(date +%s) curl -H 'Cache-Control: no-cache, no-store' -s -o $PLANE_INSTALL_DIR/docker-compose.yaml https://raw.githubusercontent.com/makeplane/plane/$BRANCH/deploy/selfhost/docker-compose.yml?$(date +%s)
curl -H 'Cache-Control: no-cache, no-store' -s -o $PLANE_INSTALL_DIR/variables-upgrade.env https://raw.githubusercontent.com/makeplane/plane/$BRANCH/deploy/selfhost/variables.env?$(date +%s) curl -H 'Cache-Control: no-cache, no-store' -s -o $PLANE_INSTALL_DIR/variables-upgrade.env https://raw.githubusercontent.com/makeplane/plane/$BRANCH/deploy/selfhost/variables.env?$(date +%s)
if [ -f "$PLANE_INSTALL_DIR/.env" ]; if [ -f "$DOCKER_ENV_PATH" ];
then then
cp $PLANE_INSTALL_DIR/.env $PLANE_INSTALL_DIR/archive/$TS.env cp $DOCKER_ENV_PATH $PLANE_INSTALL_DIR/archive/$TS.env
else else
mv $PLANE_INSTALL_DIR/variables-upgrade.env $PLANE_INSTALL_DIR/.env mv $PLANE_INSTALL_DIR/variables-upgrade.env $DOCKER_ENV_PATH
fi fi
if [ "$BRANCH" != "master" ]; if [ "$BRANCH" != "master" ];
then then
cp $PLANE_INSTALL_DIR/docker-compose.yaml $PLANE_INSTALL_DIR/temp.yaml cp $PLANE_INSTALL_DIR/docker-compose.yaml $PLANE_INSTALL_DIR/temp.yaml
sed -e 's@${APP_RELEASE:-latest}@'"$BRANCH"'@g' \ sed -e 's@${APP_RELEASE:-stable}@'"$BRANCH"'@g' \
$PLANE_INSTALL_DIR/temp.yaml > $PLANE_INSTALL_DIR/docker-compose.yaml $PLANE_INSTALL_DIR/temp.yaml > $PLANE_INSTALL_DIR/docker-compose.yaml
rm $PLANE_INSTALL_DIR/temp.yaml rm $PLANE_INSTALL_DIR/temp.yaml
@ -131,9 +131,9 @@ function download() {
fi fi
echo "" echo ""
echo "Latest version is now available for you to use" echo "Most recent Stable version is now available for you to use"
echo "" echo ""
echo "In case of Upgrade, your new setting file is availabe as 'variables-upgrade.env'. Please compare and set the required values in '.env 'file." echo "In case of Upgrade, your new setting file is availabe as 'variables-upgrade.env'. Please compare and set the required values in 'plane.env 'file."
echo "" echo ""
} }
@ -144,7 +144,7 @@ function startServices() {
if [ -n "$migrator_container_id" ]; then if [ -n "$migrator_container_id" ]; then
local idx=0 local idx=0
while docker inspect --format='{{.State.Status}}' $migrator_container_id | grep -q "running"; do while docker inspect --format='{{.State.Status}}' $migrator_container_id | grep -q "running"; do
local message=">>> Waiting for Data Migration to finish" local message=">> Waiting for Data Migration to finish"
local dots=$(printf '%*s' $idx | tr ' ' '.') local dots=$(printf '%*s' $idx | tr ' ' '.')
echo -ne "\r$message$dots" echo -ne "\r$message$dots"
((idx++)) ((idx++))
@ -152,13 +152,18 @@ function startServices() {
done done
fi fi
printf "\r\033[K" printf "\r\033[K"
echo ""
echo " Data Migration completed successfully ✅"
# if migrator exit status is not 0, show error message and exit # if migrator exit status is not 0, show error message and exit
if [ -n "$migrator_container_id" ]; then if [ -n "$migrator_container_id" ]; then
local migrator_exit_code=$(docker inspect --format='{{.State.ExitCode}}' $migrator_container_id) local migrator_exit_code=$(docker inspect --format='{{.State.ExitCode}}' $migrator_container_id)
if [ $migrator_exit_code -ne 0 ]; then if [ $migrator_exit_code -ne 0 ]; then
echo "Plane Server failed to start ❌" echo "Plane Server failed to start ❌"
stopServices # stopServices
echo
echo "Please check the logs for the 'migrator' service and resolve the issue(s)."
echo "Stop the services by running the command: ./setup.sh stop"
exit 1 exit 1
fi fi
fi fi
@ -167,26 +172,35 @@ function startServices() {
local idx2=0 local idx2=0
while ! docker logs $api_container_id 2>&1 | grep -m 1 -i "Application startup complete" | grep -q "."; while ! docker logs $api_container_id 2>&1 | grep -m 1 -i "Application startup complete" | grep -q ".";
do do
local message=">>> Waiting for API Service to Start" local message=">> Waiting for API Service to Start"
local dots=$(printf '%*s' $idx2 | tr ' ' '.') local dots=$(printf '%*s' $idx2 | tr ' ' '.')
echo -ne "\r$message$dots" echo -ne "\r$message$dots"
((idx2++)) ((idx2++))
sleep 1 sleep 1
done done
printf "\r\033[K" printf "\r\033[K"
echo " API Service started successfully ✅"
source "${DOCKER_ENV_PATH}"
echo " Plane Server started successfully ✅"
echo ""
echo " You can access the application at $WEB_URL"
echo ""
} }
function stopServices() { function stopServices() {
docker compose -f $DOCKER_FILE_PATH --env-file=$DOCKER_ENV_PATH down docker compose -f $DOCKER_FILE_PATH --env-file=$DOCKER_ENV_PATH down
} }
function restartServices() { function restartServices() {
docker compose -f $DOCKER_FILE_PATH --env-file=$DOCKER_ENV_PATH restart # docker compose -f $DOCKER_FILE_PATH --env-file=$DOCKER_ENV_PATH restart
stopServices
startServices
} }
function upgrade() { function upgrade() {
echo "***** STOPPING SERVICES ****" echo "***** STOPPING SERVICES ****"
stopServices stopServices
echo echo
echo "***** DOWNLOADING LATEST VERSION ****" echo "***** DOWNLOADING STABLE VERSION ****"
download download
echo "***** PLEASE VALIDATE AND START SERVICES ****" echo "***** PLEASE VALIDATE AND START SERVICES ****"
@ -303,15 +317,15 @@ function askForAction() {
elif [ "$ACTION" == "2" ] || [ "$DEFAULT_ACTION" == "start" ] elif [ "$ACTION" == "2" ] || [ "$DEFAULT_ACTION" == "start" ]
then then
startServices startServices
askForAction # askForAction
elif [ "$ACTION" == "3" ] || [ "$DEFAULT_ACTION" == "stop" ] elif [ "$ACTION" == "3" ] || [ "$DEFAULT_ACTION" == "stop" ]
then then
stopServices stopServices
askForAction # askForAction
elif [ "$ACTION" == "4" ] || [ "$DEFAULT_ACTION" == "restart" ] elif [ "$ACTION" == "4" ] || [ "$DEFAULT_ACTION" == "restart" ]
then then
restartServices restartServices
askForAction # askForAction
elif [ "$ACTION" == "5" ] || [ "$DEFAULT_ACTION" == "upgrade" ] elif [ "$ACTION" == "5" ] || [ "$DEFAULT_ACTION" == "upgrade" ]
then then
upgrade upgrade
@ -343,7 +357,7 @@ fi
if [ "$BRANCH" == "master" ]; if [ "$BRANCH" == "master" ];
then then
export APP_RELEASE=latest export APP_RELEASE=stable
fi fi
# REMOVE SPECIAL CHARACTERS FROM BRANCH NAME # REMOVE SPECIAL CHARACTERS FROM BRANCH NAME
@ -354,7 +368,21 @@ fi
mkdir -p $PLANE_INSTALL_DIR/archive mkdir -p $PLANE_INSTALL_DIR/archive
DOCKER_FILE_PATH=$PLANE_INSTALL_DIR/docker-compose.yaml DOCKER_FILE_PATH=$PLANE_INSTALL_DIR/docker-compose.yaml
DOCKER_ENV_PATH=$PLANE_INSTALL_DIR/.env DOCKER_ENV_PATH=$PLANE_INSTALL_DIR/plane.env
# BACKWARD COMPATIBILITY
OLD_DOCKER_ENV_PATH=$PLANE_INSTALL_DIR/.env
if [ -f "$OLD_DOCKER_ENV_PATH" ];
then
mv "$OLD_DOCKER_ENV_PATH" "$DOCKER_ENV_PATH"
OS_NAME=$(uname)
if [ "$OS_NAME" == "Darwin" ];
then
sed -i '' -e 's@APP_RELEASE=latest@APP_RELEASE=stable@' "$DOCKER_ENV_PATH"
else
sed -i -e 's@APP_RELEASE=latest@APP_RELEASE=stable@' "$DOCKER_ENV_PATH"
fi
fi
print_header print_header
askForAction $@ askForAction $@

View File

@ -1,4 +1,4 @@
APP_RELEASE=latest APP_RELEASE=stable
WEB_REPLICAS=1 WEB_REPLICAS=1
SPACE_REPLICAS=1 SPACE_REPLICAS=1
@ -41,4 +41,4 @@ BUCKET_NAME=uploads
FILE_SIZE_LIMIT=5242880 FILE_SIZE_LIMIT=5242880
# Gunicorn Workers # Gunicorn Workers
GUNICORN_WORKERS=2 GUNICORN_WORKERS=1

View File

@ -39,7 +39,7 @@ http {
} }
location /${BUCKET_NAME}/ { location /${BUCKET_NAME}/ {
proxy_pass http://plane-minio:9000/uploads/; proxy_pass http://plane-minio:9000/${BUCKET_NAME}/;
} }
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"repository": "https://github.com/makeplane/plane.git", "repository": "https://github.com/makeplane/plane.git",
"version": "0.16.0", "version": "0.17.0",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"private": true, "private": true,
"workspaces": [ "workspaces": [

View File

@ -1,6 +1,6 @@
{ {
"name": "@plane/editor-core", "name": "@plane/editor-core",
"version": "0.16.0", "version": "0.17.0",
"description": "Core Editor that powers Plane", "description": "Core Editor that powers Plane",
"private": true, "private": true,
"main": "./dist/index.mjs", "main": "./dist/index.mjs",

View File

@ -1,5 +1,6 @@
import { Editor } from "@tiptap/react"; import { Editor } from "@tiptap/react";
import { FC, ReactNode } from "react"; import { FC, ReactNode } from "react";
import { cn } from "src/lib/utils";
interface EditorContainerProps { interface EditorContainerProps {
editor: Editor | null; editor: Editor | null;
@ -53,7 +54,7 @@ export const EditorContainer: FC<EditorContainerProps> = (props) => {
onMouseLeave={() => { onMouseLeave={() => {
hideDragHandle?.(); hideDragHandle?.();
}} }}
className={`cursor-text ${editorClassNames}`} className={cn(`cursor-text`, { "active-editor": editor?.isFocused && editor?.isEditable }, editorClassNames)}
> >
{children} {children}
</div> </div>

View File

@ -22,7 +22,7 @@ export const Suggestion = (suggestions: IMentionSuggestion[]) => ({
// @ts-ignore // @ts-ignore
popup = tippy("body", { popup = tippy("body", {
getReferenceClientRect: props.clientRect, getReferenceClientRect: props.clientRect,
appendTo: () => document.querySelector("#editor-container"), appendTo: () => document.querySelector(".active-editor") ?? document.querySelector("#editor-container"),
content: reactRenderer.element, content: reactRenderer.element,
showOnCreate: true, showOnCreate: true,
interactive: true, interactive: true,

View File

@ -1,6 +1,6 @@
{ {
"name": "@plane/document-editor", "name": "@plane/document-editor",
"version": "0.16.0", "version": "0.17.0",
"description": "Package that powers Plane's Pages Editor", "description": "Package that powers Plane's Pages Editor",
"main": "./dist/index.mjs", "main": "./dist/index.mjs",
"module": "./dist/index.mjs", "module": "./dist/index.mjs",

View File

@ -1,6 +1,6 @@
{ {
"name": "@plane/editor-extensions", "name": "@plane/editor-extensions",
"version": "0.16.0", "version": "0.17.0",
"description": "Package that powers Plane's Editor with extensions", "description": "Package that powers Plane's Editor with extensions",
"private": true, "private": true,
"main": "./dist/index.mjs", "main": "./dist/index.mjs",

View File

@ -330,7 +330,7 @@ const renderItems = () => {
// @ts-ignore // @ts-ignore
popup = tippy("body", { popup = tippy("body", {
getReferenceClientRect: props.clientRect, getReferenceClientRect: props.clientRect,
appendTo: () => document.querySelector("#editor-container"), appendTo: () => document.querySelector(".active-editor") ?? document.querySelector("#editor-container"),
content: component.element, content: component.element,
showOnCreate: true, showOnCreate: true,
interactive: true, interactive: true,

View File

@ -1,6 +1,6 @@
{ {
"name": "@plane/lite-text-editor", "name": "@plane/lite-text-editor",
"version": "0.16.0", "version": "0.17.0",
"description": "Package that powers Plane's Comment Editor", "description": "Package that powers Plane's Comment Editor",
"private": true, "private": true,
"main": "./dist/index.mjs", "main": "./dist/index.mjs",

View File

@ -1,6 +1,6 @@
{ {
"name": "@plane/rich-text-editor", "name": "@plane/rich-text-editor",
"version": "0.16.0", "version": "0.17.0",
"description": "Rich Text Editor that powers Plane", "description": "Rich Text Editor that powers Plane",
"private": true, "private": true,
"main": "./dist/index.mjs", "main": "./dist/index.mjs",

View File

@ -1,7 +1,7 @@
{ {
"name": "eslint-config-custom", "name": "eslint-config-custom",
"private": true, "private": true,
"version": "0.16.0", "version": "0.17.0",
"main": "index.js", "main": "index.js",
"license": "MIT", "license": "MIT",
"devDependencies": {}, "devDependencies": {},

View File

@ -1,6 +1,6 @@
{ {
"name": "tailwind-config-custom", "name": "tailwind-config-custom",
"version": "0.16.0", "version": "0.17.0",
"description": "common tailwind configuration across monorepo", "description": "common tailwind configuration across monorepo",
"main": "index.js", "main": "index.js",
"private": true, "private": true,

View File

@ -1,6 +1,6 @@
{ {
"name": "tsconfig", "name": "tsconfig",
"version": "0.16.0", "version": "0.17.0",
"private": true, "private": true,
"files": [ "files": [
"base.json", "base.json",

View File

@ -1,6 +1,6 @@
{ {
"name": "@plane/types", "name": "@plane/types",
"version": "0.16.0", "version": "0.17.0",
"private": true, "private": true,
"main": "./src/index.d.ts" "main": "./src/index.d.ts"
} }

View File

@ -2,7 +2,7 @@
"name": "@plane/ui", "name": "@plane/ui",
"description": "UI components shared across multiple apps internally", "description": "UI components shared across multiple apps internally",
"private": true, "private": true,
"version": "0.16.0", "version": "0.17.0",
"main": "./dist/index.js", "main": "./dist/index.js",
"module": "./dist/index.mjs", "module": "./dist/index.mjs",
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",

View File

@ -91,7 +91,7 @@ const CustomSelect = (props: ICustomSelectProps) => {
)} )}
</> </>
{isOpen && ( {isOpen && (
<Listbox.Options className="fixed z-10" onClick={() => closeDropdown()} static> <Listbox.Options className="fixed z-20" onClick={() => closeDropdown()} static>
<div <div
className={cn( className={cn(
"my-1 overflow-y-scroll rounded-md border-[0.5px] border-custom-border-300 bg-custom-background-100 px-2 py-2.5 text-xs shadow-custom-shadow-rg focus:outline-none min-w-[12rem] whitespace-nowrap", "my-1 overflow-y-scroll rounded-md border-[0.5px] border-custom-border-300 bg-custom-background-100 px-2 py-2.5 text-xs shadow-custom-shadow-rg focus:outline-none min-w-[12rem] whitespace-nowrap",

View File

@ -1,6 +1,6 @@
{ {
"name": "space", "name": "space",
"version": "0.16.0", "version": "0.17.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "turbo run develop", "dev": "turbo run develop",

View File

@ -1,9 +1,7 @@
// icons
import { Triangle } from "lucide-react";
import { IDefaultAnalyticsResponse, TStateGroups } from "@plane/types";
// types // types
import { STATE_GROUPS } from "@/constants/state"; import { IDefaultAnalyticsResponse, TStateGroups } from "@plane/types";
// constants // constants
import { STATE_GROUPS } from "@/constants/state";
type Props = { type Props = {
defaultAnalytics: IDefaultAnalyticsResponse; defaultAnalytics: IDefaultAnalyticsResponse;
@ -16,7 +14,7 @@ export const AnalyticsDemand: React.FC<Props> = ({ defaultAnalytics }) => (
<h4 className="text-base font-medium text-custom-text-100">Total open tasks</h4> <h4 className="text-base font-medium text-custom-text-100">Total open tasks</h4>
<h3 className="mt-1 text-xl font-semibold">{defaultAnalytics.open_issues}</h3> <h3 className="mt-1 text-xl font-semibold">{defaultAnalytics.open_issues}</h3>
</div> </div>
<div className="space-y-6"> <div className="space-y-6 pb-2">
{defaultAnalytics?.open_issues_classified.map((group) => { {defaultAnalytics?.open_issues_classified.map((group) => {
const percentage = ((group.state_count / defaultAnalytics.total_issues) * 100).toFixed(0); const percentage = ((group.state_count / defaultAnalytics.total_issues) * 100).toFixed(0);
@ -50,14 +48,5 @@ export const AnalyticsDemand: React.FC<Props> = ({ defaultAnalytics }) => (
); );
})} })}
</div> </div>
<div className="!mt-6 flex w-min items-center gap-2 whitespace-nowrap rounded-md border border-custom-border-200 bg-custom-background-80 p-2 text-xs">
<p className="flex items-center gap-1 text-custom-text-200">
<Triangle className="h-4 w-4" />
<span>Estimate Demand:</span>
</p>
<p className="font-medium">
{defaultAnalytics.open_estimate_sum}/{defaultAnalytics.total_estimate_sum}
</p>
</div>
</div> </div>
); );

View File

@ -69,7 +69,9 @@ export const CommandPaletteHelpActions: React.FC<Props> = (props) => {
<Command.Item <Command.Item
onSelect={() => { onSelect={() => {
closePalette(); closePalette();
(window as any)?.$crisp.push(["do", "chat:open"]); if (window) {
window.$crisp.push(["do", "chat:show"]);
}
}} }}
className="focus:outline-none" className="focus:outline-none"
> >

View File

@ -40,7 +40,7 @@ const issueService = new IssueService();
export const CommandModal: React.FC = observer(() => { export const CommandModal: React.FC = observer(() => {
// hooks // hooks
const { getProjectById } = useProject(); const { getProjectById, workspaceProjectIds } = useProject();
const { isMobile } = usePlatformOS(); const { isMobile } = usePlatformOS();
// states // states
const [placeholder, setPlaceholder] = useState("Type a command or search..."); const [placeholder, setPlaceholder] = useState("Type a command or search...");
@ -282,22 +282,24 @@ export const CommandModal: React.FC = observer(() => {
setSearchTerm={(newSearchTerm) => setSearchTerm(newSearchTerm)} setSearchTerm={(newSearchTerm) => setSearchTerm(newSearchTerm)}
/> />
)} )}
<Command.Group heading="Issue"> {workspaceSlug && workspaceProjectIds && workspaceProjectIds.length > 0 && (
<Command.Item <Command.Group heading="Issue">
onSelect={() => { <Command.Item
closePalette(); onSelect={() => {
setTrackElement("Command Palette"); closePalette();
toggleCreateIssueModal(true); setTrackElement("Command Palette");
}} toggleCreateIssueModal(true);
className="focus:bg-custom-background-80" }}
> className="focus:bg-custom-background-80"
<div className="flex items-center gap-2 text-custom-text-200"> >
<LayersIcon className="h-3.5 w-3.5" /> <div className="flex items-center gap-2 text-custom-text-200">
Create new issue <LayersIcon className="h-3.5 w-3.5" />
</div> Create new issue
<kbd>C</kbd> </div>
</Command.Item> <kbd>C</kbd>
</Command.Group> </Command.Item>
</Command.Group>
)}
{workspaceSlug && ( {workspaceSlug && (
<Command.Group heading="Project"> <Command.Group heading="Project">

View File

@ -36,18 +36,18 @@ export const ShortcutsModal: FC<Props> = (props) => {
<div className="fixed inset-0 bg-custom-backdrop transition-opacity" /> <div className="fixed inset-0 bg-custom-backdrop transition-opacity" />
</Transition.Child> </Transition.Child>
<div className="fixed inset-0 z-20 h-full w-full overflow-y-auto"> <div className="fixed inset-0 z-20 overflow-y-auto">
<Transition.Child <div className="my-10 flex items-center justify-center p-4 text-center sm:p-0 md:my-20">
as={Fragment} <Transition.Child
enter="ease-out duration-300" as={Fragment}
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" enter="ease-out duration-300"
enterTo="opacity-100 translate-y-0 sm:scale-100" enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
leave="ease-in duration-200" enterTo="opacity-100 translate-y-0 sm:scale-100"
leaveFrom="opacity-100 translate-y-0 sm:scale-100" leave="ease-in duration-200"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" leaveFrom="opacity-100 translate-y-0 sm:scale-100"
> leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
<Dialog.Panel className="h-full w-full"> >
<div className="my-10 flex items-center justify-center p-4 text-center sm:p-0 md:my-20"> <Dialog.Panel className="relative flex h-full items-center justify-center">
<div className="flex h-[61vh] w-full flex-col space-y-4 overflow-hidden rounded-lg bg-custom-background-100 p-5 shadow-custom-shadow-md transition-all sm:w-[28rem]"> <div className="flex h-[61vh] w-full flex-col space-y-4 overflow-hidden rounded-lg bg-custom-background-100 p-5 shadow-custom-shadow-md transition-all sm:w-[28rem]">
<Dialog.Title as="h3" className="flex justify-between"> <Dialog.Title as="h3" className="flex justify-between">
<span className="text-lg font-medium">Keyboard shortcuts</span> <span className="text-lg font-medium">Keyboard shortcuts</span>
@ -71,9 +71,9 @@ export const ShortcutsModal: FC<Props> = (props) => {
</div> </div>
<ShortcutCommandsList searchQuery={query} /> <ShortcutCommandsList searchQuery={query} />
</div> </div>
</div> </Dialog.Panel>
</Dialog.Panel> </Transition.Child>
</Transition.Child> </div>
</div> </div>
</Dialog> </Dialog>
</Transition.Root> </Transition.Root>

View File

@ -1,6 +1,6 @@
import Image from "next/image"; import Image from "next/image";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
import { LayoutGrid, Zap } from "lucide-react"; import { Home, Zap } from "lucide-react";
// images // images
import githubBlackImage from "/public/logos/github-black.png"; import githubBlackImage from "/public/logos/github-black.png";
import githubWhiteImage from "/public/logos/github-white.png"; import githubWhiteImage from "/public/logos/github-white.png";
@ -25,9 +25,7 @@ export const WorkspaceDashboardHeader = () => {
<Breadcrumbs> <Breadcrumbs>
<Breadcrumbs.BreadcrumbItem <Breadcrumbs.BreadcrumbItem
type="text" type="text"
link={ link={<BreadcrumbLink label="Home" icon={<Home className="h-4 w-4 text-custom-text-300" />} />}
<BreadcrumbLink label="Dashboard" icon={<LayoutGrid className="h-4 w-4 text-custom-text-300" />} />
}
/> />
</Breadcrumbs> </Breadcrumbs>
</div> </div>

View File

@ -1,20 +1,21 @@
import { useState } from "react"; import { useState } from "react";
import omit from "lodash/omit"; import omit from "lodash/omit";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
// hooks // icons
import { Copy, Pencil, Trash2 } from "lucide-react"; import { Pencil, Trash2 } from "lucide-react";
// types
import { TIssue } from "@plane/types"; import { TIssue } from "@plane/types";
// ui
import { CustomMenu } from "@plane/ui"; import { CustomMenu } from "@plane/ui";
// components
import { CreateUpdateIssueModal, DeleteIssueModal } from "@/components/issues"; import { CreateUpdateIssueModal, DeleteIssueModal } from "@/components/issues";
// constant
import { EIssuesStoreType } from "@/constants/issue"; import { EIssuesStoreType } from "@/constants/issue";
import { EUserProjectRoles } from "@/constants/project"; import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useEventTracker, useIssues, useUser } from "@/hooks/store"; import { useEventTracker, useIssues, useUser } from "@/hooks/store";
// ui
// components
// helpers
// types // types
import { IQuickActionProps } from "../list/list-view-types"; import { IQuickActionProps } from "../list/list-view-types";
// constant
export const DraftIssueQuickActions: React.FC<IQuickActionProps> = observer((props) => { export const DraftIssueQuickActions: React.FC<IQuickActionProps> = observer((props) => {
const { issue, handleDelete, handleUpdate, customActionButton, portalElement, readOnly = false } = props; const { issue, handleDelete, handleUpdate, customActionButton, portalElement, readOnly = false } = props;
@ -89,19 +90,6 @@ export const DraftIssueQuickActions: React.FC<IQuickActionProps> = observer((pro
</div> </div>
</CustomMenu.MenuItem> </CustomMenu.MenuItem>
)} )}
{isEditingAllowed && (
<CustomMenu.MenuItem
onClick={() => {
setTrackElement(activeLayout);
setCreateUpdateIssueModal(true);
}}
>
<div className="flex items-center gap-2">
<Copy className="h-3 w-3" />
Make a copy
</div>
</CustomMenu.MenuItem>
)}
{isDeletingAllowed && ( {isDeletingAllowed && (
<CustomMenu.MenuItem <CustomMenu.MenuItem
onClick={() => { onClick={() => {

View File

@ -84,7 +84,7 @@ export const DraftIssueLayout: React.FC<DraftIssueProps> = observer((props) => {
const payload = { const payload = {
...changesMade, ...changesMade,
name: changesMade?.name && changesMade?.name?.trim() === "" ? changesMade.name?.trim() : "Untitled", name: changesMade?.name && changesMade?.name?.trim() !== "" ? changesMade.name?.trim() : "Untitled",
}; };
await issueDraftService await issueDraftService

View File

@ -26,6 +26,7 @@ import { renderFormattedPayloadDate, getDate } from "@/helpers/date-time.helper"
import { getChangedIssuefields } from "@/helpers/issue.helper"; import { getChangedIssuefields } from "@/helpers/issue.helper";
import { shouldRenderProject } from "@/helpers/project.helper"; import { shouldRenderProject } from "@/helpers/project.helper";
import { useApplication, useEstimate, useIssueDetail, useMention, useProject, useWorkspace } from "@/hooks/store"; import { useApplication, useEstimate, useIssueDetail, useMention, useProject, useWorkspace } from "@/hooks/store";
import { useProjectIssueProperties } from "@/hooks/use-project-issue-properties";
// services // services
import { AIService } from "@/services/ai.service"; import { AIService } from "@/services/ai.service";
import { FileService } from "@/services/file.service"; import { FileService } from "@/services/file.service";
@ -121,6 +122,7 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
// store hooks // store hooks
const { const {
config: { envConfig }, config: { envConfig },
router: { projectId: routeProjectId },
} = useApplication(); } = useApplication();
const { getProjectById } = useProject(); const { getProjectById } = useProject();
const { areEstimatesEnabledForProject } = useEstimate(); const { areEstimatesEnabledForProject } = useEstimate();
@ -128,6 +130,7 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
const { const {
issue: { getIssueById }, issue: { getIssueById },
} = useIssueDetail(); } = useIssueDetail();
const { fetchCycles } = useProjectIssueProperties();
// form info // form info
const { const {
formState: { errors, isDirty, isSubmitting, dirtyFields }, formState: { errors, isDirty, isSubmitting, dirtyFields },
@ -160,6 +163,7 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
parent_id: formData.parent_id, parent_id: formData.parent_id,
}); });
} }
if (projectId && routeProjectId !== projectId) fetchCycles(workspaceSlug, projectId);
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [projectId]); }, [projectId]);

View File

@ -10,11 +10,11 @@ import {
ContrastIcon, ContrastIcon,
FileText, FileText,
LayersIcon, LayersIcon,
LayoutGrid,
PenSquare, PenSquare,
Search, Search,
Settings, Settings,
Bell, Bell,
Home,
} from "lucide-react"; } from "lucide-react";
import { IWorkspace } from "@plane/types"; import { IWorkspace } from "@plane/types";
import { Avatar, DiceIcon, PhotoFilterIcon } from "@plane/ui"; import { Avatar, DiceIcon, PhotoFilterIcon } from "@plane/ui";
@ -26,8 +26,8 @@ import projectEmoji from "public/emoji/project-emoji.svg";
const workspaceLinks = [ const workspaceLinks = [
{ {
Icon: LayoutGrid, Icon: Home,
name: "Dashboard", name: "Home",
}, },
{ {
Icon: BarChart2, Icon: BarChart2,

View File

@ -226,7 +226,7 @@ export const CreateProjectForm: FC<Props> = observer((props) => {
control={control} control={control}
name="name" name="name"
rules={{ rules={{
required: "Title is required", required: "Name is required",
maxLength: { maxLength: {
value: 255, value: 255,
message: "Title should be less than 255 characters", message: "Title should be less than 255 characters",
@ -240,7 +240,7 @@ export const CreateProjectForm: FC<Props> = observer((props) => {
value={value} value={value}
onChange={handleNameChange(onChange)} onChange={handleNameChange(onChange)}
hasError={Boolean(errors.name)} hasError={Boolean(errors.name)}
placeholder="Project title" placeholder="Project name"
className="w-full focus:border-blue-400" className="w-full focus:border-blue-400"
tabIndex={1} tabIndex={1}
/> />

View File

@ -1,7 +1,7 @@
import { FC, useEffect, useState } from "react"; import { FC, useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
// icons // icons
import { Lock } from "lucide-react"; import { Info, Lock } from "lucide-react";
import { IProject, IWorkspace } from "@plane/types"; import { IProject, IWorkspace } from "@plane/types";
// ui // ui
import { import {
@ -13,6 +13,7 @@ import {
setToast, setToast,
CustomEmojiIconPicker, CustomEmojiIconPicker,
EmojiIconPickerTypes, EmojiIconPickerTypes,
Tooltip,
} from "@plane/ui"; } from "@plane/ui";
// components // components
import { ImagePickerPopover } from "@/components/core"; import { ImagePickerPopover } from "@/components/core";
@ -24,6 +25,7 @@ import { renderFormattedDate } from "@/helpers/date-time.helper";
// hooks // hooks
import { convertHexEmojiToDecimal } from "@/helpers/emoji.helper"; import { convertHexEmojiToDecimal } from "@/helpers/emoji.helper";
import { useEventTracker, useProject } from "@/hooks/store"; import { useEventTracker, useProject } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
// services // services
import { ProjectService } from "@/services/project"; import { ProjectService } from "@/services/project";
// types // types
@ -42,6 +44,7 @@ export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
// store hooks // store hooks
const { captureProjectEvent } = useEventTracker(); const { captureProjectEvent } = useEventTracker();
const { updateProject } = useProject(); const { updateProject } = useProject();
const { isMobile } = usePlatformOS();
// form info // form info
const { const {
handleSubmit, handleSubmit,
@ -229,6 +232,9 @@ export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
/> />
)} )}
/> />
<span className="text-xs text-red-500">
<>{errors?.name?.message}</>
</span>
</div> </div>
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<h4 className="text-sm">Description</h4> <h4 className="text-sm">Description</h4>
@ -249,39 +255,54 @@ export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
)} )}
/> />
</div> </div>
<div className="flex w-full items-center justify-between gap-10"> <div className="flex w-full justify-between gap-10">
<div className="flex w-1/2 flex-col gap-1"> <div className="flex w-1/2 flex-col gap-1">
<h4 className="text-sm">Identifier</h4> <h4 className="text-sm">Project ID</h4>
<Controller <div className="relative">
control={control} <Controller
name="identifier" control={control}
rules={{ name="identifier"
required: "Identifier is required", rules={{
validate: (value) => /^[A-Z0-9]+$/.test(value.toUpperCase()) || "Identifier must be in uppercase.", required: "Project ID is required",
minLength: { validate: (value) =>
value: 1, /^[ÇŞĞIİÖÜA-Z0-9]+$/.test(value.toUpperCase()) ||
message: "Identifier must at least be of 1 character", "Only Alphanumeric & Non-latin characters are allowed.",
}, minLength: {
maxLength: { value: 1,
value: 12, message: "Project ID must at least be of 1 character",
message: "Identifier must at most be of 5 characters", },
}, maxLength: {
}} value: 5,
render={({ field: { value, ref } }) => ( message: "Project ID must at most be of 5 characters",
<Input },
id="identifier" }}
name="identifier" render={({ field: { value, ref } }) => (
type="text" <Input
value={value} id="identifier"
onChange={handleIdentifierChange} name="identifier"
ref={ref} type="text"
hasError={Boolean(errors.identifier)} value={value}
placeholder="Enter identifier" onChange={handleIdentifierChange}
className="w-full font-medium" ref={ref}
disabled={!isAdmin} hasError={Boolean(errors.identifier)}
/> placeholder="Enter Project ID"
)} className="w-full font-medium"
/> disabled={!isAdmin}
/>
)}
/>
<Tooltip
isMobile={isMobile}
tooltipContent="Helps you identify issues in the project uniquely, (e.g. APP-123). Max 5 characters."
className="text-sm"
position="right-top"
>
<Info className="absolute right-2 top-2.5 h-4 w-4 text-custom-text-400" />
</Tooltip>
</div>
<span className="text-xs text-red-500">
<>{errors?.identifier?.message}</>
</span>
</div> </div>
<div className="flex w-1/2 flex-col gap-1"> <div className="flex w-1/2 flex-col gap-1">
<h4 className="text-sm">Network</h4> <h4 className="text-sm">Network</h4>

View File

@ -0,0 +1,89 @@
import { useCycle, useEstimate, useLabel, useMember, useModule, useProjectState } from "./store";
export const useProjectIssueProperties = () => {
const { fetchProjectStates } = useProjectState();
const {
project: { fetchProjectMembers },
} = useMember();
const { fetchProjectLabels } = useLabel();
const { fetchAllCycles: fetchProjectAllCycles } = useCycle();
const { fetchModules: fetchProjectAllModules } = useModule();
const { fetchProjectEstimates } = useEstimate();
// fetching project states
const fetchStates = async (
workspaceSlug: string | string[] | undefined,
projectId: string | string[] | undefined
) => {
if (workspaceSlug && projectId) {
await fetchProjectStates(workspaceSlug.toString(), projectId.toString());
}
};
// fetching project members
const fetchMembers = async (
workspaceSlug: string | string[] | undefined,
projectId: string | string[] | undefined
) => {
if (workspaceSlug && projectId) {
await fetchProjectMembers(workspaceSlug.toString(), projectId.toString());
}
};
// fetching project labels
const fetchLabels = async (
workspaceSlug: string | string[] | undefined,
projectId: string | string[] | undefined
) => {
if (workspaceSlug && projectId) {
await fetchProjectLabels(workspaceSlug.toString(), projectId.toString());
}
};
// fetching project cycles
const fetchCycles = async (
workspaceSlug: string | string[] | undefined,
projectId: string | string[] | undefined
) => {
if (workspaceSlug && projectId) {
await fetchProjectAllCycles(workspaceSlug.toString(), projectId.toString());
}
};
// fetching project modules
const fetchModules = async (
workspaceSlug: string | string[] | undefined,
projectId: string | string[] | undefined
) => {
if (workspaceSlug && projectId) {
await fetchProjectAllModules(workspaceSlug.toString(), projectId.toString());
}
};
// fetching project estimates
const fetchEstimates = async (
workspaceSlug: string | string[] | undefined,
projectId: string | string[] | undefined
) => {
if (workspaceSlug && projectId) {
await fetchProjectEstimates(workspaceSlug.toString(), projectId.toString());
}
};
const fetchAll = async (workspaceSlug: string | string[] | undefined, projectId: string | string[] | undefined) => {
if (workspaceSlug && projectId) {
await fetchStates(workspaceSlug, projectId);
await fetchMembers(workspaceSlug, projectId);
await fetchLabels(workspaceSlug, projectId);
await fetchCycles(workspaceSlug, projectId);
await fetchModules(workspaceSlug, projectId);
await fetchEstimates(workspaceSlug, projectId);
}
};
return {
fetchAll,
fetchStates,
fetchMembers,
fetchLabels,
fetchCycles,
fetchModules,
fetchEstimates,
};
};

View File

@ -1,6 +1,6 @@
{ {
"name": "web", "name": "web",
"version": "0.16.0", "version": "0.17.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "turbo run develop", "dev": "turbo run develop",

View File

@ -14,7 +14,7 @@ import { NextPageWithLayout } from "@/lib/types";
const WorkspacePage: NextPageWithLayout = observer(() => { const WorkspacePage: NextPageWithLayout = observer(() => {
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
// derived values // derived values
const pageTitle = currentWorkspace?.name ? `${currentWorkspace?.name} - Dashboard` : undefined; const pageTitle = currentWorkspace?.name ? `${currentWorkspace?.name} - Home` : undefined;
return ( return (
<> <>

View File

@ -220,7 +220,7 @@ const UserInvitationsPage: NextPageWithLayout = observer(() => {
description="You can see here if someone invites you to a workspace." description="You can see here if someone invites you to a workspace."
image={emptyInvitation} image={emptyInvitation}
primaryButton={{ primaryButton={{
text: "Back to dashboard", text: "Back to home",
onClick: () => router.push("/"), onClick: () => router.push("/"),
}} }}
/> />

View File

@ -81,7 +81,7 @@ const WorkspaceInvitationPage: NextPageWithLayout = observer(() => {
title={`You are already a member of ${invitationDetail.workspace.name}`} title={`You are already a member of ${invitationDetail.workspace.name}`}
description="Your workspace is where you'll create projects, collaborate on your issues, and organize different streams of work in your Plane account." description="Your workspace is where you'll create projects, collaborate on your issues, and organize different streams of work in your Plane account."
> >
<EmptySpaceItem Icon={Boxes} title="Continue to Dashboard" href="/" /> <EmptySpaceItem Icon={Boxes} title="Continue to home" href="/" />
</EmptySpace> </EmptySpace>
</> </>
) : ( ) : (
@ -105,7 +105,7 @@ const WorkspaceInvitationPage: NextPageWithLayout = observer(() => {
{!currentUser ? ( {!currentUser ? (
<EmptySpaceItem Icon={User2} title="Sign in to continue" href="/" /> <EmptySpaceItem Icon={User2} title="Sign in to continue" href="/" />
) : ( ) : (
<EmptySpaceItem Icon={Boxes} title="Continue to Dashboard" href="/" /> <EmptySpaceItem Icon={Boxes} title="Continue to home" href="/" />
)} )}
<EmptySpaceItem Icon={Star} title="Star us on GitHub" href="https://github.com/makeplane" /> <EmptySpaceItem Icon={Star} title="Star us on GitHub" href="https://github.com/makeplane" />
<EmptySpaceItem <EmptySpaceItem

View File

@ -2733,7 +2733,7 @@
dependencies: dependencies:
"@types/react" "*" "@types/react" "*"
"@types/react@*", "@types/react@^18.2.42": "@types/react@*", "@types/react@18.2.42", "@types/react@^18.2.42":
version "18.2.42" version "18.2.42"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.42.tgz#6f6b11a904f6d96dda3c2920328a97011a00aba7" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.42.tgz#6f6b11a904f6d96dda3c2920328a97011a00aba7"
integrity sha512-c1zEr96MjakLYus/wPnuWDo1/zErfdU9rNsIGmE+NV71nx88FG9Ttgo5dqorXTu/LImX2f63WBP986gJkMPNbA== integrity sha512-c1zEr96MjakLYus/wPnuWDo1/zErfdU9rNsIGmE+NV71nx88FG9Ttgo5dqorXTu/LImX2f63WBP986gJkMPNbA==