diff --git a/.github/workflows/build-branch.yml b/.github/workflows/build-branch.yml index 74d81a83eb7..f9ca2b61e12 100644 --- a/.github/workflows/build-branch.yml +++ b/.github/workflows/build-branch.yml @@ -2,6 +2,27 @@ name: Branch Build on: workflow_dispatch: + inputs: + build-web: + required: false + description: "Build Web" + type: boolean + default: false + build-space: + required: false + description: "Build Space" + type: boolean + default: false + build-api: + required: false + description: "Build API" + type: boolean + default: false + build-proxy: + required: false + description: "Build Proxy" + type: boolean + default: false push: branches: - master @@ -18,7 +39,7 @@ jobs: name: Build-Push Web/Space/API/Proxy Docker Image runs-on: ubuntu-latest outputs: - gh_branch_name: ${{ steps.set_env_variables.outputs.TARGET_BRANCH }} + gh_branch_name: ${{ steps.set_env_variables.outputs.TARGET_BRANCH }} gh_buildx_driver: ${{ steps.set_env_variables.outputs.BUILDX_DRIVER }} gh_buildx_version: ${{ steps.set_env_variables.outputs.BUILDX_VERSION }} gh_buildx_platforms: ${{ steps.set_env_variables.outputs.BUILDX_PLATFORMS }} @@ -74,7 +95,7 @@ jobs: - nginx/** branch_build_push_frontend: - if: ${{ (needs.branch_build_setup.outputs.build_frontend == 'true' || github.event_name == 'release' || needs.branch_build_setup.outputs.gh_branch_name == 'master') && !contains(needs.branch_build_setup.outputs.gh_buildx_platforms, 'linux/arm64') }} + if: ${{ (needs.branch_build_setup.outputs.build_frontend == 'true' || github.event.inputs.build-web=='true' || github.event_name == 'release' || needs.branch_build_setup.outputs.gh_branch_name == 'master') && !contains(needs.branch_build_setup.outputs.gh_buildx_platforms, 'linux/arm64') }} runs-on: ubuntu-20.04 needs: [branch_build_setup] env: @@ -298,7 +319,7 @@ jobs: ${{ env.FRONTEND_TAG_ARM64 }} branch_build_push_space: - if: ${{ needs.branch_build_setup.outputs.build_space == 'true' || github.event_name == 'release' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + if: ${{ needs.branch_build_setup.outputs.build_space == 'true' || github.event.inputs.build-space=='true' || github.event_name == 'release' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} runs-on: ubuntu-20.04 needs: [branch_build_setup] env: @@ -351,7 +372,7 @@ jobs: DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }} branch_build_push_backend: - if: ${{ needs.branch_build_setup.outputs.build_backend == 'true' || github.event_name == 'release' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + if: ${{ needs.branch_build_setup.outputs.build_backend == 'true' || github.event.inputs.build-api=='true' || github.event_name == 'release' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} runs-on: ubuntu-20.04 needs: [branch_build_setup] env: @@ -404,7 +425,7 @@ jobs: DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }} branch_build_push_proxy: - if: ${{ needs.branch_build_setup.outputs.build_proxy == 'true' || github.event_name == 'release' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} + if: ${{ needs.branch_build_setup.outputs.build_proxy == 'true' || github.event.inputs.build-web=='true' || github.event_name == 'release' || needs.branch_build_setup.outputs.gh_branch_name == 'master' }} runs-on: ubuntu-20.04 needs: [branch_build_setup] env: @@ -455,4 +476,3 @@ jobs: DOCKER_BUILDKIT: 1 DOCKER_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }} - diff --git a/.github/workflows/feature-deployment.yml b/.github/workflows/feature-deployment.yml index 12549cff514..c5eec3cd3ad 100644 --- a/.github/workflows/feature-deployment.yml +++ b/.github/workflows/feature-deployment.yml @@ -40,7 +40,7 @@ jobs: 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_API_URL: ${{ vars.FEATURE_PREVIEW_NEXT_PUBLIC_API_BASE_URL }} + NEXT_PUBLIC_API_BASE_URL: ${{ vars.FEATURE_PREVIEW_NEXT_PUBLIC_API_BASE_URL }} steps: - name: Set up Node.js uses: actions/setup-node@v4 @@ -54,21 +54,21 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - path: feature-preview + path: plane - name: Install Dependencies run: | - cd $GITHUB_WORKSPACE/feature-preview + cd $GITHUB_WORKSPACE/plane yarn install - name: Build Web id: build-web run: | - cd $GITHUB_WORKSPACE/feature-preview + cd $GITHUB_WORKSPACE/plane yarn build --filter=web cd $GITHUB_WORKSPACE TAR_NAME="web.tar.gz" - tar -czf $TAR_NAME ./feature-preview - + 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 @@ -82,6 +82,7 @@ jobs: 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.space-build }} s3-url: ${{ steps.build-space.outputs.S3_PRESIGNED_URL }} @@ -181,6 +182,7 @@ jobs: --set space.enabled=${{ env.BUILD_SPACE || false }} \ --set space.artifact_url=$SPACE_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 \ --timeout 1000s) diff --git a/apiserver/plane/app/views/project.py b/apiserver/plane/app/views/project.py index 6f9b2618e19..35d997d1544 100644 --- a/apiserver/plane/app/views/project.py +++ b/apiserver/plane/app/views/project.py @@ -88,7 +88,10 @@ def get_queryset(self): .get_queryset() .filter(workspace__slug=self.kwargs.get("slug")) .filter( - Q(project_projectmember__member=self.request.user) + Q( + project_projectmember__member=self.request.user, + project_projectmember__is_active=True, + ) | Q(network=2) ) .select_related( @@ -173,10 +176,7 @@ def list(self, request, slug): for field in request.GET.get("fields", "").split(",") if field ] - projects = ( - self.get_queryset() - .order_by("sort_order", "name") - ) + projects = self.get_queryset().order_by("sort_order", "name") if request.GET.get("per_page", False) and request.GET.get( "cursor", False ): @@ -576,9 +576,11 @@ def post(self, request, slug, project_id, pk): _ = WorkspaceMember.objects.create( workspace_id=project_invite.workspace_id, member=user, - role=15 - if project_invite.role >= 15 - else project_invite.role, + role=( + 15 + if project_invite.role >= 15 + else project_invite.role + ), ) else: # Else make him active @@ -685,9 +687,14 @@ def create(self, request, slug, project_id): ) bulk_project_members = [] - member_roles = {member.get("member_id"): member.get("role") for member in members} + member_roles = { + member.get("member_id"): member.get("role") for member in members + } # Update roles in the members array based on the member_roles dictionary - for project_member in ProjectMember.objects.filter(project_id=project_id, member_id__in=[member.get("member_id") for member in members]): + for project_member in ProjectMember.objects.filter( + project_id=project_id, + member_id__in=[member.get("member_id") for member in members], + ): project_member.role = member_roles[str(project_member.member_id)] project_member.is_active = True bulk_project_members.append(project_member) @@ -710,9 +717,9 @@ def create(self, request, slug, project_id): role=member.get("role", 10), project_id=project_id, workspace_id=project.workspace_id, - sort_order=sort_order[0] - 10000 - if len(sort_order) - else 65535, + sort_order=( + sort_order[0] - 10000 if len(sort_order) else 65535 + ), ) ) bulk_issue_props.append( @@ -733,7 +740,10 @@ def create(self, request, slug, project_id): bulk_issue_props, batch_size=10, ignore_conflicts=True ) - project_members = ProjectMember.objects.filter(project_id=project_id, member_id__in=[member.get("member_id") for member in members]) + project_members = ProjectMember.objects.filter( + project_id=project_id, + member_id__in=[member.get("member_id") for member in members], + ) serializer = ProjectMemberRoleSerializer(project_members, many=True) return Response(serializer.data, status=status.HTTP_201_CREATED) diff --git a/deploy/1-click/README.md b/deploy/1-click/README.md index 88ea66c4c8e..9ed2323de2d 100644 --- a/deploy/1-click/README.md +++ b/deploy/1-click/README.md @@ -1,78 +1,79 @@ -# 1-Click Self-Hosting +# One-click deploy -In this guide, we will walk you through the process of setting up a 1-click self-hosted environment. Self-hosting allows you to have full control over your applications and data. It's a great way to ensure privacy, control, and customization. +Deployment methods for Plane have improved significantly to make self-managing super-easy. One of those is a single-line-command installation of Plane. -Let's get started! +This short guide will guide you through the process, the background tasks that run with the command for the Community, One, and Enterprise editions, and the post-deployment configuration options available to you. -## Installing Plane +### Requirements -Installing Plane is a very easy and minimal step process. +- Operating systems: Debian, Ubuntu, CentOS +- Supported CPU architectures: AMD64, ARM64, x86_64, AArch64 -### Prerequisite +### Download the latest stable release -- Operating System (latest): Debian / Ubuntu / Centos -- Supported CPU Architechture: AMD64 / ARM64 / x86_64 / aarch64 - -### Downloading Latest Stable Release +Run ↓ on any CLI. ``` curl -fsSL https://raw.githubusercontent.com/makeplane/plane/master/deploy/1-click/install.sh | sh - - ``` -
- Downloading Preview Release +### Download the Preview release + +`Preview` builds do not support ARM64, AArch64 CPU architectures + +Run ↓ on any CLI. ``` export BRANCH=preview - curl -fsSL https://raw.githubusercontent.com/makeplane/plane/preview/deploy/1-click/install.sh | sh - - ``` -NOTE: `Preview` builds do not support ARM64/AARCH64 CPU architecture -
- --- +--- +### Successful installation -Expect this after a successful install +You should see ↓ if there are no hitches. That output will also list the IP address you can use to access your Plane instance. ![Install Output](images/install.png) -Access the application on a browser via http://server-ip-address - --- -### Get Control of your Plane Server Setup +### Manage your Plane instance -Plane App is available via the command `plane-app`. Running the command `plane-app --help` helps you to manage Plane +Use `plane-app` [OPERATOR] to manage your Plane instance easily. Get a list of all operators with `plane-app ---help`. ![Plane Help](images/help.png) -Basic Operations: -1. Start Server using `plane-app start` -1. Stop Server using `plane-app stop` -1. Restart Server using `plane-app restart` - -Advanced Operations: -1. Configure Plane using `plane-app --configure`. This will give you options to modify - - NGINX Port (default 80) - - Domain Name (default is the local server public IP address) - - File Upload Size (default 5MB) - - External Postgres DB Url (optional - default empty) - - External Redis URL (optional - default empty) - - AWS S3 Bucket (optional - to be configured only in case the user wants to use an S3 Bucket) - -1. Upgrade Plane using `plane-app --upgrade`. This will get the latest stable version of Plane files (docker-compose.yaml, .env, and docker images) - -1. Updating Plane App installer using `plane-app --update-installer` will update the `plane-app` utility. - -1. Uninstall Plane using `plane-app --uninstall`. This will uninstall the Plane application from the server and all docker containers but do not remove the data stored in Postgres, Redis, and Minio. - -1. Plane App can be reinstalled using `plane-app --install`. - -Application Data is stored in the mentioned folders: -1. DB Data: /opt/plane/data/postgres -1. Redis Data: /opt/plane/data/redis -1. Minio Data: /opt/plane/data/minio \ No newline at end of file +1. Basic operators + + 1. `plane-app start` starts the Plane server. + 2. `plane-app restart` restarts the Plane server. + 3. `plane-app stop` stops the Plane server. + +2. Advanced operators + + `plane-app --configure` will show advanced configurators. + + - Change your proxy or listening port +
Default: 80 + - Change your domain name +
Default: Deployed server's public IP address + - File upload size +
Default: 5MB + - Specify external database address when using an external database +
Default: `Empty` +
`Default folder: /opt/plane/data/postgres` + - Specify external Redis URL when using external Redis +
Default: `Empty` +
`Default folder: /opt/plane/data/redis` + - Configure AWS S3 bucket +
Use only when you or your users want to use S3 +
`Default folder: /opt/plane/data/minio` + +3. Version operators + + 1. `plane-app --upgrade` gets the latest stable version of `docker-compose.yaml`, `.env`, and Docker images + 2. `plane-app --update-installer` updates the installer and the `plane-app` utility. + 3. `plane-app --uninstall` uninstalls the Plane application and all Docker containers from the server but leaves the data stored in + Postgres, Redis, and Minio alone. + 4. `plane-app --install` installs the Plane app again. diff --git a/deploy/1-click/plane-app b/deploy/1-click/plane-app index be3718c9267..2f6c8b73069 100644 --- a/deploy/1-click/plane-app +++ b/deploy/1-click/plane-app @@ -494,13 +494,6 @@ function install() { update_env "CORS_ALLOWED_ORIGINS" "http://$MY_IP" update_config "INSTALLATION_DATE" "$(date '+%Y-%m-%d')" - - if command -v crontab &> /dev/null; then - sudo touch /etc/cron.daily/makeplane - sudo chmod +x /etc/cron.daily/makeplane - sudo echo "0 2 * * * root /usr/local/bin/plane-app --upgrade" > /etc/cron.daily/makeplane - sudo crontab /etc/cron.daily/makeplane - fi show_message "Plane Installed Successfully ✅" show_message "" @@ -606,11 +599,6 @@ function uninstall() { sudo rm $PLANE_INSTALL_DIR/variables-upgrade.env &> /dev/null sudo rm $PLANE_INSTALL_DIR/config.env &> /dev/null sudo rm $PLANE_INSTALL_DIR/docker-compose.yaml &> /dev/null - - if command -v crontab &> /dev/null; then - sudo crontab -r &> /dev/null - sudo rm /etc/cron.daily/makeplane &> /dev/null - fi # rm -rf $PLANE_INSTALL_DIR &> /dev/null show_message "- Configuration Cleaned ✅" diff --git a/web/components/core/modals/gpt-assistant-popover.tsx b/web/components/core/modals/gpt-assistant-popover.tsx index 590015e122c..deffd883afd 100644 --- a/web/components/core/modals/gpt-assistant-popover.tsx +++ b/web/components/core/modals/gpt-assistant-popover.tsx @@ -7,6 +7,8 @@ import useToast from "hooks/use-toast"; import { usePopper } from "react-popper"; // ui import { Button, Input } from "@plane/ui"; +// icons +import { AlertCircle } from "lucide-react"; // components import { RichReadOnlyEditorWithRef } from "@plane/rich-text-editor"; import { Popover, Transition } from "@headlessui/react"; @@ -250,8 +252,17 @@ export const GptAssistantPopover: React.FC = (props) => { /> )} /> -
- {responseActionButton} +
+ {responseActionButton ? ( + <>{responseActionButton} + ) : ( + <> +
+ +

By using this feature, you consent to sharing the message with a 3rd party service.

+
+ + )}