diff --git a/.env.example b/.env.example index fc1aef49d..2b6931761 100644 --- a/.env.example +++ b/.env.example @@ -9,11 +9,11 @@ NEXT_PUBLIC_GITHUB_ID="" NEXT_PUBLIC_GITHUB_APP_NAME="" # Sentry DSN for error monitoring NEXT_PUBLIC_SENTRY_DSN="" -# Enable/Disable OAUTH - default 0 for selfhosted instance +# Enable/Disable OAUTH - default 0 for selfhosted instance NEXT_PUBLIC_ENABLE_OAUTH=0 # Enable/Disable sentry NEXT_PUBLIC_ENABLE_SENTRY=0 -# Enable/Disable session recording +# Enable/Disable session recording NEXT_PUBLIC_ENABLE_SESSION_RECORDER=0 # Enable/Disable event tracking NEXT_PUBLIC_TRACK_EVENTS=0 @@ -59,15 +59,16 @@ AWS_S3_BUCKET_NAME="uploads" FILE_SIZE_LIMIT=5242880 # GPT settings -OPENAI_API_KEY="" -GPT_ENGINE="" +OPENAI_API_BASE="https://api.openai.com/v1" # change if using a custom endpoint +OPENAI_API_KEY="sk-" # add your openai key here +GPT_ENGINE="gpt-3.5-turbo" # use "gpt-4" if you have access # Github GITHUB_CLIENT_SECRET="" # For fetching release notes # Settings related to Docker DOCKERIZED=1 -# set to 1 If using the pre-configured minio setup +# set to 1 If using the pre-configured minio setup USE_MINIO=1 # Nginx Configuration @@ -79,4 +80,4 @@ DEFAULT_PASSWORD="password123" # SignUps ENABLE_SIGNUP="1" -# Auto generated and Required that will be generated from setup.sh \ No newline at end of file +# Auto generated and Required that will be generated from setup.sh diff --git a/apiserver/Procfile b/apiserver/Procfile index 30d734913..694c49df4 100644 --- a/apiserver/Procfile +++ b/apiserver/Procfile @@ -1,2 +1,3 @@ web: gunicorn -w 4 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:$PORT --config gunicorn.config.py --max-requests 10000 --max-requests-jitter 1000 --access-logfile - -worker: celery -A plane worker -l info \ No newline at end of file +worker: celery -A plane worker -l info +beat: celery -A plane beat -l INFO \ No newline at end of file diff --git a/apiserver/plane/api/urls.py b/apiserver/plane/api/urls.py index 34e711be6..5403a88f0 100644 --- a/apiserver/plane/api/urls.py +++ b/apiserver/plane/api/urls.py @@ -77,6 +77,8 @@ from plane.api.views import ( BulkCreateIssueLabelsEndpoint, IssueAttachmentEndpoint, IssueSubscriberViewSet, + IssueArchiveViewSet, + IssueSubscriberViewSet, ## End Issues # States StateViewSet, @@ -853,6 +855,36 @@ urlpatterns = [ name="project-issue-roadmap", ), ## IssueProperty Ebd + ## Issue Archives + path( + "workspaces//projects//archived-issues/", + IssueArchiveViewSet.as_view( + { + "get": "list", + } + ), + name="project-issue-archive", + ), + path( + "workspaces//projects//archived-issues//", + IssueArchiveViewSet.as_view( + { + "get": "retrieve", + "delete": "destroy", + } + ), + name="project-issue-archive", + ), + path( + "workspaces//projects//unarchive//", + IssueArchiveViewSet.as_view( + { + "post": "unarchive", + } + ), + name="project-issue-archive", + ), + ## End Issue Archives ## File Assets path( "workspaces//file-assets/", diff --git a/apiserver/plane/api/views/__init__.py b/apiserver/plane/api/views/__init__.py index 327dd6037..9eba0868a 100644 --- a/apiserver/plane/api/views/__init__.py +++ b/apiserver/plane/api/views/__init__.py @@ -65,6 +65,7 @@ from .issue import ( IssueLinkViewSet, BulkCreateIssueLabelsEndpoint, IssueAttachmentEndpoint, + IssueArchiveViewSet, IssueSubscriberViewSet, ) diff --git a/apiserver/plane/api/views/gpt.py b/apiserver/plane/api/views/gpt.py index a48bea242..8878e99a5 100644 --- a/apiserver/plane/api/views/gpt.py +++ b/apiserver/plane/api/views/gpt.py @@ -67,7 +67,7 @@ class GPTIntegrationEndpoint(BaseAPIView): openai.api_key = settings.OPENAI_API_KEY response = openai.Completion.create( - engine=settings.GPT_ENGINE, + model=settings.GPT_ENGINE, prompt=final_text, temperature=0.7, max_tokens=1024, diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index d96441c75..415e7e2fa 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -914,6 +914,197 @@ class IssueAttachmentEndpoint(BaseAPIView): ) +class IssueArchiveViewSet(BaseViewSet): + permission_classes = [ + ProjectEntityPermission, + ] + serializer_class = IssueFlatSerializer + model = Issue + + def get_queryset(self): + return ( + Issue.objects.annotate( + sub_issues_count=Issue.objects.filter(parent=OuterRef("id")) + .order_by() + .annotate(count=Func(F("id"), function="Count")) + .values("count") + ) + .filter(archived_at__isnull=False) + .filter(project_id=self.kwargs.get("project_id")) + .filter(workspace__slug=self.kwargs.get("slug")) + .select_related("project") + .select_related("workspace") + .select_related("state") + .select_related("parent") + .prefetch_related("assignees") + .prefetch_related("labels") + ) + + @method_decorator(gzip_page) + def list(self, request, slug, project_id): + try: + filters = issue_filters(request.query_params, "GET") + show_sub_issues = request.GET.get("show_sub_issues", "true") + + # Custom ordering for priority and state + priority_order = ["urgent", "high", "medium", "low", None] + state_order = ["backlog", "unstarted", "started", "completed", "cancelled"] + + order_by_param = request.GET.get("order_by", "-created_at") + + issue_queryset = ( + self.get_queryset() + .filter(**filters) + .annotate(cycle_id=F("issue_cycle__id")) + .annotate(module_id=F("issue_module__id")) + .annotate( + link_count=IssueLink.objects.filter(issue=OuterRef("id")) + .order_by() + .annotate(count=Func(F("id"), function="Count")) + .values("count") + ) + .annotate( + attachment_count=IssueAttachment.objects.filter( + issue=OuterRef("id") + ) + .order_by() + .annotate(count=Func(F("id"), function="Count")) + .values("count") + ) + ) + + # Priority Ordering + if order_by_param == "priority" or order_by_param == "-priority": + priority_order = ( + priority_order + if order_by_param == "priority" + else priority_order[::-1] + ) + issue_queryset = issue_queryset.annotate( + priority_order=Case( + *[ + When(priority=p, then=Value(i)) + for i, p in enumerate(priority_order) + ], + output_field=CharField(), + ) + ).order_by("priority_order") + + # State Ordering + elif order_by_param in [ + "state__name", + "state__group", + "-state__name", + "-state__group", + ]: + state_order = ( + state_order + if order_by_param in ["state__name", "state__group"] + else state_order[::-1] + ) + issue_queryset = issue_queryset.annotate( + state_order=Case( + *[ + When(state__group=state_group, then=Value(i)) + for i, state_group in enumerate(state_order) + ], + default=Value(len(state_order)), + output_field=CharField(), + ) + ).order_by("state_order") + # assignee and label ordering + elif order_by_param in [ + "labels__name", + "-labels__name", + "assignees__first_name", + "-assignees__first_name", + ]: + issue_queryset = issue_queryset.annotate( + max_values=Max( + order_by_param[1::] + if order_by_param.startswith("-") + else order_by_param + ) + ).order_by( + "-max_values" if order_by_param.startswith("-") else "max_values" + ) + else: + issue_queryset = issue_queryset.order_by(order_by_param) + + issue_queryset = ( + issue_queryset + if show_sub_issues == "true" + else issue_queryset.filter(parent__isnull=True) + ) + + issues = IssueLiteSerializer(issue_queryset, many=True).data + + ## Grouping the results + group_by = request.GET.get("group_by", False) + if group_by: + return Response( + group_results(issues, group_by), status=status.HTTP_200_OK + ) + + return Response(issues, status=status.HTTP_200_OK) + + except Exception as e: + capture_exception(e) + return Response( + {"error": "Something went wrong please try again later"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + def retrieve(self, request, slug, project_id, pk=None): + try: + issue = Issue.objects.get( + workspace__slug=slug, + project_id=project_id, + archived_at__isnull=False, + pk=pk, + ) + return Response(IssueSerializer(issue).data, status=status.HTTP_200_OK) + except Issue.DoesNotExist: + return Response( + {"error": "Issue Does not exist"}, status=status.HTTP_404_NOT_FOUND + ) + except Exception as e: + capture_exception(e) + return Response( + {"error": "Something went wrong please try again later"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + def unarchive(self, request, slug, project_id, pk=None): + try: + issue = Issue.objects.get( + workspace__slug=slug, + project_id=project_id, + archived_at__isnull=False, + pk=pk, + ) + issue.archived_at = None + issue.save() + issue_activity.delay( + type="issue.activity.updated", + requested_data=json.dumps({"archived_in": None}), + actor_id=str(request.user.id), + issue_id=str(issue.id), + project_id=str(project_id), + current_instance=None, + ) + + return Response(IssueSerializer(issue).data, status=status.HTTP_200_OK) + except Issue.DoesNotExist: + return Response( + {"error": "Issue Does not exist"}, status=status.HTTP_404_NOT_FOUND) + except Exception as e: + capture_exception(e) + return Response( + {"error": "Something went wrong, please try again later"}, + status=status.HTTP_400_BAD_REQUEST, + ) + class IssueSubscriberViewSet(BaseViewSet): serializer_class = IssueSubscriberSerializer model = IssueSubscriber diff --git a/apiserver/plane/bgtasks/issue_activites_task.py b/apiserver/plane/bgtasks/issue_activites_task.py index 7bb6010dd..ae123cfa7 100644 --- a/apiserver/plane/bgtasks/issue_activites_task.py +++ b/apiserver/plane/bgtasks/issue_activites_task.py @@ -5,6 +5,7 @@ import requests # Django imports from django.conf import settings from django.core.serializers.json import DjangoJSONEncoder +from django.utils import timezone # Third Party imports from celery import shared_task @@ -557,6 +558,24 @@ def track_estimate_points( ) +def track_archive_in( + requested_data, current_instance, issue_id, project, actor, issue_activities +): + issue_activities.append( + IssueActivity( + issue_id=issue_id, + project=project, + workspace=project.workspace, + comment=f"{actor.email} has restored the issue", + verb="updated", + actor=actor, + field="archived_at", + old_value="archive", + new_value="restore", + ) + ) + + def update_issue_activity( requested_data, current_instance, issue_id, project, actor, issue_activities ): @@ -573,6 +592,7 @@ def update_issue_activity( "blocks_list": track_blocks, "blockers_list": track_blockings, "estimate_point": track_estimate_points, + "archived_in": track_archive_in, } requested_data = json.loads(requested_data) if requested_data is not None else None @@ -950,6 +970,7 @@ def delete_attachment_activity( ) + # Receive message from room group @shared_task def issue_activity( @@ -961,6 +982,11 @@ def issue_activity( actor = User.objects.get(pk=actor_id) project = Project.objects.get(pk=project_id) + issue = Issue.objects.filter(pk=issue_id).first() + if issue is not None: + issue.updated_at = timezone.now() + issue.save() + # add the user to issue subscriber try: _ = IssueSubscriber.objects.create(issue_id=issue_id, subscriber=actor) diff --git a/apiserver/plane/bgtasks/issue_automation_task.py b/apiserver/plane/bgtasks/issue_automation_task.py new file mode 100644 index 000000000..0b64e546f --- /dev/null +++ b/apiserver/plane/bgtasks/issue_automation_task.py @@ -0,0 +1,148 @@ +# Python improts +from datetime import timedelta + +# Django imports +from django.utils import timezone +from django.db.models import Q +from django.conf import settings + +# Third party imports +from celery import shared_task +from sentry_sdk import capture_exception + +# Module imports +from plane.db.models import Issue, Project, IssueActivity, State + + +@shared_task +def archive_and_close_old_issues(): + archive_old_issues() + close_old_issues() + +def archive_old_issues(): + try: + # Get all the projects whose archive_in is greater than 0 + projects = Project.objects.filter(archive_in__gt=0) + + for project in projects: + project_id = project.id + archive_in = project.archive_in + + # Get all the issues whose updated_at in less that the archive_in month + issues = Issue.objects.filter( + Q( + project=project_id, + archived_at__isnull=True, + updated_at__lte=(timezone.now() - timedelta(days=archive_in * 30)), + state__group__in=["completed", "cancelled"], + ), + Q(issue_cycle__isnull=True) + | ( + Q(issue_cycle__cycle__end_date__lt=timezone.now().date()) + & Q(issue_cycle__isnull=False) + ), + Q(issue_module__isnull=True) + | ( + Q(issue_module__module__target_date__lt=timezone.now().date()) + & Q(issue_module__isnull=False) + ), + ) + + # Check if Issues + if issues: + issues_to_update = [] + for issue in issues: + issue.archived_at = timezone.now() + issues_to_update.append(issue) + + # Bulk Update the issues and log the activity + Issue.objects.bulk_update(issues_to_update, ["archived_at"], batch_size=100) + IssueActivity.objects.bulk_create( + [ + IssueActivity( + issue_id=issue.id, + actor=project.created_by, + verb="updated", + field="archived_at", + project=project, + workspace=project.workspace, + comment="Plane archived the issue", + new_value="archive", + old_value="" + ) + for issue in issues_to_update + ], + batch_size=100, + ) + return + except Exception as e: + if settings.DEBUG: + print(e) + capture_exception(e) + return + +def close_old_issues(): + try: + # Get all the projects whose close_in is greater than 0 + projects = Project.objects.filter(close_in__gt=0).select_related("default_state") + + for project in projects: + project_id = project.id + close_in = project.close_in + + # Get all the issues whose updated_at in less that the close_in month + issues = Issue.objects.filter( + Q( + project=project_id, + archived_at__isnull=True, + updated_at__lte=(timezone.now() - timedelta(days=close_in * 30)), + state__group__in=["backlog", "unstarted", "started"], + ), + Q(issue_cycle__isnull=True) + | ( + Q(issue_cycle__cycle__end_date__lt=timezone.now().date()) + & Q(issue_cycle__isnull=False) + ), + Q(issue_module__isnull=True) + | ( + Q(issue_module__module__target_date__lt=timezone.now().date()) + & Q(issue_module__isnull=False) + ), + ) + + # Check if Issues + if issues: + if project.default_state is None: + close_state = project.default_state + else: + close_state = State.objects.filter(group="cancelled").first() + + + issues_to_update = [] + for issue in issues: + issue.state = close_state + issues_to_update.append(issue) + + # Bulk Update the issues and log the activity + Issue.objects.bulk_update(issues_to_update, ["state"], batch_size=100) + IssueActivity.objects.bulk_create( + [ + IssueActivity( + issue_id=issue.id, + actor=project.created_by, + verb="updated", + field="state", + project=project, + workspace=project.workspace, + comment="Plane cancelled the issue", + ) + for issue in issues_to_update + ], + batch_size=100, + ) + return + except Exception as e: + if settings.DEBUG: + print(e) + capture_exception(e) + return \ No newline at end of file diff --git a/apiserver/plane/celery.py b/apiserver/plane/celery.py index 1fbbdd732..ed0dc419e 100644 --- a/apiserver/plane/celery.py +++ b/apiserver/plane/celery.py @@ -1,6 +1,7 @@ import os from celery import Celery from plane.settings.redis import redis_instance +from celery.schedules import crontab # Set the default Django settings module for the 'celery' program. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "plane.settings.production") @@ -13,5 +14,15 @@ app = Celery("plane") # pickle the object when using Windows. app.config_from_object("django.conf:settings", namespace="CELERY") +app.conf.beat_schedule = { + # Executes every day at 12 AM + "check-every-day-to-archive-and-close": { + "task": "plane.bgtasks.issue_automation_task.archive_and_close_old_issues", + "schedule": crontab(hour=0, minute=0), + }, +} + # Load task modules from all registered Django app configs. app.autodiscover_tasks() + +app.conf.beat_scheduler = 'django_celery_beat.schedulers.DatabaseScheduler' \ No newline at end of file diff --git a/apiserver/plane/db/models/issue.py b/apiserver/plane/db/models/issue.py index 4b765a516..f301d4191 100644 --- a/apiserver/plane/db/models/issue.py +++ b/apiserver/plane/db/models/issue.py @@ -28,6 +28,8 @@ class IssueManager(models.Manager): | models.Q(issue_inbox__status=2) | models.Q(issue_inbox__isnull=True) ) + .filter(archived_at__isnull=True) + .exclude(archived_at__isnull=False) ) @@ -81,6 +83,7 @@ class Issue(ProjectBaseModel): ) sort_order = models.FloatField(default=65535) completed_at = models.DateTimeField(null=True) + archived_at = models.DateField(null=True) objects = models.Manager() issue_objects = IssueManager() diff --git a/apiserver/plane/db/models/project.py b/apiserver/plane/db/models/project.py index 0b6c4b50d..b28cbc69e 100644 --- a/apiserver/plane/db/models/project.py +++ b/apiserver/plane/db/models/project.py @@ -4,6 +4,7 @@ from django.conf import settings from django.template.defaultfilters import slugify from django.db.models.signals import post_save from django.dispatch import receiver +from django.core.validators import MinValueValidator, MaxValueValidator # Modeule imports from plane.db.mixins import AuditModel @@ -74,6 +75,15 @@ class Project(BaseModel): estimate = models.ForeignKey( "db.Estimate", on_delete=models.SET_NULL, related_name="projects", null=True ) + archive_in = models.IntegerField( + default=0, validators=[MinValueValidator(0), MaxValueValidator(12)] + ) + close_in = models.IntegerField( + default=0, validators=[MinValueValidator(0), MaxValueValidator(12)] + ) + default_state = models.ForeignKey( + "db.State", on_delete=models.SET_NULL, null=True, related_name="default_state" + ) def __str__(self): """Return name of the project""" diff --git a/apiserver/plane/settings/common.py b/apiserver/plane/settings/common.py index 2e0266159..e3a918c18 100644 --- a/apiserver/plane/settings/common.py +++ b/apiserver/plane/settings/common.py @@ -35,6 +35,7 @@ INSTALLED_APPS = [ "rest_framework_simplejwt.token_blacklist", "corsheaders", "taggit", + "django_celery_beat", ] MIDDLEWARE = [ @@ -213,3 +214,4 @@ SIMPLE_JWT = { CELERY_TIMEZONE = TIME_ZONE CELERY_TASK_SERIALIZER = 'json' CELERY_ACCEPT_CONTENT = ['application/json'] +CELERY_IMPORTS = ("plane.bgtasks.issue_automation_task",) diff --git a/apiserver/plane/settings/production.py b/apiserver/plane/settings/production.py index 2e40c5998..98e22bcbd 100644 --- a/apiserver/plane/settings/production.py +++ b/apiserver/plane/settings/production.py @@ -246,8 +246,9 @@ PROXY_BASE_URL = os.environ.get("PROXY_BASE_URL", False) ANALYTICS_SECRET_KEY = os.environ.get("ANALYTICS_SECRET_KEY", False) ANALYTICS_BASE_API = os.environ.get("ANALYTICS_BASE_API", False) +OPENAI_API_BASE = os.environ.get("OPENAI_API_BASE", "https://api.openai.com/v1") OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", False) -GPT_ENGINE = os.environ.get("GPT_ENGINE", "text-davinci-003") +GPT_ENGINE = os.environ.get("GPT_ENGINE", "gpt-3.5-turbo") SLACK_BOT_TOKEN = os.environ.get("SLACK_BOT_TOKEN", False) diff --git a/apiserver/plane/settings/staging.py b/apiserver/plane/settings/staging.py index 076bb3e3c..daf8f974b 100644 --- a/apiserver/plane/settings/staging.py +++ b/apiserver/plane/settings/staging.py @@ -11,10 +11,9 @@ from sentry_sdk.integrations.django import DjangoIntegration from sentry_sdk.integrations.redis import RedisIntegration from .common import * # noqa + # Database -DEBUG = int(os.environ.get( - "DEBUG", 1 -)) == 1 +DEBUG = int(os.environ.get("DEBUG", 1)) == 1 DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql_psycopg2", @@ -56,9 +55,7 @@ STORAGES = { # Make true if running in a docker environment -DOCKERIZED = int(os.environ.get( - "DOCKERIZED", 0 -)) == 1 +DOCKERIZED = int(os.environ.get("DOCKERIZED", 0)) == 1 FILE_SIZE_LIMIT = int(os.environ.get("FILE_SIZE_LIMIT", 5242880)) USE_MINIO = int(os.environ.get("USE_MINIO", 0)) == 1 @@ -201,15 +198,19 @@ PROXY_BASE_URL = os.environ.get("PROXY_BASE_URL", False) ANALYTICS_SECRET_KEY = os.environ.get("ANALYTICS_SECRET_KEY", False) ANALYTICS_BASE_API = os.environ.get("ANALYTICS_BASE_API", False) + +OPENAI_API_BASE = os.environ.get("OPENAI_API_BASE", "https://api.openai.com/v1") OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", False) -GPT_ENGINE = os.environ.get("GPT_ENGINE", "text-davinci-003") +GPT_ENGINE = os.environ.get("GPT_ENGINE", "gpt-3.5-turbo") SLACK_BOT_TOKEN = os.environ.get("SLACK_BOT_TOKEN", False) LOGGER_BASE_URL = os.environ.get("LOGGER_BASE_URL", False) redis_url = os.environ.get("REDIS_URL") -broker_url = f"{redis_url}?ssl_cert_reqs={ssl.CERT_NONE.name}&ssl_ca_certs={certifi.where()}" +broker_url = ( + f"{redis_url}?ssl_cert_reqs={ssl.CERT_NONE.name}&ssl_ca_certs={certifi.where()}" +) CELERY_RESULT_BACKEND = broker_url CELERY_BROKER_URL = broker_url diff --git a/apiserver/requirements/base.txt b/apiserver/requirements/base.txt index 537564828..c4fa8ef2c 100644 --- a/apiserver/requirements/base.txt +++ b/apiserver/requirements/base.txt @@ -28,4 +28,5 @@ uvicorn==0.22.0 channels==4.0.0 openai==0.27.8 slack-sdk==3.21.3 -celery==5.3.1 \ No newline at end of file +celery==5.3.1 +django_celery_beat==2.5.0 diff --git a/apps/app/components/account/email-code-form.tsx b/apps/app/components/account/email-code-form.tsx index e1b7aea98..ba8c759af 100644 --- a/apps/app/components/account/email-code-form.tsx +++ b/apps/app/components/account/email-code-form.tsx @@ -164,8 +164,8 @@ export const EmailCodeForm = ({ handleSignIn }: any) => { type="button" className={`mt-5 flex w-full justify-end text-xs outline-none ${ isResendDisabled - ? "cursor-default text-brand-secondary" - : "cursor-pointer text-brand-accent" + ? "cursor-default text-custom-text-200" + : "cursor-pointer text-custom-primary" } `} onClick={() => { setIsCodeResending(true); diff --git a/apps/app/components/account/email-password-form.tsx b/apps/app/components/account/email-password-form.tsx index 8a0dc3a33..97da2b9e4 100644 --- a/apps/app/components/account/email-password-form.tsx +++ b/apps/app/components/account/email-password-form.tsx @@ -80,7 +80,7 @@ export const EmailPasswordForm: React.FC = ({ onSubmit }) => {
{isSignUpPage ? ( - + Already have an account? Sign in. @@ -88,7 +88,7 @@ export const EmailPasswordForm: React.FC = ({ onSubmit }) => { @@ -112,7 +112,7 @@ export const EmailPasswordForm: React.FC = ({ onSubmit }) => { {!isSignUpPage && ( - + Don{"'"}t have an account? Sign up. diff --git a/apps/app/components/account/github-login-button.tsx b/apps/app/components/account/github-login-button.tsx index d997b3a3d..889d46405 100644 --- a/apps/app/components/account/github-login-button.tsx +++ b/apps/app/components/account/github-login-button.tsx @@ -39,7 +39,7 @@ export const GithubLoginButton: FC = (props) => { - diff --git a/apps/app/components/analytics/custom-analytics/create-update-analytics-modal.tsx b/apps/app/components/analytics/custom-analytics/create-update-analytics-modal.tsx index afaaf1b98..22e728089 100644 --- a/apps/app/components/analytics/custom-analytics/create-update-analytics-modal.tsx +++ b/apps/app/components/analytics/custom-analytics/create-update-analytics-modal.tsx @@ -97,7 +97,7 @@ export const CreateUpdateAnalyticsModal: React.FC = ({ isOpen, handleClos leaveFrom="opacity-100" leaveTo="opacity-0" > -
+
@@ -111,10 +111,13 @@ export const CreateUpdateAnalyticsModal: React.FC = ({ isOpen, handleClos leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - +
- + Save Analytics
diff --git a/apps/app/components/analytics/custom-analytics/custom-analytics.tsx b/apps/app/components/analytics/custom-analytics/custom-analytics.tsx index f46b7f2b2..d04733b56 100644 --- a/apps/app/components/analytics/custom-analytics/custom-analytics.tsx +++ b/apps/app/components/analytics/custom-analytics/custom-analytics.tsx @@ -61,7 +61,7 @@ export const CustomAnalytics: React.FC = ({ = ({
) : (
-
+

No matching issues found. Try changing the parameters.

@@ -104,7 +104,7 @@ export const CustomAnalytics: React.FC = ({ ) ) : (
-
+

There was some error in fetching the data.

= ({ datum, analytics, params }) => } return ( -
+
= ({ datum, analytics, params }) => }} /> = ({ : undefined, }} theme={{ - background: "rgb(var(--color-bg-base))", axis: {}, }} /> diff --git a/apps/app/components/analytics/custom-analytics/select-bar.tsx b/apps/app/components/analytics/custom-analytics/select-bar.tsx index 7286a9cf8..8c2b822e5 100644 --- a/apps/app/components/analytics/custom-analytics/select-bar.tsx +++ b/apps/app/components/analytics/custom-analytics/select-bar.tsx @@ -29,7 +29,7 @@ export const AnalyticsSelectBar: React.FC = ({ > {!isProjectLevel && (
-
Project
+
Project
= ({
)}
-
Measure (y-axis)
+
Measure (y-axis)
= ({ />
-
Dimension (x-axis)
+
Dimension (x-axis)
= ({ />
-
Group
+
Group
= ({ }; const selectedProjects = - params.project && params.project.length > 0 ? params.project : projects.map((p) => p.id); + params.project && params.project.length > 0 ? params.project : projects?.map((p) => p.id); return (
-
+
{analytics ? analytics.total : "..."} Issues
{isProjectLevel && ( -
+
{renderShortDate( (cycleId @@ -207,7 +207,7 @@ export const AnalyticsSidebar: React.FC = ({
)}
-
+
{fullScreen ? ( <> {!isProjectLevel && selectedProjects && selectedProjects.length > 0 && ( @@ -215,61 +215,62 @@ export const AnalyticsSidebar: React.FC = ({

Selected Projects

{selectedProjects.map((projectId) => { - const project: IProject = projects.find((p) => p.id === projectId); + const project = projects?.find((p) => p.id === projectId); - return ( -
-
- {project.emoji ? ( - - {renderEmoji(project.emoji)} - - ) : project.icon_prop ? ( -
- - {project.icon_prop.name} + if (project) + return ( +
+
+ {project.emoji ? ( + + {renderEmoji(project.emoji)} -
- ) : ( - - {project?.name.charAt(0)} - - )} -
- {project.name} - - ({project.identifier}) - -
-
-
-
-
- -
Total members
-
- {project.total_members} + ) : project.icon_prop ? ( +
+ + {project.icon_prop.name} + +
+ ) : ( + + {project?.name.charAt(0)} + + )} +
+

{truncateText(project.name, 20)}

+ + ({project.identifier}) + +
-
-
- -
Total cycles
+
+
+
+ +
Total members
+
+ {project.total_members}
- {project.total_cycles} -
-
-
- -
Total modules
+
+
+ +
Total cycles
+
+ {project.total_cycles} +
+
+
+ +
Total modules
+
+ {project.total_modules}
- {project.total_modules}
-
- ); + ); })}
@@ -280,13 +281,13 @@ export const AnalyticsSidebar: React.FC = ({

Analytics for {cycleDetails.name}

-
Lead
+
Lead
{cycleDetails.owned_by?.first_name} {cycleDetails.owned_by?.last_name}
-
Start Date
+
Start Date
{cycleDetails.start_date && cycleDetails.start_date !== "" ? renderShortDate(cycleDetails.start_date) @@ -294,7 +295,7 @@ export const AnalyticsSidebar: React.FC = ({
-
Target Date
+
Target Date
{cycleDetails.end_date && cycleDetails.end_date !== "" ? renderShortDate(cycleDetails.end_date) @@ -308,14 +309,14 @@ export const AnalyticsSidebar: React.FC = ({

Analytics for {moduleDetails.name}

-
Lead
+
Lead
{moduleDetails.lead_detail?.first_name}{" "} {moduleDetails.lead_detail?.last_name}
-
Start Date
+
Start Date
{moduleDetails.start_date && moduleDetails.start_date !== "" ? renderShortDate(moduleDetails.start_date) @@ -323,7 +324,7 @@ export const AnalyticsSidebar: React.FC = ({
-
Target Date
+
Target Date
{moduleDetails.target_date && moduleDetails.target_date !== "" ? renderShortDate(moduleDetails.target_date) @@ -357,7 +358,7 @@ export const AnalyticsSidebar: React.FC = ({
-
Network
+
Network
{ NETWORK_CHOICES[ diff --git a/apps/app/components/analytics/custom-analytics/table.tsx b/apps/app/components/analytics/custom-analytics/table.tsx index df3953b35..54a73186e 100644 --- a/apps/app/components/analytics/custom-analytics/table.tsx +++ b/apps/app/components/analytics/custom-analytics/table.tsx @@ -37,9 +37,9 @@ export const AnalyticsTable: React.FC = ({ analytics, barGraphData, param
- - - +
+ + @@ -80,11 +80,11 @@ export const AnalyticsTable: React.FC = ({ analytics, barGraphData, param )} - + {barGraphData.data.map((item, index) => (
{ANALYTICS_X_AXIS_VALUES.find((v) => v.value === params.x_axis)?.label}
= ({ isOpen, onClose }) => { return (
-
+

Analytics for{" "} {cycleId ? cycleDetails?.name : moduleId ? moduleDetails?.name : projectDetails?.name} @@ -167,7 +167,7 @@ export const AnalyticsProjectModal: React.FC = ({ isOpen, onClose }) => {

- + {tabsList.map((tab) => ( - `rounded-3xl border border-brand-base px-4 py-2 text-xs hover:bg-brand-surface-2 ${ - selected ? "bg-brand-surface-2" : "" + `rounded-3xl border border-custom-border-100 px-4 py-2 text-xs hover:bg-custom-background-80 ${ + selected ? "bg-custom-background-80" : "" }` } onClick={() => trackAnalyticsEvent(tab)} diff --git a/apps/app/components/analytics/scope-and-demand/demand.tsx b/apps/app/components/analytics/scope-and-demand/demand.tsx index 4a454b564..bb0627025 100644 --- a/apps/app/components/analytics/scope-and-demand/demand.tsx +++ b/apps/app/components/analytics/scope-and-demand/demand.tsx @@ -10,10 +10,10 @@ type Props = { }; export const AnalyticsDemand: React.FC = ({ defaultAnalytics }) => ( -
+
DEMAND
-

Total open tasks

+

Total open tasks

{defaultAnalytics.open_issues}

@@ -31,13 +31,13 @@ export const AnalyticsDemand: React.FC = ({ defaultAnalytics }) => ( }} />
{group.state_group}
- + {group.state_count}
-

{percentage}%

+

{percentage}%

-
+
= ({ defaultAnalytics }) => ( ); })}
-
-

+

+

diff --git a/apps/app/components/analytics/scope-and-demand/leaderboard.tsx b/apps/app/components/analytics/scope-and-demand/leaderboard.tsx index 72b892eeb..daad1a9d9 100644 --- a/apps/app/components/analytics/scope-and-demand/leaderboard.tsx +++ b/apps/app/components/analytics/scope-and-demand/leaderboard.tsx @@ -10,7 +10,7 @@ type Props = { }; export const AnalyticsLeaderboard: React.FC = ({ users, title }) => ( -
+
{title}
{users.length > 0 ? (
@@ -33,7 +33,7 @@ export const AnalyticsLeaderboard: React.FC = ({ users, title }) => ( {user.firstName !== "" ? user.firstName[0] : "?"}
)} - + {user.firstName !== "" ? `${user.firstName} ${user.lastName}` : "No assignee"}
@@ -42,7 +42,7 @@ export const AnalyticsLeaderboard: React.FC = ({ users, title }) => ( ))}
) : ( -
No matching data found.
+
No matching data found.
)}
); diff --git a/apps/app/components/analytics/scope-and-demand/scope-and-demand.tsx b/apps/app/components/analytics/scope-and-demand/scope-and-demand.tsx index d5bf10bc2..cfc315ac1 100644 --- a/apps/app/components/analytics/scope-and-demand/scope-and-demand.tsx +++ b/apps/app/components/analytics/scope-and-demand/scope-and-demand.tsx @@ -88,7 +88,7 @@ export const ScopeAndDemand: React.FC = ({ fullScreen = true }) => { ) ) : (
-
+

There was some error in fetching the data.

mutateDefaultAnalytics()}>Refresh diff --git a/apps/app/components/analytics/scope-and-demand/scope.tsx b/apps/app/components/analytics/scope-and-demand/scope.tsx index b0a422ed4..1247fa824 100644 --- a/apps/app/components/analytics/scope-and-demand/scope.tsx +++ b/apps/app/components/analytics/scope-and-demand/scope.tsx @@ -8,9 +8,9 @@ type Props = { }; export const AnalyticsScope: React.FC = ({ defaultAnalytics }) => ( -
+
SCOPE
-
+
Pending issues
{defaultAnalytics.pending_issue_user.length > 0 ? ( @@ -27,8 +27,8 @@ export const AnalyticsScope: React.FC = ({ defaultAnalytics }) => ( ); return ( -
- +
+ {assignee ? assignee.assignees__first_name + " " + assignee.assignees__last_name : "No assignee"} @@ -69,12 +69,11 @@ export const AnalyticsScope: React.FC = ({ defaultAnalytics }) => ( }} margin={{ top: 20 }} theme={{ - background: "rgb(var(--color-bg-base))", axis: {}, }} /> ) : ( -
+
No matching data found.
)} diff --git a/apps/app/components/analytics/scope-and-demand/year-wise-issues.tsx b/apps/app/components/analytics/scope-and-demand/year-wise-issues.tsx index a37518cba..c1e0e95fa 100644 --- a/apps/app/components/analytics/scope-and-demand/year-wise-issues.tsx +++ b/apps/app/components/analytics/scope-and-demand/year-wise-issues.tsx @@ -15,14 +15,14 @@ export const AnalyticsYearWiseIssues: React.FC = ({ defaultAnalytics }) = const quarterMonthsList = [startMonth, startMonth + 1, startMonth + 2]; return ( -
+

Issues closed in a year

{defaultAnalytics.issue_completed_month_wise.length > 0 ? ( ({ x: month.label.substring(0, 3), y: @@ -43,19 +43,19 @@ export const AnalyticsYearWiseIssues: React.FC = ({ defaultAnalytics }) = margin={{ top: 20 }} enableSlices="x" sliceTooltip={(datum) => ( -
+
{datum.slice.points[0].data.yFormatted} - issues closed in + issues closed in {datum.slice.points[0].data.xFormatted}
)} theme={{ - background: "rgb(var(--color-bg-base))", + background: "rgb(var(--color-background-100))", }} enableArea /> ) : ( -
No matching data found.
+
No matching data found.
)}
); diff --git a/apps/app/components/analytics/select/project.tsx b/apps/app/components/analytics/select/project.tsx index 0cc88aa3b..5d625bd02 100644 --- a/apps/app/components/analytics/select/project.tsx +++ b/apps/app/components/analytics/select/project.tsx @@ -15,7 +15,7 @@ export const SelectProject: React.FC = ({ value, onChange, projects }) => query: project.name + project.identifier, content: (
- {project.identifier} + {project.identifier} {project.name}
), diff --git a/apps/app/components/analytics/select/segment.tsx b/apps/app/components/analytics/select/segment.tsx index ef6a2fe51..e125d8401 100644 --- a/apps/app/components/analytics/select/segment.tsx +++ b/apps/app/components/analytics/select/segment.tsx @@ -23,7 +23,7 @@ export const SelectSegment: React.FC = ({ value, onChange, params }) => { label={ {ANALYTICS_X_AXIS_VALUES.find((v) => v.value === value)?.label ?? ( - No value + No value )} } diff --git a/apps/app/components/auth-screens/not-authorized-view.tsx b/apps/app/components/auth-screens/not-authorized-view.tsx index d76e56b61..f0917a640 100644 --- a/apps/app/components/auth-screens/not-authorized-view.tsx +++ b/apps/app/components/auth-screens/not-authorized-view.tsx @@ -22,7 +22,7 @@ export const NotAuthorizedView: React.FC = ({ actionButton, type }) => { return ( -
+
= ({ actionButton, type }) => { alt="ProjectSettingImg" />
-

+

Oops! You are not authorized to view this page

-
+
{user ? (

You have signed in as {user.email}.
- Sign in + Sign in {" "} with different account that has access to this page.

@@ -48,7 +48,7 @@ export const NotAuthorizedView: React.FC = ({ actionButton, type }) => {

You need to{" "} - Sign in + Sign in {" "} with an account that has access to this page.

diff --git a/apps/app/components/auth-screens/project/join-project.tsx b/apps/app/components/auth-screens/project/join-project.tsx index 06ae1c240..854773632 100644 --- a/apps/app/components/auth-screens/project/join-project.tsx +++ b/apps/app/components/auth-screens/project/join-project.tsx @@ -41,13 +41,15 @@ export const JoinProject: React.FC = () => { }; return ( -
+
JoinProject
-

You are not a member of this project

+

+ You are not a member of this project +

-
+

You are not a member of this project, but you can join this project by clicking the button below. diff --git a/apps/app/components/auth-screens/workspace/not-a-member.tsx b/apps/app/components/auth-screens/workspace/not-a-member.tsx index 12bb3d850..ee63b5883 100644 --- a/apps/app/components/auth-screens/workspace/not-a-member.tsx +++ b/apps/app/components/auth-screens/workspace/not-a-member.tsx @@ -11,7 +11,7 @@ export const NotAWorkspaceMember = () => (

Not Authorized!

-

+

You{"'"}re not a member of this workspace. Please contact the workspace admin to get an invitation or check your pending invitations.

diff --git a/apps/app/components/breadcrumbs/index.tsx b/apps/app/components/breadcrumbs/index.tsx index 6e2c85785..893d6fde1 100644 --- a/apps/app/components/breadcrumbs/index.tsx +++ b/apps/app/components/breadcrumbs/index.tsx @@ -17,12 +17,12 @@ const Breadcrumbs = ({ children }: BreadcrumbsProps) => {
{children} @@ -41,7 +41,7 @@ const BreadcrumbItem: React.FC = ({ title, link, icon }) => <> {link ? ( - +

{icon ?? null} {title} diff --git a/apps/app/components/command-palette/change-interface-theme.tsx b/apps/app/components/command-palette/change-interface-theme.tsx index f4bcd7483..b2b43c670 100644 --- a/apps/app/components/command-palette/change-interface-theme.tsx +++ b/apps/app/components/command-palette/change-interface-theme.tsx @@ -34,8 +34,8 @@ export const ChangeInterfaceTheme: React.FC = ({ setIsPaletteOpen }) => { }} className="focus:outline-none" > -

- +
+ {theme.label}
diff --git a/apps/app/components/command-palette/command-pallette.tsx b/apps/app/components/command-palette/command-pallette.tsx index 32634f18c..244265ff5 100644 --- a/apps/app/components/command-palette/command-pallette.tsx +++ b/apps/app/components/command-palette/command-pallette.tsx @@ -408,7 +408,7 @@ export const CommandPalette: React.FC = () => { leaveFrom="opacity-100" leaveTo="opacity-0" > -
+
@@ -421,7 +421,7 @@ export const CommandPalette: React.FC = () => { leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - + { if (value.toLowerCase().includes(search.toLowerCase())) return 1; @@ -444,7 +444,7 @@ export const CommandPalette: React.FC = () => { > {issueId && issueDetails && (
-

+

{issueDetails.project_detail?.identifier}-{issueDetails.sequence_id}{" "} {issueDetails?.name}

@@ -452,11 +452,11 @@ export const CommandPalette: React.FC = () => { )}
+
No results found.
)} @@ -533,9 +533,9 @@ export const CommandPalette: React.FC = () => { value={value} className="focus:outline-none" > -
+

{item.name}

@@ -562,8 +562,8 @@ export const CommandPalette: React.FC = () => { }} className="focus:outline-none" > -
- +
+ Change state...
@@ -575,8 +575,8 @@ export const CommandPalette: React.FC = () => { }} className="focus:outline-none" > -
- +
+ Change priority...
@@ -588,8 +588,8 @@ export const CommandPalette: React.FC = () => { }} className="focus:outline-none" > -
- +
+ Assign to...
@@ -600,15 +600,15 @@ export const CommandPalette: React.FC = () => { }} className="focus:outline-none" > -
+
{issueDetails?.assignees.includes(user.id) ? ( <> - + Un-assign from me ) : ( <> - + Assign to me )} @@ -616,8 +616,8 @@ export const CommandPalette: React.FC = () => { -
- +
+ Delete issue
@@ -628,8 +628,8 @@ export const CommandPalette: React.FC = () => { }} className="focus:outline-none" > -
- +
+ Copy issue URL to clipboard
@@ -638,9 +638,9 @@ export const CommandPalette: React.FC = () => { -
+
Create new issue
@@ -654,7 +654,7 @@ export const CommandPalette: React.FC = () => { onSelect={createNewProject} className="focus:outline-none" > -
+
Create new project
@@ -670,7 +670,7 @@ export const CommandPalette: React.FC = () => { onSelect={createNewCycle} className="focus:outline-none" > -
+
Create new cycle
@@ -683,7 +683,7 @@ export const CommandPalette: React.FC = () => { onSelect={createNewModule} className="focus:outline-none" > -
+
Create new module
@@ -693,7 +693,7 @@ export const CommandPalette: React.FC = () => { -
+
Create new view
@@ -703,7 +703,7 @@ export const CommandPalette: React.FC = () => { -
+
Create new page
@@ -721,7 +721,7 @@ export const CommandPalette: React.FC = () => { } className="focus:outline-none" > -
+
Open inbox
@@ -740,7 +740,7 @@ export const CommandPalette: React.FC = () => { }} className="focus:outline-none" > -
+
Search settings...
@@ -751,8 +751,8 @@ export const CommandPalette: React.FC = () => { onSelect={createNewWorkspace} className="focus:outline-none" > -
- +
+ Create new workspace
@@ -764,8 +764,8 @@ export const CommandPalette: React.FC = () => { }} className="focus:outline-none" > -
- +
+ Change interface theme...
@@ -781,8 +781,8 @@ export const CommandPalette: React.FC = () => { }} className="focus:outline-none" > -
- +
+ Open keyboard shortcuts
@@ -793,8 +793,8 @@ export const CommandPalette: React.FC = () => { }} className="focus:outline-none" > -
- +
+ Open Plane documentation
@@ -805,7 +805,7 @@ export const CommandPalette: React.FC = () => { }} className="focus:outline-none" > -
+
Join our Discord
@@ -820,7 +820,7 @@ export const CommandPalette: React.FC = () => { }} className="focus:outline-none" > -
+
Report a bug
@@ -832,8 +832,8 @@ export const CommandPalette: React.FC = () => { }} className="focus:outline-none" > -
- +
+ Chat with us
@@ -847,8 +847,8 @@ export const CommandPalette: React.FC = () => { onSelect={() => redirect(`/${workspaceSlug}/settings`)} className="focus:outline-none" > -
- +
+ General
@@ -856,8 +856,8 @@ export const CommandPalette: React.FC = () => { onSelect={() => redirect(`/${workspaceSlug}/settings/members`)} className="focus:outline-none" > -
- +
+ Members
@@ -865,8 +865,8 @@ export const CommandPalette: React.FC = () => { onSelect={() => redirect(`/${workspaceSlug}/settings/billing`)} className="focus:outline-none" > -
- +
+ Billing and Plans
@@ -874,8 +874,8 @@ export const CommandPalette: React.FC = () => { onSelect={() => redirect(`/${workspaceSlug}/settings/integrations`)} className="focus:outline-none" > -
- +
+ Integrations
@@ -883,8 +883,8 @@ export const CommandPalette: React.FC = () => { onSelect={() => redirect(`/${workspaceSlug}/settings/import-export`)} className="focus:outline-none" > -
- +
+ Import/Export
diff --git a/apps/app/components/command-palette/shortcuts-modal.tsx b/apps/app/components/command-palette/shortcuts-modal.tsx index 8f946f5ea..339d3695e 100644 --- a/apps/app/components/command-palette/shortcuts-modal.tsx +++ b/apps/app/components/command-palette/shortcuts-modal.tsx @@ -85,29 +85,29 @@ export const ShortcutsModal: React.FC = ({ isOpen, setIsOpen }) => { leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - -
+ +
Keyboard Shortcuts
-
- +
+ = ({ isOpen, setIsOpen }) => {
-

+

{shortcut.description}

{shortcut.keys.split(",").map((key, index) => ( {key === "Ctrl" ? ( - - + + ) : key === "Ctrl" ? ( - - + + ) : ( - + {key} )} @@ -151,7 +151,7 @@ export const ShortcutsModal: React.FC = ({ isOpen, setIsOpen }) => { )) ) : (
-

+

No shortcuts found for{" "} {`"`} @@ -168,20 +168,20 @@ export const ShortcutsModal: React.FC = ({ isOpen, setIsOpen }) => {

{shortcuts.map(({ keys, description }, index) => (
-

{description}

+

{description}

{keys.split(",").map((key, index) => ( {key === "Ctrl" ? ( - - + + ) : key === "Ctrl" ? ( - - + + ) : ( - + {key} )} diff --git a/apps/app/components/core/board-view/all-boards.tsx b/apps/app/components/core/board-view/all-boards.tsx index 711fb7336..7b5d1e527 100644 --- a/apps/app/components/core/board-view/all-boards.tsx +++ b/apps/app/components/core/board-view/all-boards.tsx @@ -85,7 +85,7 @@ export const AllBoards: React.FC = ({ return (
{currentState && @@ -96,7 +96,7 @@ export const AllBoards: React.FC = ({ : addSpaceIfCamelCase(singleGroup)}
- 0 + 0
); })} diff --git a/apps/app/components/core/board-view/board-header.tsx b/apps/app/components/core/board-view/board-header.tsx index 880a6b56b..38cb8fa87 100644 --- a/apps/app/components/core/board-view/board-header.tsx +++ b/apps/app/components/core/board-view/board-header.tsx @@ -113,7 +113,7 @@ export const BoardHeader: React.FC = ({ return (
@@ -134,7 +134,7 @@ export const BoardHeader: React.FC = ({ {groupedByIssues?.[groupTitle].length ?? 0} @@ -144,7 +144,7 @@ export const BoardHeader: React.FC = ({
))}
-
+
{MONTHS_LIST.map((month) => (
diff --git a/apps/app/components/core/calendar-view/single-issue.tsx b/apps/app/components/core/calendar-view/single-issue.tsx index 31cbf139c..7c5c89afa 100644 --- a/apps/app/components/core/calendar-view/single-issue.tsx +++ b/apps/app/components/core/calendar-view/single-issue.tsx @@ -163,8 +163,8 @@ export const SingleCalendarIssue: React.FC = ({ ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} - className={`w-full relative cursor-pointer rounded border border-brand-base px-1.5 py-1.5 text-xs duration-300 hover:cursor-move hover:bg-brand-surface-2 ${ - snapshot.isDragging ? "bg-brand-surface-2 shadow-lg" : "" + className={`w-full relative cursor-pointer rounded border border-custom-border-100 px-1.5 py-1.5 text-xs duration-300 hover:cursor-move hover:bg-custom-background-80 ${ + snapshot.isDragging ? "bg-custom-background-80 shadow-lg" : "" }`} >
@@ -199,13 +199,13 @@ export const SingleCalendarIssue: React.FC = ({ tooltipHeading="Issue ID" tooltipContent={`${issue.project_detail?.identifier}-${issue.sequence_id}`} > - + {issue.project_detail?.identifier}-{issue.sequence_id} )} - {truncateText(issue.name, 25)} + {truncateText(issue.name, 25)} @@ -267,9 +267,9 @@ export const SingleCalendarIssue: React.FC = ({ /> )} {properties.sub_issue_count && ( -
+
-
+
{issue.sub_issues_count}
@@ -277,9 +277,9 @@ export const SingleCalendarIssue: React.FC = ({
)} {properties.link && ( -
+
-
+
{issue.link_count}
@@ -287,9 +287,9 @@ export const SingleCalendarIssue: React.FC = ({
)} {properties.attachment_count && ( -
+
-
+
{issue.attachment_count}
diff --git a/apps/app/components/core/custom-theme-selector.tsx b/apps/app/components/core/custom-theme-selector.tsx deleted file mode 100644 index 59aed8b2b..000000000 --- a/apps/app/components/core/custom-theme-selector.tsx +++ /dev/null @@ -1,198 +0,0 @@ -import React, { useEffect, useState } from "react"; - -import { useTheme } from "next-themes"; - -import { useForm } from "react-hook-form"; - -// hooks -import useUser from "hooks/use-user"; -// ui -import { PrimaryButton } from "components/ui"; -import { ColorPickerInput } from "components/core"; -// services -import userService from "services/user.service"; -// helper -import { applyTheme } from "helpers/theme.helper"; -// types -import { ICustomTheme } from "types"; - -type Props = { - preLoadedData?: Partial | null; -}; - -export const CustomThemeSelector: React.FC = ({ preLoadedData }) => { - const [darkPalette, setDarkPalette] = useState(false); - - const defaultValues = { - accent: preLoadedData?.accent ?? "#FE5050", - bgBase: preLoadedData?.bgBase ?? "#FFF7F7", - bgSurface1: preLoadedData?.bgSurface1 ?? "#FFE0E0", - bgSurface2: preLoadedData?.bgSurface2 ?? "#FFF7F7", - border: preLoadedData?.border ?? "#FFC9C9", - darkPalette: preLoadedData?.darkPalette ?? false, - palette: preLoadedData?.palette ?? "", - sidebar: preLoadedData?.sidebar ?? "#FFFFFF", - textBase: preLoadedData?.textBase ?? "#430000", - textSecondary: preLoadedData?.textSecondary ?? "#323232", - }; - - const { - register, - formState: { errors, isSubmitting }, - handleSubmit, - watch, - setValue, - reset, - } = useForm({ - defaultValues, - }); - - const { setTheme } = useTheme(); - const { mutateUser } = useUser(); - - const handleFormSubmit = async (formData: any) => { - await userService - .updateUser({ - theme: { - accent: formData.accent, - bgBase: formData.bgBase, - bgSurface1: formData.bgSurface1, - bgSurface2: formData.bgSurface2, - border: formData.border, - darkPalette: darkPalette, - palette: `${formData.bgBase},${formData.bgSurface1},${formData.bgSurface2},${formData.border},${formData.sidebar},${formData.accent},${formData.textBase},${formData.textSecondary}`, - sidebar: formData.sidebar, - textBase: formData.textBase, - textSecondary: formData.textSecondary, - }, - }) - .then((res) => { - mutateUser((prevData) => { - if (!prevData) return prevData; - return { ...prevData, user: res }; - }, false); - applyTheme(formData.palette, darkPalette); - setTheme("custom"); - }) - .catch((err) => console.log(err)); - }; - - const handleUpdateTheme = async (formData: any) => { - await handleFormSubmit({ ...formData, darkPalette }); - - reset({ - ...defaultValues, - }); - }; - - useEffect(() => { - reset({ - ...defaultValues, - ...preLoadedData, - }); - }, [preLoadedData, reset]); - - return ( - -
-

Customize your theme

-
-
-
-

Background

- -
- -
-

Background surface 1

- -
- -
-

Background surface 2

- -
- -
-

Border

- -
- -
-

Sidebar

- -
- -
-

Accent

- -
- -
-

Text primary

- -
- -
-

Text secondary

- -
-
-
-
-
- - {isSubmitting ? "Creating Theme..." : "Set Theme"} - -
- - ); -}; diff --git a/apps/app/components/core/feeds.tsx b/apps/app/components/core/feeds.tsx index d00804ec8..bc915d294 100644 --- a/apps/app/components/core/feeds.tsx +++ b/apps/app/components/core/feeds.tsx @@ -55,55 +55,55 @@ const activityDetails: { }, modules: { message: "set the module to", - icon:
)} - + @@ -234,7 +234,7 @@ export const Feeds: React.FC = ({ activities }) => ( {activity.actor_detail.first_name} {activity.actor_detail.is_bot ? "Bot" : " " + activity.actor_detail.last_name}
-

+

Commented {timeAgo(activity.created_at)}

@@ -247,7 +247,7 @@ export const Feeds: React.FC = ({ activities }) => ( } editable={false} noBorder - customClassName="text-xs border border-brand-base bg-brand-base" + customClassName="text-xs border border-custom-border-100 bg-custom-background-100" />
@@ -262,7 +262,7 @@ export const Feeds: React.FC = ({ activities }) => (
{activities.length > 1 && activityIdx !== activities.length - 1 ? (
-
+
{activity.field ? ( activityDetails[activity.field as keyof typeof activityDetails]?.icon ) : activity.actor_detail.avatar && @@ -295,7 +295,7 @@ export const Feeds: React.FC = ({ activities }) => (
-
+
{activity.actor_detail.first_name} {activity.actor_detail.is_bot @@ -303,7 +303,7 @@ export const Feeds: React.FC = ({ activities }) => ( : " " + activity.actor_detail.last_name} {action} - {value} + {value} {timeAgo(activity.created_at)}
diff --git a/apps/app/components/core/filters/due-date-filter-modal.tsx b/apps/app/components/core/filters/due-date-filter-modal.tsx index 6c6bc4ec6..e3a24a7b1 100644 --- a/apps/app/components/core/filters/due-date-filter-modal.tsx +++ b/apps/app/components/core/filters/due-date-filter-modal.tsx @@ -96,7 +96,7 @@ export const DueDateFilterModal: React.FC = ({ isOpen, handleClose }) => leaveFrom="opacity-100" leaveTo="opacity-0" > -
+
@@ -109,7 +109,7 @@ export const DueDateFilterModal: React.FC = ({ isOpen, handleClose }) => leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - +
= ({ isOpen, handleClose }) =>
{watch("filterType") === "range" && (
- After: + After: {renderShortDateWithYearFormat(watch("date1"))} - Before: + Before: {!isInvalid && {renderShortDateWithYearFormat(watch("date2"))}}
)} diff --git a/apps/app/components/core/filters/filters-list.tsx b/apps/app/components/core/filters/filters-list.tsx index 7254f8072..2e895e5e4 100644 --- a/apps/app/components/core/filters/filters-list.tsx +++ b/apps/app/components/core/filters/filters-list.tsx @@ -58,9 +58,9 @@ export const FilterList: React.FC = ({ filters, setFilters }) => { return (
- + {key === "target_date" ? "Due Date" : replaceUnderscoreIfSnakeCase(key)}: {filters[key as keyof IIssueFilterOptions] === null || @@ -132,7 +132,7 @@ export const FilterList: React.FC = ({ filters, setFilters }) => { ? "bg-yellow-500/20 text-yellow-500" : priority === "low" ? "bg-green-500/20 text-green-500" - : "bg-brand-surface-1 text-brand-secondary" + : "bg-custom-background-90 text-custom-text-200" }`} > {getPriorityIcon(priority)} @@ -171,7 +171,7 @@ export const FilterList: React.FC = ({ filters, setFilters }) => { return (
{member?.first_name} @@ -212,7 +212,7 @@ export const FilterList: React.FC = ({ filters, setFilters }) => { return (
{member?.first_name} @@ -310,7 +310,7 @@ export const FilterList: React.FC = ({ filters, setFilters }) => { return (
@@ -381,7 +381,7 @@ export const FilterList: React.FC = ({ filters, setFilters }) => { target_date: null, }) } - className="flex items-center gap-x-1 rounded-full border border-brand-base bg-brand-surface-2 px-3 py-1.5 text-xs" + className="flex items-center gap-x-1 rounded-full border border-custom-border-100 bg-custom-background-80 px-3 py-1.5 text-xs" > Clear all filters diff --git a/apps/app/components/core/filters/issues-view-filter.tsx b/apps/app/components/core/filters/issues-view-filter.tsx index 67b2423ec..8b625fbcf 100644 --- a/apps/app/components/core/filters/issues-view-filter.tsx +++ b/apps/app/components/core/filters/issues-view-filter.tsx @@ -23,10 +23,33 @@ import { import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper"; import { checkIfArraysHaveSameElements } from "helpers/array.helper"; // types -import { Properties } from "types"; +import { Properties, TIssueViewOptions } from "types"; // constants import { GROUP_BY_OPTIONS, ORDER_BY_OPTIONS, FILTER_ISSUE_OPTIONS } from "constants/issue"; +const issueViewOptions: { type: TIssueViewOptions; icon: any }[] = [ + { + type: "list", + icon: , + }, + { + type: "kanban", + icon: , + }, + { + type: "calendar", + icon: , + }, + { + type: "spreadsheet", + icon: , + }, + { + type: "gantt_chart", + icon: , + }, +]; + export const IssuesFilterView: React.FC = () => { const router = useRouter(); const { workspaceSlug, projectId, viewId } = router.query; @@ -56,53 +79,20 @@ export const IssuesFilterView: React.FC = () => { return (
- - - - - + {issueViewOptions.map((option) => ( + + ))}
{ {({ open }) => ( <> View @@ -163,13 +155,13 @@ export const IssuesFilterView: React.FC = () => { leaveFrom="opacity-100 translate-y-0" leaveTo="opacity-0 translate-y-1" > - -
+ +
{issueView !== "calendar" && issueView !== "spreadsheet" && ( <>
-

Group by

+

Group by

option.key === groupByProperty) @@ -190,7 +182,7 @@ export const IssuesFilterView: React.FC = () => {
-

Order by

+

Order by

option.key === orderBy)?.name ?? @@ -215,7 +207,7 @@ export const IssuesFilterView: React.FC = () => { )}
-

Issue type

+

Issue type

option.key === filters.type) @@ -241,7 +233,7 @@ export const IssuesFilterView: React.FC = () => { {issueView !== "calendar" && issueView !== "spreadsheet" && ( <>
-

Show empty states

+

Show empty states

setShowEmptyGroups(!showEmptyGroups)} @@ -253,7 +245,7 @@ export const IssuesFilterView: React.FC = () => {
-

Display Properties

+

Display Properties

{Object.keys(properties).map((key) => { if (key === "estimate" && !isEstimateActive) return null; @@ -289,8 +281,8 @@ export const IssuesFilterView: React.FC = () => { type="button" className={`rounded border px-2 py-1 text-xs capitalize ${ properties[key as keyof Properties] - ? "border-brand-accent bg-brand-accent text-white" - : "border-brand-base" + ? "border-custom-primary bg-custom-primary text-white" + : "border-custom-border-100" }`} onClick={() => setProperties(key as keyof Properties)} > diff --git a/apps/app/components/core/image-picker-popover.tsx b/apps/app/components/core/image-picker-popover.tsx index 380c6f356..0bc64142d 100644 --- a/apps/app/components/core/image-picker-popover.tsx +++ b/apps/app/components/core/image-picker-popover.tsx @@ -62,7 +62,7 @@ export const ImagePickerPopover: React.FC = ({ label, value, onChange }) return ( setIsOpen((prev) => !prev)} > {label} @@ -76,16 +76,16 @@ export const ImagePickerPopover: React.FC = ({ label, value, onChange }) leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > - -
+ +
- + {tabOptions.map((tab) => ( `rounded py-1 px-4 text-center text-sm outline-none transition-colors ${ - selected ? "bg-brand-accent text-white" : "text-brand-base" + selected ? "bg-custom-primary text-white" : "text-custom-text-100" }` } > diff --git a/apps/app/components/core/index.ts b/apps/app/components/core/index.ts index 1eb52590c..b91944abf 100644 --- a/apps/app/components/core/index.ts +++ b/apps/app/components/core/index.ts @@ -5,10 +5,8 @@ export * from "./gantt-chart-view"; export * from "./list-view"; export * from "./modals"; export * from "./spreadsheet-view"; +export * from "./theme"; export * from "./sidebar"; export * from "./issues-view"; export * from "./image-picker-popover"; export * from "./feeds"; -export * from "./theme-switch"; -export * from "./custom-theme-selector"; -export * from "./color-picker-input"; diff --git a/apps/app/components/core/issues-view.tsx b/apps/app/components/core/issues-view.tsx index 7a8c8960f..b53553c9f 100644 --- a/apps/app/components/core/issues-view.tsx +++ b/apps/app/components/core/issues-view.tsx @@ -29,19 +29,13 @@ import { } from "components/core"; import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues"; import { CreateUpdateViewModal } from "components/views"; -import { CycleIssuesGanttChartView, TransferIssues, TransferIssuesModal } from "components/cycles"; -import { IssueGanttChartView } from "components/issues/gantt-chart"; +import { TransferIssues, TransferIssuesModal } from "components/cycles"; // ui -import { EmptySpace, EmptySpaceItem, EmptyState, PrimaryButton, Spinner } from "components/ui"; +import { EmptyState, PrimaryButton, Spinner } from "components/ui"; // icons -import { - ListBulletIcon, - PlusIcon, - RectangleStackIcon, - TrashIcon, -} from "@heroicons/react/24/outline"; +import { PlusIcon, TrashIcon } from "@heroicons/react/24/outline"; // images -import emptyIssue from "public/empty-state/empty-issue.svg"; +import emptyIssue from "public/empty-state/issue.svg"; // helpers import { getStatesList } from "helpers/state.helper"; import { orderArrayBy } from "helpers/array.helper"; @@ -56,7 +50,6 @@ import { PROJECT_ISSUES_LIST_WITH_PARAMS, STATES_LIST, } from "constants/fetch-keys"; -import { ModuleIssuesGanttChartView } from "components/modules"; type Props = { type?: "issue" | "cycle" | "module"; @@ -107,7 +100,7 @@ export const IssuesView: React.FC = ({ groupByProperty: selectedGroup, orderBy, filters, - isNotEmpty, + isEmpty, setFilters, params, } = useIssuesView(); @@ -495,7 +488,7 @@ export const IssuesView: React.FC = ({ {viewId ? "Update" : "Save"} view
- {
} + {
} )} @@ -505,7 +498,7 @@ export const IssuesView: React.FC = ({
= ({ )} {groupedByIssues ? ( - isNotEmpty ? ( + !isEmpty || issueView === "kanban" || issueView === "calendar" ? ( <> {isCompleted && setTransferIssuesModal(true)} />} {issueView === "list" ? ( @@ -584,46 +577,20 @@ export const IssuesView: React.FC = ({ issueView === "gantt_chart" && )} - ) : type === "issue" ? ( - ) : ( -
- - - Use
C
{" "} - shortcut to create a new issue - - } - Icon={PlusIcon} - action={() => { - const e = new KeyboardEvent("keydown", { - key: "c", - }); - document.dispatchEvent(e); - }} - /> - {openIssuesListModal && ( - - )} -
-
+ } + onClick={() => { + const e = new KeyboardEvent("keydown", { + key: "c", + }); + document.dispatchEvent(e); + }} + /> ) ) : (
diff --git a/apps/app/components/core/list-view/single-issue.tsx b/apps/app/components/core/list-view/single-issue.tsx index 774fbb02d..686151243 100644 --- a/apps/app/components/core/list-view/single-issue.tsx +++ b/apps/app/components/core/list-view/single-issue.tsx @@ -218,7 +218,7 @@ export const SingleListIssue: React.FC = ({
{ e.preventDefault(); setContextMenu(true); @@ -233,13 +233,13 @@ export const SingleListIssue: React.FC = ({ tooltipHeading="Issue ID" tooltipContent={`${issue.project_detail?.identifier}-${issue.sequence_id}`} > - + {issue.project_detail?.identifier}-{issue.sequence_id} )} - + {truncateText(issue.name, 50)} @@ -302,9 +302,9 @@ export const SingleListIssue: React.FC = ({ /> )} {properties.sub_issue_count && ( -
+
-
+
{issue.sub_issues_count}
@@ -312,9 +312,9 @@ export const SingleListIssue: React.FC = ({
)} {properties.link && ( -
+
-
+
{issue.link_count}
@@ -322,9 +322,9 @@ export const SingleListIssue: React.FC = ({
)} {properties.attachment_count && ( -
+
-
+
{issue.attachment_count}
diff --git a/apps/app/components/core/list-view/single-list.tsx b/apps/app/components/core/list-view/single-list.tsx index b76f3ad8a..4ea1be2f3 100644 --- a/apps/app/components/core/list-view/single-list.tsx +++ b/apps/app/components/core/list-view/single-list.tsx @@ -141,20 +141,20 @@ export const SingleList: React.FC = ({ {({ open }) => (
-
+
{selectedGroup !== null && (
{getGroupIcon()}
)} {selectedGroup !== null ? ( -

+

{getGroupTitle()}

) : (

All Issues

)} - + {groupedByIssues[groupTitle as keyof IIssue].length}
@@ -162,7 +162,7 @@ export const SingleList: React.FC = ({ {type === "issue" ? (
))}
) : ( -
+
No issues selected
)} @@ -208,9 +208,9 @@ export const ExistingIssuesListModal: React.FC = ({ {debouncedSearchTerm !== "" && ( -
+
Search results for{" "} - + {'"'} {debouncedSearchTerm} {'"'} @@ -225,9 +225,9 @@ export const ExistingIssuesListModal: React.FC = ({ debouncedSearchTerm !== "" && (
-

+

No issues found. Create a new issue with{" "} -
+                            
                               C
                             
. @@ -243,7 +243,9 @@ export const ExistingIssuesListModal: React.FC = ({ ) : ( -

-
+
{renderShortDateWithYearFormat(service.created_at)}| Imported by{" "} diff --git a/apps/app/components/integration/single-integration-card.tsx b/apps/app/components/integration/single-integration-card.tsx index f6ae65b12..8d1d480f0 100644 --- a/apps/app/components/integration/single-integration-card.tsx +++ b/apps/app/components/integration/single-integration-card.tsx @@ -99,7 +99,7 @@ export const SingleIntegrationCard: React.FC = ({ integration }) => { ); return ( -
+
= ({ integration }) => { Installed ) : ( - - Not - Installed + + {" "} + Not Installed ) ) : null}
-

+

{workspaceIntegrations ? isInstalled ? integrationDetails[integration.provider].installed diff --git a/apps/app/components/issues/activity.tsx b/apps/app/components/issues/activity.tsx index e30f00b0b..baa860660 100644 --- a/apps/app/components/issues/activity.tsx +++ b/apps/app/components/issues/activity.tsx @@ -61,54 +61,54 @@ const activityDetails: { }, estimate_point: { message: "set the estimate point to", - icon:

{issueActivities.length > 1 && activityItemIdx !== issueActivities.length - 1 ? (
-
+
{activityItem.field ? ( activityDetails[activityItem.field as keyof typeof activityDetails] ?.icon @@ -368,7 +368,7 @@ export const IssueActivitySection: React.FC = ({ issueId, user }) => {
-
+
{activityItem.actor_detail.first_name} {activityItem.actor_detail.is_bot @@ -376,7 +376,10 @@ export const IssueActivitySection: React.FC = ({ issueId, user }) => { : " " + activityItem.actor_detail.last_name} {action} - {value} + + {" "} + {value}{" "} + {timeAgo(activityItem.created_at)} diff --git a/apps/app/components/issues/attachment-upload.tsx b/apps/app/components/issues/attachment-upload.tsx index 7e5184ce8..5eb5f76e3 100644 --- a/apps/app/components/issues/attachment-upload.tsx +++ b/apps/app/components/issues/attachment-upload.tsx @@ -85,8 +85,8 @@ export const IssueAttachmentUpload = () => { return (
diff --git a/apps/app/components/issues/attachments.tsx b/apps/app/components/issues/attachments.tsx index 7f4be47dd..6d56264e5 100644 --- a/apps/app/components/issues/attachments.tsx +++ b/apps/app/components/issues/attachments.tsx @@ -61,7 +61,7 @@ export const IssueAttachments = () => { attachments.map((file) => ( diff --git a/apps/app/components/issues/comment/comment-card.tsx b/apps/app/components/issues/comment/comment-card.tsx index 72f6fcae6..a90c7ff47 100644 --- a/apps/app/components/issues/comment/comment-card.tsx +++ b/apps/app/components/issues/comment/comment-card.tsx @@ -72,7 +72,7 @@ export const CommentCard: React.FC = ({ comment, onSubmit, handleCommentD alt={comment.actor_detail.first_name} height={30} width={30} - className="grid h-7 w-7 place-items-center rounded-full border-2 border-brand-base" + className="grid h-7 w-7 place-items-center rounded-full border-2 border-custom-border-100" /> ) : (
= ({ comment, onSubmit, handleCommentD
)} - + @@ -95,7 +95,7 @@ export const CommentCard: React.FC = ({ comment, onSubmit, handleCommentD {comment.actor_detail.first_name} {comment.actor_detail.is_bot ? "Bot" : " " + comment.actor_detail.last_name}
-

+

Commented {timeAgo(comment.created_at)}

@@ -135,7 +135,7 @@ export const CommentCard: React.FC = ({ comment, onSubmit, handleCommentD value={comment.comment_html} editable={false} noBorder - customClassName="text-xs border border-brand-base bg-brand-base" + customClassName="text-xs border border-custom-border-100 bg-custom-background-100" ref={showEditorRef} />
diff --git a/apps/app/components/issues/delete-attachment-modal.tsx b/apps/app/components/issues/delete-attachment-modal.tsx index 85450809a..0ea0f9684 100644 --- a/apps/app/components/issues/delete-attachment-modal.tsx +++ b/apps/app/components/issues/delete-attachment-modal.tsx @@ -75,7 +75,7 @@ export const DeleteAttachmentModal: React.FC = ({ isOpen, setIsOpen, data leaveFrom="opacity-100" leaveTo="opacity-0" > -
+
@@ -89,8 +89,8 @@ export const DeleteAttachmentModal: React.FC = ({ isOpen, setIsOpen, data leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - -
+ +
= ({ isOpen, setIsOpen, data
Delete Attachment
-

+

Are you sure you want to delete attachment-{" "} {getFileName(data.attributes.name)}? This attachment will be permanently removed. This action cannot be @@ -116,7 +116,7 @@ export const DeleteAttachmentModal: React.FC = ({ isOpen, setIsOpen, data

-
+
Cancel { diff --git a/apps/app/components/issues/delete-issue-modal.tsx b/apps/app/components/issues/delete-issue-modal.tsx index c4fb3b00a..cbda250fe 100644 --- a/apps/app/components/issues/delete-issue-modal.tsx +++ b/apps/app/components/issues/delete-issue-modal.tsx @@ -138,7 +138,7 @@ export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data, u leaveFrom="opacity-100" leaveTo="opacity-0" > -
+
@@ -152,7 +152,7 @@ export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data, u leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - +
@@ -166,9 +166,9 @@ export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data, u
-

+

Are you sure you want to delete issue{" "} - + {data?.project_detail.identifier}-{data?.sequence_id} {""}? All of the data related to the issue will be permanently removed. This diff --git a/apps/app/components/issues/description-form.tsx b/apps/app/components/issues/description-form.tsx index 492110a8c..0770834fa 100644 --- a/apps/app/components/issues/description-form.tsx +++ b/apps/app/components/issues/description-form.tsx @@ -105,14 +105,12 @@ export const IssueDescriptionForm: FC = ({ }); }} required={true} - className="min-h-10 block w-full resize-none - overflow-hidden rounded border-none bg-transparent - px-3 py-2 text-xl outline-none ring-0 focus:ring-1 focus:ring-theme" + className="min-h-10 block w-full resize-none overflow-hidden rounded border-none bg-transparent px-3 py-2 text-xl outline-none ring-0 focus:ring-1 focus:ring-custom-primary" role="textbox" disabled={!isAllowed} /> {characterLimit && ( -

+
255 ? "text-red-500" : "" @@ -166,7 +164,7 @@ export const IssueDescriptionForm: FC = ({ }} />
diff --git a/apps/app/components/issues/form.tsx b/apps/app/components/issues/form.tsx index 8bf64e6ff..a06b1d7cd 100644 --- a/apps/app/components/issues/form.tsx +++ b/apps/app/components/issues/form.tsx @@ -273,14 +273,14 @@ export const IssueForm: FC = ({ )} /> )} -

+

{status ? "Update" : "Create"} Issue

{watch("parent") && watch("parent") !== "" && (fieldsToShow.includes("all") || fieldsToShow.includes("parent")) && ( -
+
= ({ .color, }} /> - + {/* {projects?.find((p) => p.id === projectId)?.identifier}- */} {issues.find((i) => i.id === watch("parent"))?.sequence_id} @@ -326,7 +326,7 @@ export const IssueForm: FC = ({ /> {mostSimilarIssue && (
-

+

@@ -342,7 +342,7 @@ export const IssueForm: FC = ({

-
+
setCreateMore((prevData) => !prevData)} diff --git a/apps/app/components/issues/gantt-chart.tsx b/apps/app/components/issues/gantt-chart.tsx index 571583707..533badd7d 100644 --- a/apps/app/components/issues/gantt-chart.tsx +++ b/apps/app/components/issues/gantt-chart.tsx @@ -27,7 +27,7 @@ export const IssueGanttChartView: FC = ({}) => { className="rounded-sm flex-shrink-0 w-[10px] h-[10px] flex justify-center items-center" style={{ backgroundColor: data?.state_detail?.color || "#858e96" }} /> -
{data?.name}
+
{data?.name}
); @@ -40,7 +40,7 @@ export const IssueGanttChartView: FC = ({}) => { style={{ backgroundColor: data?.state_detail?.color || "#858e96" }} /> -
+
{data?.name}
@@ -50,7 +50,7 @@ export const IssueGanttChartView: FC = ({}) => { className={`z-[999999]`} >
- + info
diff --git a/apps/app/components/issues/main-content.tsx b/apps/app/components/issues/main-content.tsx index 6123556a5..9eb351c8b 100644 --- a/apps/app/components/issues/main-content.tsx +++ b/apps/app/components/issues/main-content.tsx @@ -53,9 +53,9 @@ export const IssueMainContent: React.FC = ({ issueDetails, submitChanges <>
{issueDetails?.parent && issueDetails.parent !== "" ? ( -
-

Comments/Activity

+

Comments/Activity

diff --git a/apps/app/components/issues/modal.tsx b/apps/app/components/issues/modal.tsx index b83bbc480..b0b0a8e20 100644 --- a/apps/app/components/issues/modal.tsx +++ b/apps/app/components/issues/modal.tsx @@ -188,7 +188,7 @@ export const CreateUpdateIssueModal: React.FC = ({ payload, user ) - .then((res) => { + .then(() => { setToastAlert({ type: "success", title: "Success!", @@ -323,7 +323,7 @@ export const CreateUpdateIssueModal: React.FC = ({ return ( - {}}> + handleClose()}> = ({ leaveFrom="opacity-100" leaveTo="opacity-0" > -
+
@@ -347,7 +347,7 @@ export const CreateUpdateIssueModal: React.FC = ({ leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - + = ({ issue, properties, projectId const isNotAllowed = false; return ( -
+
@@ -96,13 +96,13 @@ export const MyIssuesListItem: React.FC = ({ issue, properties, projectId tooltipHeading="Issue ID" tooltipContent={`${issue.project_detail?.identifier}-${issue.sequence_id}`} > - + {issue.project_detail?.identifier}-{issue.sequence_id} )} - + {truncateText(issue.name, 50)} @@ -139,7 +139,7 @@ export const MyIssuesListItem: React.FC = ({ issue, properties, projectId {issue.label_details.map((label) => ( = ({ issue, properties, projectId "" )} {properties.assignee && ( -
+
= ({ issue, properties, projectId
)} {properties.sub_issue_count && ( -
+
-
+
{issue.sub_issues_count}
@@ -186,20 +186,20 @@ export const MyIssuesListItem: React.FC = ({ issue, properties, projectId
)} {properties.link && ( -
+
-
- +
+ {issue.link_count}
)} {properties.attachment_count && ( -
+
-
- +
+ {issue.attachment_count}
diff --git a/apps/app/components/issues/parent-issues-list-modal.tsx b/apps/app/components/issues/parent-issues-list-modal.tsx index b93c07d3c..f01fe80bf 100644 --- a/apps/app/components/issues/parent-issues-list-modal.tsx +++ b/apps/app/components/issues/parent-issues-list-modal.tsx @@ -95,7 +95,7 @@ export const ParentIssuesListModal: React.FC = ({ leaveFrom="opacity-100" leaveTo="opacity-0" > -
+
@@ -108,15 +108,15 @@ export const ParentIssuesListModal: React.FC = ({ leaveFrom="opacity-100 scale-100" leaveTo="opacity-0 scale-95" > - +
Search results for{" "} - + {'"'} {debouncedSearchTerm} {'"'} @@ -143,9 +143,9 @@ export const ParentIssuesListModal: React.FC = ({ debouncedSearchTerm !== "" && (
-

+

No issues found. Create a new issue with{" "} -
+                            
                               C
                             
. @@ -167,9 +167,9 @@ export const ParentIssuesListModal: React.FC = ({ key={issue.id} value={issue.id} className={({ active, selected }) => - `flex cursor-pointer select-none items-center gap-2 rounded-md px-3 py-2 text-brand-secondary ${ - active ? "bg-brand-surface-2 text-brand-base" : "" - } ${selected ? "text-brand-base" : ""}` + `flex cursor-pointer select-none items-center gap-2 rounded-md px-3 py-2 text-custom-text-200 ${ + active ? "bg-custom-background-80 text-custom-text-100" : "" + } ${selected ? "text-custom-text-100" : ""}` } onClick={handleClose} > diff --git a/apps/app/components/issues/select/assignee.tsx b/apps/app/components/issues/select/assignee.tsx index 2e1844a69..6805c931e 100644 --- a/apps/app/components/issues/select/assignee.tsx +++ b/apps/app/components/issues/select/assignee.tsx @@ -55,15 +55,15 @@ export const IssueAssigneeSelect: React.FC = ({ projectId, value = [], on onChange={onChange} options={options} label={ -
+
{value && value.length > 0 && Array.isArray(value) ? (
) : (
- - Assignee + + Assignee
)}
diff --git a/apps/app/components/issues/select/date.tsx b/apps/app/components/issues/select/date.tsx index 26288e11b..7ce39c449 100644 --- a/apps/app/components/issues/select/date.tsx +++ b/apps/app/components/issues/select/date.tsx @@ -16,11 +16,11 @@ export const IssueDateSelect: React.FC = ({ value, onChange }) => ( {({ open }) => ( <> - - + + {value ? ( <> - {renderShortDateWithYearFormat(value)} + {renderShortDateWithYearFormat(value)} diff --git a/apps/app/components/issues/select/estimate.tsx b/apps/app/components/issues/select/estimate.tsx index 18204295b..0d910013b 100644 --- a/apps/app/components/issues/select/estimate.tsx +++ b/apps/app/components/issues/select/estimate.tsx @@ -22,8 +22,12 @@ export const IssueEstimateSelect: React.FC = ({ value, onChange }) => { value={value} label={
- - + + {estimatePoints?.find((e) => e.key === value)?.value ?? "Estimate"}
diff --git a/apps/app/components/issues/select/label.tsx b/apps/app/components/issues/select/label.tsx index e99eecc16..318d70185 100644 --- a/apps/app/components/issues/select/label.tsx +++ b/apps/app/components/issues/select/label.tsx @@ -59,7 +59,7 @@ export const IssueLabelSelect: React.FC = ({ setIsOpen, value, onChange, > {({ open }: any) => ( <> - + {value && value.length > 0 ? ( = ({ setIsOpen, value, onChange, ) : ( - - Label + + Label )} @@ -88,12 +88,12 @@ export const IssueLabelSelect: React.FC = ({ setIsOpen, value, onChange, > -
- +
+ setQuery(event.target.value)} placeholder="Search for label..." displayValue={(assigned: any) => assigned?.name} @@ -112,8 +112,8 @@ export const IssueLabelSelect: React.FC = ({ setIsOpen, value, onChange, key={label.id} className={({ active }) => `${ - active ? "bg-brand-surface-2" : "" - } group flex min-w-[14rem] cursor-pointer select-none items-center gap-2 truncate rounded px-1 py-1.5 text-brand-secondary` + active ? "bg-custom-background-80" : "" + } group flex min-w-[14rem] cursor-pointer select-none items-center gap-2 truncate rounded px-1 py-1.5 text-custom-text-200` } value={label.id} > @@ -141,8 +141,8 @@ export const IssueLabelSelect: React.FC = ({ setIsOpen, value, onChange, ); } else return ( -
-
+
+
{label.name}
@@ -151,8 +151,8 @@ export const IssueLabelSelect: React.FC = ({ setIsOpen, value, onChange, key={child.id} className={({ active }) => `${ - active ? "bg-brand-surface-2" : "" - } group flex min-w-[14rem] cursor-pointer select-none items-center gap-2 truncate rounded px-1 py-1.5 text-brand-secondary` + active ? "bg-custom-background-80" : "" + } group flex min-w-[14rem] cursor-pointer select-none items-center gap-2 truncate rounded px-1 py-1.5 text-custom-text-200` } value={child.id} > @@ -183,17 +183,17 @@ export const IssueLabelSelect: React.FC = ({ setIsOpen, value, onChange, ); }) ) : ( -

No labels found

+

No labels found

) ) : ( -

Loading...

+

Loading...

)}
} footerOption={
diff --git a/apps/app/components/issues/sidebar-select/priority.tsx b/apps/app/components/issues/sidebar-select/priority.tsx index 70a23090c..9f3631f7c 100644 --- a/apps/app/components/issues/sidebar-select/priority.tsx +++ b/apps/app/components/issues/sidebar-select/priority.tsx @@ -21,7 +21,7 @@ export const SidebarPrioritySelect: React.FC = ({ value, onChange, userAu return (
-
+

Priority

@@ -29,10 +29,10 @@ export const SidebarPrioritySelect: React.FC = ({ value, onChange, userAu - + {getPriorityIcon(value ?? "None", "text-sm")} - + {value ?? "None"}
diff --git a/apps/app/components/issues/sidebar-select/state.tsx b/apps/app/components/issues/sidebar-select/state.tsx index 02d1dd5cb..518e95c81 100644 --- a/apps/app/components/issues/sidebar-select/state.tsx +++ b/apps/app/components/issues/sidebar-select/state.tsx @@ -43,7 +43,7 @@ export const SidebarStateSelect: React.FC = ({ value, onChange, userAuth return (
-
+

State

@@ -51,7 +51,7 @@ export const SidebarStateSelect: React.FC = ({ value, onChange, userAuth +
{getStateGroupIcon( selectedState?.group ?? "backlog", "16", @@ -61,7 +61,7 @@ export const SidebarStateSelect: React.FC = ({ value, onChange, userAuth {addSpaceIfCamelCase(selectedState?.name ?? "")}
) : inboxIssueId ? ( -
+
{getStateGroupIcon("backlog", "16", "16", "#ff7700")} Triage
diff --git a/apps/app/components/issues/sidebar.tsx b/apps/app/components/issues/sidebar.tsx index 6f231871b..13a9c6395 100644 --- a/apps/app/components/issues/sidebar.tsx +++ b/apps/app/components/issues/sidebar.tsx @@ -281,7 +281,7 @@ export const IssueDetailsSidebar: React.FC = ({ data={issueDetail ?? null} user={user} /> -
+

{issueDetail?.project_detail?.identifier}-{issueDetail?.sequence_id} @@ -290,7 +290,7 @@ export const IssueDetailsSidebar: React.FC = ({ {(fieldsToShow.includes("all") || fieldsToShow.includes("link")) && (

-
+
{showFirstSection && (
{(fieldsToShow.includes("all") || fieldsToShow.includes("state")) && ( @@ -374,15 +374,15 @@ export const IssueDetailsSidebar: React.FC = ({ issueDetail?.parent_detail ? ( ) : ( -
+
No parent selected
) @@ -409,7 +409,7 @@ export const IssueDetailsSidebar: React.FC = ({ )} {(fieldsToShow.includes("all") || fieldsToShow.includes("dueDate")) && (
-
+

Due date

@@ -426,7 +426,7 @@ export const IssueDetailsSidebar: React.FC = ({ target_date: val, }) } - className="bg-brand-surface-1" + className="bg-custom-background-90" disabled={isNotAllowed} /> )} @@ -458,7 +458,7 @@ export const IssueDetailsSidebar: React.FC = ({ {(fieldsToShow.includes("all") || fieldsToShow.includes("label")) && (
-
+

Label

@@ -471,7 +471,7 @@ export const IssueDetailsSidebar: React.FC = ({ return ( { const updatedLabels = watchIssue("labels_list")?.filter( (l) => l !== labelId @@ -511,8 +511,8 @@ export const IssueDetailsSidebar: React.FC = ({ className={`flex ${ isNotAllowed ? "cursor-not-allowed" - : "cursor-pointer hover:bg-brand-surface-1" - } items-center gap-2 rounded-2xl border border-brand-base px-2 py-0.5 text-xs text-brand-secondary`} + : "cursor-pointer hover:bg-custom-background-90" + } items-center gap-2 rounded-2xl border border-custom-border-100 px-2 py-0.5 text-xs text-custom-text-200`} > Select Label @@ -524,7 +524,7 @@ export const IssueDetailsSidebar: React.FC = ({ leaveFrom="opacity-100" leaveTo="opacity-0" > - +
{issueLabels ? ( issueLabels.length > 0 ? ( @@ -540,9 +540,11 @@ export const IssueDetailsSidebar: React.FC = ({ key={label.id} className={({ active, selected }) => `${ - active || selected ? "bg-brand-surface-1" : "" + active || selected + ? "bg-custom-background-90" + : "" } ${ - selected ? "" : "text-brand-secondary" + selected ? "" : "text-custom-text-200" } flex cursor-pointer select-none items-center gap-2 truncate p-2` } value={label.id} @@ -561,8 +563,8 @@ export const IssueDetailsSidebar: React.FC = ({ ); } else return ( -
-
+
+
{label.name}
@@ -572,9 +574,11 @@ export const IssueDetailsSidebar: React.FC = ({ key={child.id} className={({ active, selected }) => `${ - active || selected ? "bg-brand-base" : "" + active || selected + ? "bg-custom-background-100" + : "" } ${ - selected ? "" : "text-brand-secondary" + selected ? "" : "text-custom-text-200" } flex cursor-pointer select-none items-center gap-2 truncate p-2` } value={child.id} @@ -612,8 +616,8 @@ export const IssueDetailsSidebar: React.FC = ({ className={`flex ${ isNotAllowed ? "cursor-not-allowed" - : "cursor-pointer hover:bg-brand-surface-1" - } items-center gap-1 rounded-2xl border border-brand-base px-2 py-0.5 text-xs text-brand-secondary`} + : "cursor-pointer hover:bg-custom-background-90" + } items-center gap-1 rounded-2xl border border-custom-border-100 px-2 py-0.5 text-xs text-custom-text-200`} onClick={() => setCreateLabelForm((prevData) => !prevData)} > {createLabelForm ? ( @@ -637,7 +641,7 @@ export const IssueDetailsSidebar: React.FC = ({ {({ open }) => ( <> {watch("color") && watch("color") !== "" && ( = ({ {!isNotAllowed && ( )} diff --git a/apps/app/components/issues/view-select/assignee.tsx b/apps/app/components/issues/view-select/assignee.tsx index cba1db1e7..c4bf7c16c 100644 --- a/apps/app/components/issues/view-select/assignee.tsx +++ b/apps/app/components/issues/view-select/assignee.tsx @@ -84,7 +84,7 @@ export const ViewAssigneeSelect: React.FC = ({
{issue.assignees && issue.assignees.length > 0 && Array.isArray(issue.assignees) ? (
@@ -92,7 +92,7 @@ export const ViewAssigneeSelect: React.FC = ({
) : (
- +
)}
diff --git a/apps/app/components/issues/view-select/due-date.tsx b/apps/app/components/issues/view-select/due-date.tsx index efd568c30..f45440cfc 100644 --- a/apps/app/components/issues/view-select/due-date.tsx +++ b/apps/app/components/issues/view-select/due-date.tsx @@ -8,6 +8,7 @@ import { findHowManyDaysLeft, renderShortDateWithYearFormat } from "helpers/date import trackEventServices from "services/track-event.service"; // types import { ICurrentUserResponse, IIssue } from "types"; +import useIssuesView from "hooks/use-issues-view"; type Props = { issue: IIssue; @@ -29,6 +30,8 @@ export const ViewDueDateSelect: React.FC = ({ const router = useRouter(); const { workspaceSlug } = router.query; + const { issueView } = useIssuesView(); + return ( = ({ user ); }} - className={issue?.target_date ? "w-[6.5rem]" : "w-[5rem] text-center"} + className={`${issue?.target_date ? "w-[6.5rem]" : "w-[5rem] text-center"} ${ + issueView === "kanban" ? "bg-custom-background-90" : "bg-custom-background-100" + }`} noBorder={noBorder} disabled={isNotAllowed} /> diff --git a/apps/app/components/issues/view-select/estimate.tsx b/apps/app/components/issues/view-select/estimate.tsx index d330a5f58..bef060e77 100644 --- a/apps/app/components/issues/view-select/estimate.tsx +++ b/apps/app/components/issues/view-select/estimate.tsx @@ -43,7 +43,7 @@ export const ViewEstimateSelect: React.FC = ({ const estimateLabels = ( -
+
{estimateValue ?? "None"}
diff --git a/apps/app/components/issues/view-select/label.tsx b/apps/app/components/issues/view-select/label.tsx index b82b02a0f..098576dd7 100644 --- a/apps/app/components/issues/view-select/label.tsx +++ b/apps/app/components/issues/view-select/label.tsx @@ -71,34 +71,43 @@ export const ViewLabelSelect: React.FC = ({ position={tooltipPosition} tooltipHeading="Labels" tooltipContent={ - issue.label_details.length > 0 - ? issue.label_details.map((label) => label.name ?? "").join(", ") - : "No Label" + issue.labels.length > 0 + ? issue.labels + .map((labelId) => { + const label = issueLabels?.find((l) => l.id === labelId); + + return label?.name ?? ""; + }) + .join(", ") + : "No label" } >
- {issue.label_details.length > 0 ? ( + {issue.labels.length > 0 ? ( <> - {issue.label_details.slice(0, 4).map((label, index) => ( -
- -
- ))} - {issue.label_details.length > 4 ? +{issue.label_details.length - 4} : null} + {issue.labels.slice(0, 4).map((labelId, index) => { + const label = issueLabels?.find((l) => l.id === labelId); + + return ( +
+ +
+ ); + })} + {issue.labels.length > 4 ? +{issue.labels.length - 4} : null} ) : ( <> - + )}
@@ -108,17 +117,17 @@ export const ViewLabelSelect: React.FC = ({ const footerOption = ( ); - const noResultIcon = ; + const noResultIcon = ; return ( <> diff --git a/apps/app/components/issues/view-select/priority.tsx b/apps/app/components/issues/view-select/priority.tsx index e7a674ec7..04f500e88 100644 --- a/apps/app/components/issues/view-select/priority.tsx +++ b/apps/app/components/issues/view-select/priority.tsx @@ -67,14 +67,14 @@ export const ViewPrioritySelect: React.FC = ({ noBorder ? "" : issue.priority === "urgent" - ? "border-red-500/20 bg-red-500/20 text-red-500" + ? "border-red-500/20 bg-red-500/20" : issue.priority === "high" - ? "border-orange-500/20 bg-orange-500/20 text-orange-500" + ? "border-orange-500/20 bg-orange-500/20" : issue.priority === "medium" - ? "border-yellow-500/20 bg-yellow-500/20 text-yellow-500" + ? "border-yellow-500/20 bg-yellow-500/20" : issue.priority === "low" - ? "border-green-500/20 bg-green-500/20 text-green-500" - : "border-brand-base" + ? "border-green-500/20 bg-green-500/20" + : "border-custom-border-100 bg-custom-background-80" } items-center`} > = ({ tooltipContent={issue.priority ?? "None"} position={tooltipPosition} > - + {getPriorityIcon( issue.priority && issue.priority !== "" ? issue.priority ?? "" : "None", - "text-sm" + `text-sm ${ + issue.priority === "urgent" + ? "text-red-500" + : issue.priority === "high" + ? "text-orange-500" + : issue.priority === "medium" + ? "text-yellow-500" + : issue.priority === "low" + ? "text-green-500" + : "text-custom-text-200" + }` )} {noBorder ? issue.priority && issue.priority !== "" diff --git a/apps/app/components/issues/view-select/state.tsx b/apps/app/components/issues/view-select/state.tsx index a38ff55a7..6f679fe7c 100644 --- a/apps/app/components/issues/view-select/state.tsx +++ b/apps/app/components/issues/view-select/state.tsx @@ -10,7 +10,6 @@ import { CustomSearchSelect, Tooltip } from "components/ui"; // icons import { getStateGroupIcon } from "components/icons"; // helpers -import { addSpaceIfCamelCase } from "helpers/string.helper"; import { getStatesList } from "helpers/state.helper"; // types import { ICurrentUserResponse, IIssue } from "types"; @@ -67,10 +66,10 @@ export const ViewStateSelect: React.FC = ({ const stateLabel = ( -
+
{selectedOption && getStateGroupIcon(selectedOption.group, "16", "16", selectedOption.color)} diff --git a/apps/app/components/labels/create-label-modal.tsx b/apps/app/components/labels/create-label-modal.tsx index c7566dc77..c420e45b4 100644 --- a/apps/app/components/labels/create-label-modal.tsx +++ b/apps/app/components/labels/create-label-modal.tsx @@ -31,7 +31,7 @@ type Props = { const defaultValues: Partial = { name: "", - color: "#858E96", + color: "rgb(var(--color-text-200))", }; export const CreateLabelModal: React.FC = ({ isOpen, projectId, handleClose, user }) => { @@ -98,10 +98,13 @@ export const CreateLabelModal: React.FC = ({ isOpen, projectId, handleClo leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - +
- + Create Label
@@ -109,8 +112,8 @@ export const CreateLabelModal: React.FC = ({ isOpen, projectId, handleClo {({ open, close }) => ( <> {watch("color") && watch("color") !== "" && ( @@ -122,7 +125,7 @@ export const CreateLabelModal: React.FC = ({ isOpen, projectId, handleClo /> )}