diff --git a/.github/workflows/build-branch.yml b/.github/workflows/build-branch.yml
index 306f92957..1f14f15aa 100644
--- a/.github/workflows/build-branch.yml
+++ b/.github/workflows/build-branch.yml
@@ -23,6 +23,7 @@ jobs:
gh_buildx_platforms: ${{ steps.set_env_variables.outputs.BUILDX_PLATFORMS }}
gh_buildx_endpoint: ${{ steps.set_env_variables.outputs.BUILDX_ENDPOINT }}
build_frontend: ${{ steps.changed_files.outputs.frontend_any_changed }}
+ build_admin: ${{ steps.changed_files.outputs.admin_any_changed }}
build_space: ${{ steps.changed_files.outputs.space_any_changed }}
build_backend: ${{ steps.changed_files.outputs.backend_any_changed }}
build_proxy: ${{ steps.changed_files.outputs.proxy_any_changed }}
@@ -67,6 +68,13 @@ jobs:
- 'yarn.lock'
- 'tsconfig.json'
- 'turbo.json'
+ admin:
+ - admin/**
+ - packages/**
+ - 'package.json'
+ - 'yarn.lock'
+ - 'tsconfig.json'
+ - 'turbo.json'
backend:
- apiserver/**
proxy:
@@ -124,6 +132,58 @@ jobs:
DOCKER_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }}
+ branch_build_push_admin:
+ if: ${{ needs.branch_build_setup.outputs.build_admin== 'true' || github.event_name == 'workflow_dispatch' || github.event_name == 'release' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }}
+ runs-on: ubuntu-20.04
+ needs: [branch_build_setup]
+ env:
+ ADMIN_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/plane-admin:${{ needs.branch_build_setup.outputs.gh_branch_name }}
+ TARGET_BRANCH: ${{ needs.branch_build_setup.outputs.gh_branch_name }}
+ BUILDX_DRIVER: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }}
+ BUILDX_VERSION: ${{ needs.branch_build_setup.outputs.gh_buildx_version }}
+ BUILDX_PLATFORMS: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }}
+ BUILDX_ENDPOINT: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }}
+ steps:
+ - name: Set Admin Docker Tag
+ run: |
+ if [ "${{ github.event_name }}" == "release" ]; then
+ TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-admin:stable,${{ secrets.DOCKERHUB_USERNAME }}/plane-admin:${{ github.event.release.tag_name }}
+ elif [ "${{ env.TARGET_BRANCH }}" == "master" ]; then
+ TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-admin:latest
+ else
+ TAG=${{ env.ADMIN_TAG }}
+ fi
+ echo "ADMIN_TAG=${TAG}" >> $GITHUB_ENV
+
+ - name: Login to Docker Hub
+ uses: docker/login-action@v3
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+ with:
+ driver: ${{ env.BUILDX_DRIVER }}
+ version: ${{ env.BUILDX_VERSION }}
+ endpoint: ${{ env.BUILDX_ENDPOINT }}
+
+ - name: Check out the repo
+ uses: actions/checkout@v4
+
+ - name: Build and Push Frontend to Docker Container Registry
+ uses: docker/build-push-action@v5.1.0
+ with:
+ context: .
+ file: ./admin/Dockerfile.admin
+ platforms: ${{ env.BUILDX_PLATFORMS }}
+ tags: ${{ env.ADMIN_TAG }}
+ push: true
+ env:
+ DOCKER_BUILDKIT: 1
+ DOCKER_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
+ DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }}
+
branch_build_push_space:
if: ${{ needs.branch_build_setup.outputs.build_space == 'true' || github.event_name == 'workflow_dispatch' || github.event_name == 'release' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }}
runs-on: ubuntu-20.04
diff --git a/.github/workflows/feature-deployment.yml b/.github/workflows/feature-deployment.yml
index c5eec3cd3..a0a9dc7f1 100644
--- a/.github/workflows/feature-deployment.yml
+++ b/.github/workflows/feature-deployment.yml
@@ -13,10 +13,16 @@ on:
description: 'Build Space'
type: boolean
default: false
+ admin-build:
+ required: false
+ description: 'Build Admin'
+ type: boolean
+ default: false
env:
BUILD_WEB: ${{ github.event.inputs.web-build }}
BUILD_SPACE: ${{ github.event.inputs.space-build }}
+ BUILD_ADMIN: ${{ github.event.inputs.admin-build }}
jobs:
setup-feature-build:
@@ -27,9 +33,11 @@ jobs:
run: |
echo "BUILD_WEB=$BUILD_WEB"
echo "BUILD_SPACE=$BUILD_SPACE"
+ echo "BUILD_ADMIN=$BUILD_ADMIN"
outputs:
web-build: ${{ env.BUILD_WEB}}
space-build: ${{env.BUILD_SPACE}}
+ admin-build: ${{env.BUILD_ADMIN}}
feature-build-web:
if: ${{ needs.setup-feature-build.outputs.web-build == 'true' }}
@@ -117,9 +125,54 @@ jobs:
FILE_EXPIRY=$(date -u -d "+2 days" +"%Y-%m-%dT%H:%M:%SZ")
aws s3 cp $TAR_NAME s3://${{ env.AWS_BUCKET }}/${{github.sha}}/$TAR_NAME --expires $FILE_EXPIRY
+ feature-build-admin:
+ if: ${{ needs.setup-feature-build.outputs.admin-build == 'true' }}
+ needs: setup-feature-build
+ name: Feature Build Admin
+ runs-on: ubuntu-latest
+ env:
+ AWS_ACCESS_KEY_ID: ${{ vars.FEATURE_PREVIEW_AWS_ACCESS_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.FEATURE_PREVIEW_AWS_SECRET_ACCESS_KEY }}
+ AWS_BUCKET: ${{ vars.FEATURE_PREVIEW_AWS_BUCKET }}
+ NEXT_PUBLIC_DEPLOY_WITH_NGINX: 1
+ NEXT_PUBLIC_API_BASE_URL: ${{ vars.FEATURE_PREVIEW_NEXT_PUBLIC_API_BASE_URL }}
+ outputs:
+ do-build: ${{ needs.setup-feature-build.outputs.admin-build }}
+ s3-url: ${{ steps.build-admin.outputs.S3_PRESIGNED_URL }}
+ steps:
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '18'
+ - name: Install AWS cli
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y python3-pip
+ pip3 install awscli
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ path: plane
+ - name: Install Dependencies
+ run: |
+ cd $GITHUB_WORKSPACE/plane
+ yarn install
+ - name: Build Admin
+ id: build-admin
+ run: |
+ cd $GITHUB_WORKSPACE/plane
+ yarn build --filter=admin
+ cd $GITHUB_WORKSPACE
+
+ TAR_NAME="admin.tar.gz"
+ tar -czf $TAR_NAME ./plane
+
+ FILE_EXPIRY=$(date -u -d "+2 days" +"%Y-%m-%dT%H:%M:%SZ")
+ aws s3 cp $TAR_NAME s3://${{ env.AWS_BUCKET }}/${{github.sha}}/$TAR_NAME --expires $FILE_EXPIRY
+
feature-deploy:
- if: ${{ always() && (needs.setup-feature-build.outputs.web-build == 'true' || needs.setup-feature-build.outputs.space-build == 'true') }}
- needs: [feature-build-web, feature-build-space]
+ if: ${{ always() && (needs.setup-feature-build.outputs.web-build == 'true' || needs.setup-feature-build.outputs.space-build == 'true' || needs.setup-feature-build.outputs.admin-build == 'true') }}
+ needs: [setup-feature-build, feature-build-web, feature-build-space, feature-build-admin]
name: Feature Deploy
runs-on: ubuntu-latest
env:
@@ -164,7 +217,12 @@ jobs:
SPACE_S3_URL=$(aws s3 presign s3://${{ vars.FEATURE_PREVIEW_AWS_BUCKET }}/${{github.sha}}/space.tar.gz --expires-in 3600)
fi
- if [ ${{ env.BUILD_WEB }} == true ] || [ ${{ env.BUILD_SPACE }} == true ]; then
+ ADMIN_S3_URL=""
+ if [ ${{ env.BUILD_ADMIN }} == true ]; then
+ ADMIN_S3_URL=$(aws s3 presign s3://${{ vars.FEATURE_PREVIEW_AWS_BUCKET }}/${{github.sha}}/admin.tar.gz --expires-in 3600)
+ fi
+
+ if [ ${{ env.BUILD_WEB }} == true ] || [ ${{ env.BUILD_SPACE }} == true ] || [ ${{ env.BUILD_ADMIN }} == true ]; then
helm --kube-insecure-skip-tls-verify repo add feature-preview ${{ vars.FEATURE_PREVIEW_HELM_CHART_URL }}
@@ -181,6 +239,9 @@ jobs:
--set space.image=${{vars.FEATURE_PREVIEW_DOCKER_BASE}} \
--set space.enabled=${{ env.BUILD_SPACE || false }} \
--set space.artifact_url=$SPACE_S3_URL \
+ --set admin.image=${{vars.FEATURE_PREVIEW_DOCKER_BASE}} \
+ --set admin.enabled=${{ env.BUILD_ADMIN || false }} \
+ --set admin.artifact_url=$ADMIN_S3_URL \
--set shared_config.deploy_script_url=$DEPLOY_SCRIPT_URL \
--set shared_config.api_base_url=${{vars.FEATURE_PREVIEW_NEXT_PUBLIC_API_BASE_URL}} \
--output json \
diff --git a/admin/.eslintrc.js b/admin/.eslintrc.js
new file mode 100644
index 000000000..2278de30f
--- /dev/null
+++ b/admin/.eslintrc.js
@@ -0,0 +1,14 @@
+module.exports = {
+ root: true,
+ extends: ["custom"],
+ parser: "@typescript-eslint/parser",
+ settings: {
+ "import/resolver": {
+ typescript: {},
+ node: {
+ moduleDirectory: ["node_modules", "."],
+ },
+ },
+ },
+ rules: {}
+}
\ No newline at end of file
diff --git a/admin/.prettierignore b/admin/.prettierignore
new file mode 100644
index 000000000..43e8a7b8f
--- /dev/null
+++ b/admin/.prettierignore
@@ -0,0 +1,6 @@
+.next
+.vercel
+.tubro
+out/
+dis/
+build/
\ No newline at end of file
diff --git a/admin/.prettierrc b/admin/.prettierrc
new file mode 100644
index 000000000..87d988f1b
--- /dev/null
+++ b/admin/.prettierrc
@@ -0,0 +1,5 @@
+{
+ "printWidth": 120,
+ "tabWidth": 2,
+ "trailingComma": "es5"
+}
diff --git a/admin/Dockerfile.admin b/admin/Dockerfile.admin
new file mode 100644
index 000000000..9abc5daef
--- /dev/null
+++ b/admin/Dockerfile.admin
@@ -0,0 +1,51 @@
+FROM node:18-alpine AS builder
+RUN apk add --no-cache libc6-compat
+WORKDIR /app
+
+RUN yarn global add turbo
+COPY . .
+
+RUN turbo prune --scope=admin --docker
+
+FROM node:18-alpine AS installer
+
+RUN apk add --no-cache libc6-compat
+WORKDIR /app
+
+COPY .gitignore .gitignore
+COPY --from=builder /app/out/json/ .
+COPY --from=builder /app/out/yarn.lock ./yarn.lock
+RUN yarn install --network-timeout 500000
+
+COPY --from=builder /app/out/full/ .
+COPY turbo.json turbo.json
+
+ARG NEXT_PUBLIC_API_BASE_URL=""
+ARG NEXT_PUBLIC_DEPLOY_WITH_NGINX=1
+
+ENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL
+ENV NEXT_PUBLIC_DEPLOY_WITH_NGINX=$NEXT_PUBLIC_DEPLOY_WITH_NGINX
+
+RUN yarn turbo run build --filter=admin
+
+FROM node:18-alpine AS runner
+WORKDIR /app
+
+COPY --from=installer /app/admin/next.config.js .
+COPY --from=installer /app/admin/package.json .
+
+COPY --from=installer /app/admin/.next/standalone ./
+COPY --from=installer /app/admin/.next/static ./admin/.next/static
+COPY --from=installer /app/admin/public ./admin/public
+
+
+ARG NEXT_PUBLIC_API_BASE_URL=""
+ARG NEXT_PUBLIC_DEPLOY_WITH_NGINX=1
+
+ENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL
+ENV NEXT_PUBLIC_DEPLOY_WITH_NGINX=$NEXT_PUBLIC_DEPLOY_WITH_NGINX
+
+ENV NEXT_TELEMETRY_DISABLED 1
+ENV TURBO_TELEMETRY_DISABLED 1
+
+EXPOSE 3000
\ No newline at end of file
diff --git a/admin/app/ai/layout.tsx b/admin/app/ai/layout.tsx
new file mode 100644
index 000000000..64e747a87
--- /dev/null
+++ b/admin/app/ai/layout.tsx
@@ -0,0 +1,21 @@
+"use client";
+
+import { ReactNode } from "react";
+// layouts
+import { AuthLayout } from "@/layouts";
+// lib
+import { AuthWrapper, InstanceWrapper } from "@/lib/wrappers";
+
+interface AILayoutProps {
+ children: ReactNode;
+}
+
+const AILayout = ({ children }: AILayoutProps) => (
+
+ We will auto-generate this. Paste this into your Authorized JavaScript origins field. For this OAuth client{" "} + + here. + +
+ ), + }, + { + key: "Callback_URI", + label: "Callback URI", + url: `${originURL}/auth/google/callback/`, + description: ( ++ We will auto-generate this. Paste this into your Authorized Redirect URI field. For this OAuth client{" "} + + here. + +
+ ), + }, + ]; + + const onSubmit = async (formData: GoogleConfigFormValues) => { + const payload: Partial{message}
+{description}
+ )} +{description}
+{text}
++ Get started by setting up your instance and workspace +
+Configure instance-wide settings to secure your instance
+Post setup you will be able to manage this Plane instance.
+