mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: resolved merge conflict
This commit is contained in:
commit
c65f93c971
@ -59,8 +59,9 @@ AWS_S3_BUCKET_NAME="uploads"
|
|||||||
FILE_SIZE_LIMIT=5242880
|
FILE_SIZE_LIMIT=5242880
|
||||||
|
|
||||||
# GPT settings
|
# GPT settings
|
||||||
OPENAI_API_KEY=""
|
OPENAI_API_BASE="https://api.openai.com/v1" # change if using a custom endpoint
|
||||||
GPT_ENGINE=""
|
OPENAI_API_KEY="sk-" # add your openai key here
|
||||||
|
GPT_ENGINE="gpt-3.5-turbo" # use "gpt-4" if you have access
|
||||||
|
|
||||||
# Github
|
# Github
|
||||||
GITHUB_CLIENT_SECRET="" # For fetching release notes
|
GITHUB_CLIENT_SECRET="" # For fetching release notes
|
||||||
|
@ -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 -
|
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
|
worker: celery -A plane worker -l info
|
||||||
|
beat: celery -A plane beat -l INFO
|
@ -77,6 +77,8 @@ from plane.api.views import (
|
|||||||
BulkCreateIssueLabelsEndpoint,
|
BulkCreateIssueLabelsEndpoint,
|
||||||
IssueAttachmentEndpoint,
|
IssueAttachmentEndpoint,
|
||||||
IssueSubscriberViewSet,
|
IssueSubscriberViewSet,
|
||||||
|
IssueArchiveViewSet,
|
||||||
|
IssueSubscriberViewSet,
|
||||||
## End Issues
|
## End Issues
|
||||||
# States
|
# States
|
||||||
StateViewSet,
|
StateViewSet,
|
||||||
@ -853,6 +855,36 @@ urlpatterns = [
|
|||||||
name="project-issue-roadmap",
|
name="project-issue-roadmap",
|
||||||
),
|
),
|
||||||
## IssueProperty Ebd
|
## IssueProperty Ebd
|
||||||
|
## Issue Archives
|
||||||
|
path(
|
||||||
|
"workspaces/<str:slug>/projects/<uuid:project_id>/archived-issues/",
|
||||||
|
IssueArchiveViewSet.as_view(
|
||||||
|
{
|
||||||
|
"get": "list",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
name="project-issue-archive",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"workspaces/<str:slug>/projects/<uuid:project_id>/archived-issues/<uuid:pk>/",
|
||||||
|
IssueArchiveViewSet.as_view(
|
||||||
|
{
|
||||||
|
"get": "retrieve",
|
||||||
|
"delete": "destroy",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
name="project-issue-archive",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"workspaces/<str:slug>/projects/<uuid:project_id>/unarchive/<uuid:pk>/",
|
||||||
|
IssueArchiveViewSet.as_view(
|
||||||
|
{
|
||||||
|
"post": "unarchive",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
name="project-issue-archive",
|
||||||
|
),
|
||||||
|
## End Issue Archives
|
||||||
## File Assets
|
## File Assets
|
||||||
path(
|
path(
|
||||||
"workspaces/<str:slug>/file-assets/",
|
"workspaces/<str:slug>/file-assets/",
|
||||||
|
@ -65,6 +65,7 @@ from .issue import (
|
|||||||
IssueLinkViewSet,
|
IssueLinkViewSet,
|
||||||
BulkCreateIssueLabelsEndpoint,
|
BulkCreateIssueLabelsEndpoint,
|
||||||
IssueAttachmentEndpoint,
|
IssueAttachmentEndpoint,
|
||||||
|
IssueArchiveViewSet,
|
||||||
IssueSubscriberViewSet,
|
IssueSubscriberViewSet,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ class GPTIntegrationEndpoint(BaseAPIView):
|
|||||||
|
|
||||||
openai.api_key = settings.OPENAI_API_KEY
|
openai.api_key = settings.OPENAI_API_KEY
|
||||||
response = openai.Completion.create(
|
response = openai.Completion.create(
|
||||||
engine=settings.GPT_ENGINE,
|
model=settings.GPT_ENGINE,
|
||||||
prompt=final_text,
|
prompt=final_text,
|
||||||
temperature=0.7,
|
temperature=0.7,
|
||||||
max_tokens=1024,
|
max_tokens=1024,
|
||||||
|
@ -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):
|
class IssueSubscriberViewSet(BaseViewSet):
|
||||||
serializer_class = IssueSubscriberSerializer
|
serializer_class = IssueSubscriberSerializer
|
||||||
model = IssueSubscriber
|
model = IssueSubscriber
|
||||||
|
@ -5,6 +5,7 @@ import requests
|
|||||||
# Django imports
|
# Django imports
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.serializers.json import DjangoJSONEncoder
|
from django.core.serializers.json import DjangoJSONEncoder
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
# Third Party imports
|
# Third Party imports
|
||||||
from celery import shared_task
|
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(
|
def update_issue_activity(
|
||||||
requested_data, current_instance, issue_id, project, actor, issue_activities
|
requested_data, current_instance, issue_id, project, actor, issue_activities
|
||||||
):
|
):
|
||||||
@ -573,6 +592,7 @@ def update_issue_activity(
|
|||||||
"blocks_list": track_blocks,
|
"blocks_list": track_blocks,
|
||||||
"blockers_list": track_blockings,
|
"blockers_list": track_blockings,
|
||||||
"estimate_point": track_estimate_points,
|
"estimate_point": track_estimate_points,
|
||||||
|
"archived_in": track_archive_in,
|
||||||
}
|
}
|
||||||
|
|
||||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
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
|
# Receive message from room group
|
||||||
@shared_task
|
@shared_task
|
||||||
def issue_activity(
|
def issue_activity(
|
||||||
@ -961,6 +982,11 @@ def issue_activity(
|
|||||||
actor = User.objects.get(pk=actor_id)
|
actor = User.objects.get(pk=actor_id)
|
||||||
project = Project.objects.get(pk=project_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
|
# add the user to issue subscriber
|
||||||
try:
|
try:
|
||||||
_ = IssueSubscriber.objects.create(issue_id=issue_id, subscriber=actor)
|
_ = IssueSubscriber.objects.create(issue_id=issue_id, subscriber=actor)
|
||||||
|
148
apiserver/plane/bgtasks/issue_automation_task.py
Normal file
148
apiserver/plane/bgtasks/issue_automation_task.py
Normal file
@ -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
|
@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
from celery import Celery
|
from celery import Celery
|
||||||
from plane.settings.redis import redis_instance
|
from plane.settings.redis import redis_instance
|
||||||
|
from celery.schedules import crontab
|
||||||
|
|
||||||
# Set the default Django settings module for the 'celery' program.
|
# Set the default Django settings module for the 'celery' program.
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "plane.settings.production")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "plane.settings.production")
|
||||||
@ -13,5 +14,15 @@ app = Celery("plane")
|
|||||||
# pickle the object when using Windows.
|
# pickle the object when using Windows.
|
||||||
app.config_from_object("django.conf:settings", namespace="CELERY")
|
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.
|
# Load task modules from all registered Django app configs.
|
||||||
app.autodiscover_tasks()
|
app.autodiscover_tasks()
|
||||||
|
|
||||||
|
app.conf.beat_scheduler = 'django_celery_beat.schedulers.DatabaseScheduler'
|
@ -28,6 +28,8 @@ class IssueManager(models.Manager):
|
|||||||
| models.Q(issue_inbox__status=2)
|
| models.Q(issue_inbox__status=2)
|
||||||
| models.Q(issue_inbox__isnull=True)
|
| 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)
|
sort_order = models.FloatField(default=65535)
|
||||||
completed_at = models.DateTimeField(null=True)
|
completed_at = models.DateTimeField(null=True)
|
||||||
|
archived_at = models.DateField(null=True)
|
||||||
|
|
||||||
objects = models.Manager()
|
objects = models.Manager()
|
||||||
issue_objects = IssueManager()
|
issue_objects = IssueManager()
|
||||||
|
@ -4,6 +4,7 @@ from django.conf import settings
|
|||||||
from django.template.defaultfilters import slugify
|
from django.template.defaultfilters import slugify
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||||
|
|
||||||
# Modeule imports
|
# Modeule imports
|
||||||
from plane.db.mixins import AuditModel
|
from plane.db.mixins import AuditModel
|
||||||
@ -74,6 +75,15 @@ class Project(BaseModel):
|
|||||||
estimate = models.ForeignKey(
|
estimate = models.ForeignKey(
|
||||||
"db.Estimate", on_delete=models.SET_NULL, related_name="projects", null=True
|
"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):
|
def __str__(self):
|
||||||
"""Return name of the project"""
|
"""Return name of the project"""
|
||||||
|
@ -35,6 +35,7 @@ INSTALLED_APPS = [
|
|||||||
"rest_framework_simplejwt.token_blacklist",
|
"rest_framework_simplejwt.token_blacklist",
|
||||||
"corsheaders",
|
"corsheaders",
|
||||||
"taggit",
|
"taggit",
|
||||||
|
"django_celery_beat",
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
@ -213,3 +214,4 @@ SIMPLE_JWT = {
|
|||||||
CELERY_TIMEZONE = TIME_ZONE
|
CELERY_TIMEZONE = TIME_ZONE
|
||||||
CELERY_TASK_SERIALIZER = 'json'
|
CELERY_TASK_SERIALIZER = 'json'
|
||||||
CELERY_ACCEPT_CONTENT = ['application/json']
|
CELERY_ACCEPT_CONTENT = ['application/json']
|
||||||
|
CELERY_IMPORTS = ("plane.bgtasks.issue_automation_task",)
|
||||||
|
@ -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_SECRET_KEY = os.environ.get("ANALYTICS_SECRET_KEY", False)
|
||||||
ANALYTICS_BASE_API = os.environ.get("ANALYTICS_BASE_API", 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)
|
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)
|
SLACK_BOT_TOKEN = os.environ.get("SLACK_BOT_TOKEN", False)
|
||||||
|
|
||||||
|
@ -11,10 +11,9 @@ from sentry_sdk.integrations.django import DjangoIntegration
|
|||||||
from sentry_sdk.integrations.redis import RedisIntegration
|
from sentry_sdk.integrations.redis import RedisIntegration
|
||||||
|
|
||||||
from .common import * # noqa
|
from .common import * # noqa
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
DEBUG = int(os.environ.get(
|
DEBUG = int(os.environ.get("DEBUG", 1)) == 1
|
||||||
"DEBUG", 1
|
|
||||||
)) == 1
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
"default": {
|
"default": {
|
||||||
"ENGINE": "django.db.backends.postgresql_psycopg2",
|
"ENGINE": "django.db.backends.postgresql_psycopg2",
|
||||||
@ -56,9 +55,7 @@ STORAGES = {
|
|||||||
|
|
||||||
|
|
||||||
# Make true if running in a docker environment
|
# Make true if running in a docker environment
|
||||||
DOCKERIZED = int(os.environ.get(
|
DOCKERIZED = int(os.environ.get("DOCKERIZED", 0)) == 1
|
||||||
"DOCKERIZED", 0
|
|
||||||
)) == 1
|
|
||||||
FILE_SIZE_LIMIT = int(os.environ.get("FILE_SIZE_LIMIT", 5242880))
|
FILE_SIZE_LIMIT = int(os.environ.get("FILE_SIZE_LIMIT", 5242880))
|
||||||
USE_MINIO = int(os.environ.get("USE_MINIO", 0)) == 1
|
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_SECRET_KEY = os.environ.get("ANALYTICS_SECRET_KEY", False)
|
||||||
ANALYTICS_BASE_API = os.environ.get("ANALYTICS_BASE_API", 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)
|
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)
|
SLACK_BOT_TOKEN = os.environ.get("SLACK_BOT_TOKEN", False)
|
||||||
|
|
||||||
LOGGER_BASE_URL = os.environ.get("LOGGER_BASE_URL", False)
|
LOGGER_BASE_URL = os.environ.get("LOGGER_BASE_URL", False)
|
||||||
|
|
||||||
redis_url = os.environ.get("REDIS_URL")
|
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_RESULT_BACKEND = broker_url
|
||||||
CELERY_BROKER_URL = broker_url
|
CELERY_BROKER_URL = broker_url
|
||||||
|
@ -29,3 +29,4 @@ channels==4.0.0
|
|||||||
openai==0.27.8
|
openai==0.27.8
|
||||||
slack-sdk==3.21.3
|
slack-sdk==3.21.3
|
||||||
celery==5.3.1
|
celery==5.3.1
|
||||||
|
django_celery_beat==2.5.0
|
||||||
|
@ -164,8 +164,8 @@ export const EmailCodeForm = ({ handleSignIn }: any) => {
|
|||||||
type="button"
|
type="button"
|
||||||
className={`mt-5 flex w-full justify-end text-xs outline-none ${
|
className={`mt-5 flex w-full justify-end text-xs outline-none ${
|
||||||
isResendDisabled
|
isResendDisabled
|
||||||
? "cursor-default text-brand-secondary"
|
? "cursor-default text-custom-text-200"
|
||||||
: "cursor-pointer text-brand-accent"
|
: "cursor-pointer text-custom-primary"
|
||||||
} `}
|
} `}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsCodeResending(true);
|
setIsCodeResending(true);
|
||||||
|
@ -80,7 +80,7 @@ export const EmailPasswordForm: React.FC<Props> = ({ onSubmit }) => {
|
|||||||
<div className="ml-auto text-sm">
|
<div className="ml-auto text-sm">
|
||||||
{isSignUpPage ? (
|
{isSignUpPage ? (
|
||||||
<Link href="/">
|
<Link href="/">
|
||||||
<a className="font-medium text-brand-accent hover:text-brand-accent">
|
<a className="font-medium text-custom-primary hover:text-custom-primary">
|
||||||
Already have an account? Sign in.
|
Already have an account? Sign in.
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
@ -88,7 +88,7 @@ export const EmailPasswordForm: React.FC<Props> = ({ onSubmit }) => {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setIsResettingPassword(true)}
|
onClick={() => setIsResettingPassword(true)}
|
||||||
className="font-medium text-brand-accent hover:text-brand-accent"
|
className="font-medium text-custom-primary hover:text-custom-primary"
|
||||||
>
|
>
|
||||||
Forgot your password?
|
Forgot your password?
|
||||||
</button>
|
</button>
|
||||||
@ -112,7 +112,7 @@ export const EmailPasswordForm: React.FC<Props> = ({ onSubmit }) => {
|
|||||||
</SecondaryButton>
|
</SecondaryButton>
|
||||||
{!isSignUpPage && (
|
{!isSignUpPage && (
|
||||||
<Link href="/sign-up">
|
<Link href="/sign-up">
|
||||||
<a className="block font-medium text-brand-accent hover:text-brand-accent text-sm mt-1">
|
<a className="block font-medium text-custom-primary hover:text-custom-primary text-sm mt-1">
|
||||||
Don{"'"}t have an account? Sign up.
|
Don{"'"}t have an account? Sign up.
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -39,7 +39,7 @@ export const GithubLoginButton: FC<GithubLoginButtonProps> = (props) => {
|
|||||||
<Link
|
<Link
|
||||||
href={`https://github.com/login/oauth/authorize?client_id=${NEXT_PUBLIC_GITHUB_ID}&redirect_uri=${loginCallBackURL}&scope=read:user,user:email`}
|
href={`https://github.com/login/oauth/authorize?client_id=${NEXT_PUBLIC_GITHUB_ID}&redirect_uri=${loginCallBackURL}&scope=read:user,user:email`}
|
||||||
>
|
>
|
||||||
<button className="flex w-full items-center justify-center gap-3 rounded border border-brand-base p-2 text-sm font-medium text-brand-secondary duration-300 hover:bg-brand-surface-2">
|
<button className="flex w-full items-center justify-center gap-3 rounded border border-custom-border-100 p-2 text-sm font-medium text-custom-text-200 duration-300 hover:bg-custom-background-80">
|
||||||
<Image src={githubImage} height={20} width={20} color="#000" alt="GitHub Logo" />
|
<Image src={githubImage} height={20} width={20} color="#000" alt="GitHub Logo" />
|
||||||
<span>Sign In with Github</span>
|
<span>Sign In with Github</span>
|
||||||
</button>
|
</button>
|
||||||
|
@ -97,7 +97,7 @@ export const CreateUpdateAnalyticsModal: React.FC<Props> = ({ isOpen, handleClos
|
|||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<div className="fixed inset-0 bg-brand-backdrop bg-opacity-50 transition-opacity" />
|
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
|
|
||||||
<div className="fixed inset-0 z-10 overflow-y-auto">
|
<div className="fixed inset-0 z-10 overflow-y-auto">
|
||||||
@ -111,10 +111,13 @@ export const CreateUpdateAnalyticsModal: React.FC<Props> = ({ isOpen, handleClos
|
|||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative transform rounded-lg border border-brand-base bg-brand-base px-4 pt-5 pb-4 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-100 bg-custom-background-100 px-4 pt-5 pb-4 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div>
|
<div>
|
||||||
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-brand-base">
|
<Dialog.Title
|
||||||
|
as="h3"
|
||||||
|
className="text-lg font-medium leading-6 text-custom-text-100"
|
||||||
|
>
|
||||||
Save Analytics
|
Save Analytics
|
||||||
</Dialog.Title>
|
</Dialog.Title>
|
||||||
<div className="mt-5">
|
<div className="mt-5">
|
||||||
|
@ -61,7 +61,7 @@ export const CustomAnalytics: React.FC<Props> = ({
|
|||||||
<AnalyticsSelectBar
|
<AnalyticsSelectBar
|
||||||
control={control}
|
control={control}
|
||||||
setValue={setValue}
|
setValue={setValue}
|
||||||
projects={projects}
|
projects={projects ?? []}
|
||||||
params={params}
|
params={params}
|
||||||
fullScreen={fullScreen}
|
fullScreen={fullScreen}
|
||||||
isProjectLevel={isProjectLevel}
|
isProjectLevel={isProjectLevel}
|
||||||
@ -86,7 +86,7 @@ export const CustomAnalytics: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid h-full place-items-center p-5">
|
<div className="grid h-full place-items-center p-5">
|
||||||
<div className="space-y-4 text-brand-secondary">
|
<div className="space-y-4 text-custom-text-200">
|
||||||
<p className="text-sm">No matching issues found. Try changing the parameters.</p>
|
<p className="text-sm">No matching issues found. Try changing the parameters.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -104,7 +104,7 @@ export const CustomAnalytics: React.FC<Props> = ({
|
|||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
<div className="grid h-full place-items-center p-5">
|
<div className="grid h-full place-items-center p-5">
|
||||||
<div className="space-y-4 text-brand-secondary">
|
<div className="space-y-4 text-custom-text-200">
|
||||||
<p className="text-sm">There was some error in fetching the data.</p>
|
<p className="text-sm">There was some error in fetching the data.</p>
|
||||||
<div className="flex items-center justify-center gap-2">
|
<div className="flex items-center justify-center gap-2">
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
|
@ -31,7 +31,7 @@ export const CustomTooltip: React.FC<Props> = ({ datum, analytics, params }) =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2 rounded-md border border-brand-base bg-brand-surface-2 p-2 text-xs">
|
<div className="flex items-center gap-2 rounded-md border border-custom-border-100 bg-custom-background-80 p-2 text-xs">
|
||||||
<span
|
<span
|
||||||
className="h-3 w-3 rounded"
|
className="h-3 w-3 rounded"
|
||||||
style={{
|
style={{
|
||||||
@ -39,7 +39,7 @@ export const CustomTooltip: React.FC<Props> = ({ datum, analytics, params }) =>
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className={`font-medium text-brand-secondary ${
|
className={`font-medium text-custom-text-200 ${
|
||||||
params.segment
|
params.segment
|
||||||
? params.segment === "priority" || params.segment === "state__group"
|
? params.segment === "priority" || params.segment === "state__group"
|
||||||
? "capitalize"
|
? "capitalize"
|
||||||
|
@ -111,7 +111,6 @@ export const AnalyticsGraph: React.FC<Props> = ({
|
|||||||
: undefined,
|
: undefined,
|
||||||
}}
|
}}
|
||||||
theme={{
|
theme={{
|
||||||
background: "rgb(var(--color-bg-base))",
|
|
||||||
axis: {},
|
axis: {},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -29,7 +29,7 @@ export const AnalyticsSelectBar: React.FC<Props> = ({
|
|||||||
>
|
>
|
||||||
{!isProjectLevel && (
|
{!isProjectLevel && (
|
||||||
<div>
|
<div>
|
||||||
<h6 className="text-xs text-brand-secondary">Project</h6>
|
<h6 className="text-xs text-custom-text-200">Project</h6>
|
||||||
<Controller
|
<Controller
|
||||||
name="project"
|
name="project"
|
||||||
control={control}
|
control={control}
|
||||||
@ -40,7 +40,7 @@ export const AnalyticsSelectBar: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div>
|
<div>
|
||||||
<h6 className="text-xs text-brand-secondary">Measure (y-axis)</h6>
|
<h6 className="text-xs text-custom-text-200">Measure (y-axis)</h6>
|
||||||
<Controller
|
<Controller
|
||||||
name="y_axis"
|
name="y_axis"
|
||||||
control={control}
|
control={control}
|
||||||
@ -50,7 +50,7 @@ export const AnalyticsSelectBar: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h6 className="text-xs text-brand-secondary">Dimension (x-axis)</h6>
|
<h6 className="text-xs text-custom-text-200">Dimension (x-axis)</h6>
|
||||||
<Controller
|
<Controller
|
||||||
name="x_axis"
|
name="x_axis"
|
||||||
control={control}
|
control={control}
|
||||||
@ -67,7 +67,7 @@ export const AnalyticsSelectBar: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h6 className="text-xs text-brand-secondary">Group</h6>
|
<h6 className="text-xs text-custom-text-200">Group</h6>
|
||||||
<Controller
|
<Controller
|
||||||
name="segment"
|
name="segment"
|
||||||
control={control}
|
control={control}
|
||||||
|
@ -24,13 +24,13 @@ import { ContrastIcon, LayerDiagonalIcon } from "components/icons";
|
|||||||
// helpers
|
// helpers
|
||||||
import { renderShortDate } from "helpers/date-time.helper";
|
import { renderShortDate } from "helpers/date-time.helper";
|
||||||
import { renderEmoji } from "helpers/emoji.helper";
|
import { renderEmoji } from "helpers/emoji.helper";
|
||||||
|
import { truncateText } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
import {
|
import {
|
||||||
IAnalyticsParams,
|
IAnalyticsParams,
|
||||||
IAnalyticsResponse,
|
IAnalyticsResponse,
|
||||||
ICurrentUserResponse,
|
ICurrentUserResponse,
|
||||||
IExportAnalyticsFormData,
|
IExportAnalyticsFormData,
|
||||||
IProject,
|
|
||||||
IWorkspace,
|
IWorkspace,
|
||||||
} from "types";
|
} from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
@ -179,23 +179,23 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const selectedProjects =
|
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 (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`px-5 py-2.5 flex items-center justify-between space-y-2 ${
|
className={`px-5 py-2.5 flex items-center justify-between space-y-2 ${
|
||||||
fullScreen
|
fullScreen
|
||||||
? "border-l border-brand-base md:h-full md:border-l md:border-brand-base md:space-y-4 overflow-hidden md:flex-col md:items-start md:py-5"
|
? "border-l border-custom-border-100 md:h-full md:border-l md:border-custom-border-100 md:space-y-4 overflow-hidden md:flex-col md:items-start md:py-5"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 flex-wrap">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<div className="flex items-center gap-1 bg-brand-surface-2 rounded-md px-3 py-1 text-brand-secondary text-xs">
|
<div className="flex items-center gap-1 bg-custom-background-80 rounded-md px-3 py-1 text-custom-text-200 text-xs">
|
||||||
<LayerDiagonalIcon height={14} width={14} />
|
<LayerDiagonalIcon height={14} width={14} />
|
||||||
{analytics ? analytics.total : "..."} Issues
|
{analytics ? analytics.total : "..."} Issues
|
||||||
</div>
|
</div>
|
||||||
{isProjectLevel && (
|
{isProjectLevel && (
|
||||||
<div className="flex items-center gap-1 bg-brand-surface-2 rounded-md px-3 py-1 text-brand-secondary text-xs">
|
<div className="flex items-center gap-1 bg-custom-background-80 rounded-md px-3 py-1 text-custom-text-200 text-xs">
|
||||||
<CalendarDaysIcon className="h-3.5 w-3.5" />
|
<CalendarDaysIcon className="h-3.5 w-3.5" />
|
||||||
{renderShortDate(
|
{renderShortDate(
|
||||||
(cycleId
|
(cycleId
|
||||||
@ -207,7 +207,7 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="h-full overflow-hidden">
|
<div className="h-full w-full overflow-hidden">
|
||||||
{fullScreen ? (
|
{fullScreen ? (
|
||||||
<>
|
<>
|
||||||
{!isProjectLevel && selectedProjects && selectedProjects.length > 0 && (
|
{!isProjectLevel && selectedProjects && selectedProjects.length > 0 && (
|
||||||
@ -215,10 +215,11 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
|||||||
<h4 className="font-medium">Selected Projects</h4>
|
<h4 className="font-medium">Selected Projects</h4>
|
||||||
<div className="space-y-6 mt-4 h-full overflow-y-auto">
|
<div className="space-y-6 mt-4 h-full overflow-y-auto">
|
||||||
{selectedProjects.map((projectId) => {
|
{selectedProjects.map((projectId) => {
|
||||||
const project: IProject = projects.find((p) => p.id === projectId);
|
const project = projects?.find((p) => p.id === projectId);
|
||||||
|
|
||||||
|
if (project)
|
||||||
return (
|
return (
|
||||||
<div key={project.id}>
|
<div key={project.id} className="w-full">
|
||||||
<div className="text-sm flex items-center gap-1">
|
<div className="text-sm flex items-center gap-1">
|
||||||
{project.emoji ? (
|
{project.emoji ? (
|
||||||
<span className="grid h-6 w-6 flex-shrink-0 place-items-center">
|
<span className="grid h-6 w-6 flex-shrink-0 place-items-center">
|
||||||
@ -238,34 +239,34 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
|||||||
{project?.name.charAt(0)}
|
{project?.name.charAt(0)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<h5 className="break-words">
|
<h5 className="flex items-center gap-1">
|
||||||
{project.name}
|
<p className="break-words">{truncateText(project.name, 20)}</p>
|
||||||
<span className="text-brand-secondary text-xs ml-1">
|
<span className="text-custom-text-200 text-xs ml-1">
|
||||||
({project.identifier})
|
({project.identifier})
|
||||||
</span>
|
</span>
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4 space-y-3 pl-2">
|
<div className="mt-4 space-y-3 pl-2 w-full">
|
||||||
<div className="flex items-center justify-between gap-2 text-xs">
|
<div className="flex items-center justify-between gap-2 text-xs">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<UserGroupIcon className="h-4 w-4 text-brand-secondary" />
|
<UserGroupIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
<h6>Total members</h6>
|
<h6>Total members</h6>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-brand-secondary">{project.total_members}</span>
|
<span className="text-custom-text-200">{project.total_members}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between gap-2 text-xs">
|
<div className="flex items-center justify-between gap-2 text-xs">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<ContrastIcon height={16} width={16} />
|
<ContrastIcon height={16} width={16} />
|
||||||
<h6>Total cycles</h6>
|
<h6>Total cycles</h6>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-brand-secondary">{project.total_cycles}</span>
|
<span className="text-custom-text-200">{project.total_cycles}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between gap-2 text-xs">
|
<div className="flex items-center justify-between gap-2 text-xs">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<UserGroupIcon className="h-4 w-4 text-brand-secondary" />
|
<UserGroupIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
<h6>Total modules</h6>
|
<h6>Total modules</h6>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-brand-secondary">{project.total_modules}</span>
|
<span className="text-custom-text-200">{project.total_modules}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -280,13 +281,13 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
|||||||
<h4 className="font-medium break-words">Analytics for {cycleDetails.name}</h4>
|
<h4 className="font-medium break-words">Analytics for {cycleDetails.name}</h4>
|
||||||
<div className="space-y-4 mt-4">
|
<div className="space-y-4 mt-4">
|
||||||
<div className="flex items-center gap-2 text-xs">
|
<div className="flex items-center gap-2 text-xs">
|
||||||
<h6 className="text-brand-secondary">Lead</h6>
|
<h6 className="text-custom-text-200">Lead</h6>
|
||||||
<span>
|
<span>
|
||||||
{cycleDetails.owned_by?.first_name} {cycleDetails.owned_by?.last_name}
|
{cycleDetails.owned_by?.first_name} {cycleDetails.owned_by?.last_name}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 text-xs">
|
<div className="flex items-center gap-2 text-xs">
|
||||||
<h6 className="text-brand-secondary">Start Date</h6>
|
<h6 className="text-custom-text-200">Start Date</h6>
|
||||||
<span>
|
<span>
|
||||||
{cycleDetails.start_date && cycleDetails.start_date !== ""
|
{cycleDetails.start_date && cycleDetails.start_date !== ""
|
||||||
? renderShortDate(cycleDetails.start_date)
|
? renderShortDate(cycleDetails.start_date)
|
||||||
@ -294,7 +295,7 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 text-xs">
|
<div className="flex items-center gap-2 text-xs">
|
||||||
<h6 className="text-brand-secondary">Target Date</h6>
|
<h6 className="text-custom-text-200">Target Date</h6>
|
||||||
<span>
|
<span>
|
||||||
{cycleDetails.end_date && cycleDetails.end_date !== ""
|
{cycleDetails.end_date && cycleDetails.end_date !== ""
|
||||||
? renderShortDate(cycleDetails.end_date)
|
? renderShortDate(cycleDetails.end_date)
|
||||||
@ -308,14 +309,14 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
|||||||
<h4 className="font-medium break-words">Analytics for {moduleDetails.name}</h4>
|
<h4 className="font-medium break-words">Analytics for {moduleDetails.name}</h4>
|
||||||
<div className="space-y-4 mt-4">
|
<div className="space-y-4 mt-4">
|
||||||
<div className="flex items-center gap-2 text-xs">
|
<div className="flex items-center gap-2 text-xs">
|
||||||
<h6 className="text-brand-secondary">Lead</h6>
|
<h6 className="text-custom-text-200">Lead</h6>
|
||||||
<span>
|
<span>
|
||||||
{moduleDetails.lead_detail?.first_name}{" "}
|
{moduleDetails.lead_detail?.first_name}{" "}
|
||||||
{moduleDetails.lead_detail?.last_name}
|
{moduleDetails.lead_detail?.last_name}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 text-xs">
|
<div className="flex items-center gap-2 text-xs">
|
||||||
<h6 className="text-brand-secondary">Start Date</h6>
|
<h6 className="text-custom-text-200">Start Date</h6>
|
||||||
<span>
|
<span>
|
||||||
{moduleDetails.start_date && moduleDetails.start_date !== ""
|
{moduleDetails.start_date && moduleDetails.start_date !== ""
|
||||||
? renderShortDate(moduleDetails.start_date)
|
? renderShortDate(moduleDetails.start_date)
|
||||||
@ -323,7 +324,7 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 text-xs">
|
<div className="flex items-center gap-2 text-xs">
|
||||||
<h6 className="text-brand-secondary">Target Date</h6>
|
<h6 className="text-custom-text-200">Target Date</h6>
|
||||||
<span>
|
<span>
|
||||||
{moduleDetails.target_date && moduleDetails.target_date !== ""
|
{moduleDetails.target_date && moduleDetails.target_date !== ""
|
||||||
? renderShortDate(moduleDetails.target_date)
|
? renderShortDate(moduleDetails.target_date)
|
||||||
@ -357,7 +358,7 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className="space-y-4 mt-4">
|
<div className="space-y-4 mt-4">
|
||||||
<div className="flex items-center gap-2 text-xs">
|
<div className="flex items-center gap-2 text-xs">
|
||||||
<h6 className="text-brand-secondary">Network</h6>
|
<h6 className="text-custom-text-200">Network</h6>
|
||||||
<span>
|
<span>
|
||||||
{
|
{
|
||||||
NETWORK_CHOICES[
|
NETWORK_CHOICES[
|
||||||
|
@ -37,9 +37,9 @@ export const AnalyticsTable: React.FC<Props> = ({ analytics, barGraphData, param
|
|||||||
<div className="flow-root">
|
<div className="flow-root">
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
<div className="inline-block min-w-full align-middle">
|
<div className="inline-block min-w-full align-middle">
|
||||||
<table className="min-w-full divide-y divide-brand-base whitespace-nowrap border-y border-brand-base">
|
<table className="min-w-full divide-y divide-custom-border-100 whitespace-nowrap border-y border-custom-border-100">
|
||||||
<thead className="bg-brand-surface-2">
|
<thead className="bg-custom-background-80">
|
||||||
<tr className="divide-x divide-brand-base text-sm text-brand-base">
|
<tr className="divide-x divide-custom-border-100 text-sm text-custom-text-100">
|
||||||
<th scope="col" className="py-3 px-2.5 text-left font-medium">
|
<th scope="col" className="py-3 px-2.5 text-left font-medium">
|
||||||
{ANALYTICS_X_AXIS_VALUES.find((v) => v.value === params.x_axis)?.label}
|
{ANALYTICS_X_AXIS_VALUES.find((v) => v.value === params.x_axis)?.label}
|
||||||
</th>
|
</th>
|
||||||
@ -80,11 +80,11 @@ export const AnalyticsTable: React.FC<Props> = ({ analytics, barGraphData, param
|
|||||||
)}
|
)}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="divide-y divide-brand-base">
|
<tbody className="divide-y divide-custom-border-100">
|
||||||
{barGraphData.data.map((item, index) => (
|
{barGraphData.data.map((item, index) => (
|
||||||
<tr
|
<tr
|
||||||
key={`table-row-${index}`}
|
key={`table-row-${index}`}
|
||||||
className="divide-x divide-brand-base text-xs text-brand-secondary"
|
className="divide-x divide-custom-border-100 text-xs text-custom-text-200"
|
||||||
>
|
>
|
||||||
<td
|
<td
|
||||||
className={`flex items-center gap-2 whitespace-nowrap py-2 px-2.5 font-medium ${
|
className={`flex items-center gap-2 whitespace-nowrap py-2 px-2.5 font-medium ${
|
||||||
|
@ -150,16 +150,16 @@ export const AnalyticsProjectModal: React.FC<Props> = ({ isOpen, onClose }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`absolute top-0 z-30 h-full bg-brand-surface-1 ${
|
className={`absolute top-0 z-30 h-full bg-custom-background-90 ${
|
||||||
fullScreen ? "p-2 w-full" : "w-1/2"
|
fullScreen ? "p-2 w-full" : "w-1/2"
|
||||||
} ${isOpen ? "right-0" : "-right-full"} duration-300 transition-all`}
|
} ${isOpen ? "right-0" : "-right-full"} duration-300 transition-all`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`flex h-full flex-col overflow-hidden border-brand-base bg-brand-base text-left ${
|
className={`flex h-full flex-col overflow-hidden border-custom-border-100 bg-custom-background-100 text-left ${
|
||||||
fullScreen ? "rounded-lg border" : "border-l"
|
fullScreen ? "rounded-lg border" : "border-l"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between gap-4 bg-brand-base px-5 py-4 text-sm">
|
<div className="flex items-center justify-between gap-4 bg-custom-background-100 px-5 py-4 text-sm">
|
||||||
<h3 className="break-words">
|
<h3 className="break-words">
|
||||||
Analytics for{" "}
|
Analytics for{" "}
|
||||||
{cycleId ? cycleDetails?.name : moduleId ? moduleDetails?.name : projectDetails?.name}
|
{cycleId ? cycleDetails?.name : moduleId ? moduleDetails?.name : projectDetails?.name}
|
||||||
@ -167,7 +167,7 @@ export const AnalyticsProjectModal: React.FC<Props> = ({ isOpen, onClose }) => {
|
|||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="grid place-items-center p-1 text-brand-secondary hover:text-brand-base"
|
className="grid place-items-center p-1 text-custom-text-200 hover:text-custom-text-100"
|
||||||
onClick={() => setFullScreen((prevData) => !prevData)}
|
onClick={() => setFullScreen((prevData) => !prevData)}
|
||||||
>
|
>
|
||||||
{fullScreen ? (
|
{fullScreen ? (
|
||||||
@ -178,7 +178,7 @@ export const AnalyticsProjectModal: React.FC<Props> = ({ isOpen, onClose }) => {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="grid place-items-center p-1 text-brand-secondary hover:text-brand-base"
|
className="grid place-items-center p-1 text-custom-text-200 hover:text-custom-text-100"
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
>
|
>
|
||||||
<XMarkIcon className="h-4 w-4" />
|
<XMarkIcon className="h-4 w-4" />
|
||||||
@ -186,13 +186,13 @@ export const AnalyticsProjectModal: React.FC<Props> = ({ isOpen, onClose }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Tab.Group as={Fragment}>
|
<Tab.Group as={Fragment}>
|
||||||
<Tab.List as="div" className="space-x-2 border-b border-brand-base p-5 pt-0">
|
<Tab.List as="div" className="space-x-2 border-b border-custom-border-100 p-5 pt-0">
|
||||||
{tabsList.map((tab) => (
|
{tabsList.map((tab) => (
|
||||||
<Tab
|
<Tab
|
||||||
key={tab}
|
key={tab}
|
||||||
className={({ selected }) =>
|
className={({ selected }) =>
|
||||||
`rounded-3xl border border-brand-base px-4 py-2 text-xs hover:bg-brand-surface-2 ${
|
`rounded-3xl border border-custom-border-100 px-4 py-2 text-xs hover:bg-custom-background-80 ${
|
||||||
selected ? "bg-brand-surface-2" : ""
|
selected ? "bg-custom-background-80" : ""
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
onClick={() => trackAnalyticsEvent(tab)}
|
onClick={() => trackAnalyticsEvent(tab)}
|
||||||
|
@ -10,10 +10,10 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const AnalyticsDemand: React.FC<Props> = ({ defaultAnalytics }) => (
|
export const AnalyticsDemand: React.FC<Props> = ({ defaultAnalytics }) => (
|
||||||
<div className="space-y-3 rounded-[10px] border border-brand-base p-3">
|
<div className="space-y-3 rounded-[10px] border border-custom-border-100 p-3">
|
||||||
<h5 className="text-xs text-red-500">DEMAND</h5>
|
<h5 className="text-xs text-red-500">DEMAND</h5>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="text-brand-bas text-base font-medium">Total open tasks</h4>
|
<h4 className="text-custom-text-100 text-base font-medium">Total open tasks</h4>
|
||||||
<h3 className="mt-1 text-xl font-semibold">{defaultAnalytics.open_issues}</h3>
|
<h3 className="mt-1 text-xl font-semibold">{defaultAnalytics.open_issues}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
@ -31,13 +31,13 @@ export const AnalyticsDemand: React.FC<Props> = ({ defaultAnalytics }) => (
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<h6 className="capitalize">{group.state_group}</h6>
|
<h6 className="capitalize">{group.state_group}</h6>
|
||||||
<span className="ml-1 rounded-3xl bg-brand-surface-2 px-2 py-0.5 text-[0.65rem] text-brand-secondary">
|
<span className="ml-1 rounded-3xl bg-custom-background-80 px-2 py-0.5 text-[0.65rem] text-custom-text-200">
|
||||||
{group.state_count}
|
{group.state_count}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-brand-secondary">{percentage}%</p>
|
<p className="text-custom-text-200">{percentage}%</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="bar relative h-1 w-full rounded bg-brand-surface-2">
|
<div className="bar relative h-1 w-full rounded bg-custom-background-80">
|
||||||
<div
|
<div
|
||||||
className="absolute top-0 left-0 h-1 rounded duration-300"
|
className="absolute top-0 left-0 h-1 rounded duration-300"
|
||||||
style={{
|
style={{
|
||||||
@ -50,8 +50,8 @@ export const AnalyticsDemand: React.FC<Props> = ({ defaultAnalytics }) => (
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className="!mt-6 flex w-min items-center gap-2 whitespace-nowrap rounded-md border border-brand-base bg-brand-surface-2 p-2 text-xs">
|
<div className="!mt-6 flex w-min items-center gap-2 whitespace-nowrap rounded-md border border-custom-border-100 bg-custom-background-80 p-2 text-xs">
|
||||||
<p className="flex items-center gap-1 text-brand-secondary">
|
<p className="flex items-center gap-1 text-custom-text-200">
|
||||||
<PlayIcon className="h-4 w-4 -rotate-90" aria-hidden="true" />
|
<PlayIcon className="h-4 w-4 -rotate-90" aria-hidden="true" />
|
||||||
<span>Estimate Demand:</span>
|
<span>Estimate Demand:</span>
|
||||||
</p>
|
</p>
|
||||||
|
@ -10,7 +10,7 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const AnalyticsLeaderboard: React.FC<Props> = ({ users, title }) => (
|
export const AnalyticsLeaderboard: React.FC<Props> = ({ users, title }) => (
|
||||||
<div className="p-3 border border-brand-base rounded-[10px]">
|
<div className="p-3 border border-custom-border-100 rounded-[10px]">
|
||||||
<h6 className="text-base font-medium">{title}</h6>
|
<h6 className="text-base font-medium">{title}</h6>
|
||||||
{users.length > 0 ? (
|
{users.length > 0 ? (
|
||||||
<div className="mt-3 space-y-3">
|
<div className="mt-3 space-y-3">
|
||||||
@ -33,7 +33,7 @@ export const AnalyticsLeaderboard: React.FC<Props> = ({ users, title }) => (
|
|||||||
{user.firstName !== "" ? user.firstName[0] : "?"}
|
{user.firstName !== "" ? user.firstName[0] : "?"}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<span className="break-words text-brand-secondary">
|
<span className="break-words text-custom-text-200">
|
||||||
{user.firstName !== "" ? `${user.firstName} ${user.lastName}` : "No assignee"}
|
{user.firstName !== "" ? `${user.firstName} ${user.lastName}` : "No assignee"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -42,7 +42,7 @@ export const AnalyticsLeaderboard: React.FC<Props> = ({ users, title }) => (
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-brand-secondary text-center text-sm py-8">No matching data found.</div>
|
<div className="text-custom-text-200 text-center text-sm py-8">No matching data found.</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -88,7 +88,7 @@ export const ScopeAndDemand: React.FC<Props> = ({ fullScreen = true }) => {
|
|||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
<div className="grid h-full place-items-center p-5">
|
<div className="grid h-full place-items-center p-5">
|
||||||
<div className="space-y-4 text-brand-secondary">
|
<div className="space-y-4 text-custom-text-200">
|
||||||
<p className="text-sm">There was some error in fetching the data.</p>
|
<p className="text-sm">There was some error in fetching the data.</p>
|
||||||
<div className="flex items-center justify-center gap-2">
|
<div className="flex items-center justify-center gap-2">
|
||||||
<PrimaryButton onClick={() => mutateDefaultAnalytics()}>Refresh</PrimaryButton>
|
<PrimaryButton onClick={() => mutateDefaultAnalytics()}>Refresh</PrimaryButton>
|
||||||
|
@ -8,9 +8,9 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const AnalyticsScope: React.FC<Props> = ({ defaultAnalytics }) => (
|
export const AnalyticsScope: React.FC<Props> = ({ defaultAnalytics }) => (
|
||||||
<div className="rounded-[10px] border border-brand-base">
|
<div className="rounded-[10px] border border-custom-border-100">
|
||||||
<h5 className="p-3 text-xs text-green-500">SCOPE</h5>
|
<h5 className="p-3 text-xs text-green-500">SCOPE</h5>
|
||||||
<div className="divide-y divide-brand-base">
|
<div className="divide-y divide-custom-border-100">
|
||||||
<div>
|
<div>
|
||||||
<h6 className="px-3 text-base font-medium">Pending issues</h6>
|
<h6 className="px-3 text-base font-medium">Pending issues</h6>
|
||||||
{defaultAnalytics.pending_issue_user.length > 0 ? (
|
{defaultAnalytics.pending_issue_user.length > 0 ? (
|
||||||
@ -27,8 +27,8 @@ export const AnalyticsScope: React.FC<Props> = ({ defaultAnalytics }) => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-md border border-brand-base bg-brand-surface-2 p-2 text-xs">
|
<div className="rounded-md border border-custom-border-100 bg-custom-background-80 p-2 text-xs">
|
||||||
<span className="font-medium text-brand-secondary">
|
<span className="font-medium text-custom-text-200">
|
||||||
{assignee
|
{assignee
|
||||||
? assignee.assignees__first_name + " " + assignee.assignees__last_name
|
? assignee.assignees__first_name + " " + assignee.assignees__last_name
|
||||||
: "No assignee"}
|
: "No assignee"}
|
||||||
@ -69,12 +69,11 @@ export const AnalyticsScope: React.FC<Props> = ({ defaultAnalytics }) => (
|
|||||||
}}
|
}}
|
||||||
margin={{ top: 20 }}
|
margin={{ top: 20 }}
|
||||||
theme={{
|
theme={{
|
||||||
background: "rgb(var(--color-bg-base))",
|
|
||||||
axis: {},
|
axis: {},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-brand-secondary text-center text-sm py-8">
|
<div className="text-custom-text-200 text-center text-sm py-8">
|
||||||
No matching data found.
|
No matching data found.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -15,14 +15,14 @@ export const AnalyticsYearWiseIssues: React.FC<Props> = ({ defaultAnalytics }) =
|
|||||||
const quarterMonthsList = [startMonth, startMonth + 1, startMonth + 2];
|
const quarterMonthsList = [startMonth, startMonth + 1, startMonth + 2];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="py-3 border border-brand-base rounded-[10px]">
|
<div className="py-3 border border-custom-border-100 rounded-[10px]">
|
||||||
<h1 className="px-3 text-base font-medium">Issues closed in a year</h1>
|
<h1 className="px-3 text-base font-medium">Issues closed in a year</h1>
|
||||||
{defaultAnalytics.issue_completed_month_wise.length > 0 ? (
|
{defaultAnalytics.issue_completed_month_wise.length > 0 ? (
|
||||||
<LineGraph
|
<LineGraph
|
||||||
data={[
|
data={[
|
||||||
{
|
{
|
||||||
id: "issues_closed",
|
id: "issues_closed",
|
||||||
color: "rgb(var(--color-accent))",
|
color: "rgb(var(--color-primary-100))",
|
||||||
data: MONTHS_LIST.map((month) => ({
|
data: MONTHS_LIST.map((month) => ({
|
||||||
x: month.label.substring(0, 3),
|
x: month.label.substring(0, 3),
|
||||||
y:
|
y:
|
||||||
@ -43,19 +43,19 @@ export const AnalyticsYearWiseIssues: React.FC<Props> = ({ defaultAnalytics }) =
|
|||||||
margin={{ top: 20 }}
|
margin={{ top: 20 }}
|
||||||
enableSlices="x"
|
enableSlices="x"
|
||||||
sliceTooltip={(datum) => (
|
sliceTooltip={(datum) => (
|
||||||
<div className="rounded-md border border-brand-base bg-brand-surface-2 p-2 text-xs">
|
<div className="rounded-md border border-custom-border-100 bg-custom-background-80 p-2 text-xs">
|
||||||
{datum.slice.points[0].data.yFormatted}
|
{datum.slice.points[0].data.yFormatted}
|
||||||
<span className="text-brand-secondary"> issues closed in </span>
|
<span className="text-custom-text-200"> issues closed in </span>
|
||||||
{datum.slice.points[0].data.xFormatted}
|
{datum.slice.points[0].data.xFormatted}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
theme={{
|
theme={{
|
||||||
background: "rgb(var(--color-bg-base))",
|
background: "rgb(var(--color-background-100))",
|
||||||
}}
|
}}
|
||||||
enableArea
|
enableArea
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-brand-secondary text-center text-sm py-8">No matching data found.</div>
|
<div className="text-custom-text-200 text-center text-sm py-8">No matching data found.</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -15,7 +15,7 @@ export const SelectProject: React.FC<Props> = ({ value, onChange, projects }) =>
|
|||||||
query: project.name + project.identifier,
|
query: project.name + project.identifier,
|
||||||
content: (
|
content: (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="text-brand-secondary text-[0.65rem]">{project.identifier}</span>
|
<span className="text-custom-text-200 text-[0.65rem]">{project.identifier}</span>
|
||||||
{project.name}
|
{project.name}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
|
@ -23,7 +23,7 @@ export const SelectSegment: React.FC<Props> = ({ value, onChange, params }) => {
|
|||||||
label={
|
label={
|
||||||
<span>
|
<span>
|
||||||
{ANALYTICS_X_AXIS_VALUES.find((v) => v.value === value)?.label ?? (
|
{ANALYTICS_X_AXIS_VALUES.find((v) => v.value === value)?.label ?? (
|
||||||
<span className="text-brand-secondary">No value</span>
|
<span className="text-custom-text-200">No value</span>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ export const NotAuthorizedView: React.FC<Props> = ({ actionButton, type }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<DefaultLayout>
|
<DefaultLayout>
|
||||||
<div className="flex h-full w-full flex-col items-center justify-center gap-y-5 bg-brand-surface-1 text-center">
|
<div className="flex h-full w-full flex-col items-center justify-center gap-y-5 bg-custom-background-90 text-center">
|
||||||
<div className="h-44 w-72">
|
<div className="h-44 w-72">
|
||||||
<Image
|
<Image
|
||||||
src={type === "project" ? ProjectNotAuthorizedImg : WorkspaceNotAuthorizedImg}
|
src={type === "project" ? ProjectNotAuthorizedImg : WorkspaceNotAuthorizedImg}
|
||||||
@ -31,16 +31,16 @@ export const NotAuthorizedView: React.FC<Props> = ({ actionButton, type }) => {
|
|||||||
alt="ProjectSettingImg"
|
alt="ProjectSettingImg"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-xl font-medium text-brand-base">
|
<h1 className="text-xl font-medium text-custom-text-100">
|
||||||
Oops! You are not authorized to view this page
|
Oops! You are not authorized to view this page
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div className="w-full max-w-md text-base text-brand-secondary">
|
<div className="w-full max-w-md text-base text-custom-text-200">
|
||||||
{user ? (
|
{user ? (
|
||||||
<p>
|
<p>
|
||||||
You have signed in as {user.email}. <br />
|
You have signed in as {user.email}. <br />
|
||||||
<Link href={`/?next=${currentPath}`}>
|
<Link href={`/?next=${currentPath}`}>
|
||||||
<a className="font-medium text-brand-base">Sign in</a>
|
<a className="font-medium text-custom-text-100">Sign in</a>
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
with different account that has access to this page.
|
with different account that has access to this page.
|
||||||
</p>
|
</p>
|
||||||
@ -48,7 +48,7 @@ export const NotAuthorizedView: React.FC<Props> = ({ actionButton, type }) => {
|
|||||||
<p>
|
<p>
|
||||||
You need to{" "}
|
You need to{" "}
|
||||||
<Link href={`/?next=${currentPath}`}>
|
<Link href={`/?next=${currentPath}`}>
|
||||||
<a className="font-medium text-brand-base">Sign in</a>
|
<a className="font-medium text-custom-text-100">Sign in</a>
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
with an account that has access to this page.
|
with an account that has access to this page.
|
||||||
</p>
|
</p>
|
||||||
|
@ -41,13 +41,15 @@ export const JoinProject: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full flex-col items-center justify-center gap-y-5 bg-brand-surface-1 text-center">
|
<div className="flex h-full w-full flex-col items-center justify-center gap-y-5 bg-custom-background-90 text-center">
|
||||||
<div className="h-44 w-72">
|
<div className="h-44 w-72">
|
||||||
<Image src={JoinProjectImg} height="176" width="288" alt="JoinProject" />
|
<Image src={JoinProjectImg} height="176" width="288" alt="JoinProject" />
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-xl font-medium text-brand-base">You are not a member of this project</h1>
|
<h1 className="text-xl font-medium text-custom-text-100">
|
||||||
|
You are not a member of this project
|
||||||
|
</h1>
|
||||||
|
|
||||||
<div className="w-full max-w-md text-base text-brand-secondary">
|
<div className="w-full max-w-md text-base text-custom-text-200">
|
||||||
<p className="mx-auto w-full text-sm md:w-3/4">
|
<p className="mx-auto w-full text-sm md:w-3/4">
|
||||||
You are not a member of this project, but you can join this project by clicking the button
|
You are not a member of this project, but you can join this project by clicking the button
|
||||||
below.
|
below.
|
||||||
|
@ -11,7 +11,7 @@ export const NotAWorkspaceMember = () => (
|
|||||||
<div className="space-y-8 text-center">
|
<div className="space-y-8 text-center">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<h3 className="text-lg font-semibold">Not Authorized!</h3>
|
<h3 className="text-lg font-semibold">Not Authorized!</h3>
|
||||||
<p className="mx-auto w-1/2 text-sm text-brand-secondary">
|
<p className="mx-auto w-1/2 text-sm text-custom-text-200">
|
||||||
You{"'"}re not a member of this workspace. Please contact the workspace admin to get an
|
You{"'"}re not a member of this workspace. Please contact the workspace admin to get an
|
||||||
invitation or check your pending invitations.
|
invitation or check your pending invitations.
|
||||||
</p>
|
</p>
|
||||||
|
@ -17,12 +17,12 @@ const Breadcrumbs = ({ children }: BreadcrumbsProps) => {
|
|||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="group grid h-7 w-7 flex-shrink-0 cursor-pointer place-items-center rounded border border-brand-base text-center text-sm hover:bg-brand-surface-1"
|
className="group grid h-7 w-7 flex-shrink-0 cursor-pointer place-items-center rounded border border-custom-sidebar-border-100 text-center text-sm hover:bg-custom-sidebar-background-90"
|
||||||
onClick={() => router.back()}
|
onClick={() => router.back()}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
iconName="keyboard_backspace"
|
iconName="keyboard_backspace"
|
||||||
className="text-base leading-4 text-brand-secondary group-hover:text-brand-base"
|
className="text-base leading-4 text-custom-sidebar-text-200 group-hover:text-custom-sidebar-text-100"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
{children}
|
{children}
|
||||||
@ -41,7 +41,7 @@ const BreadcrumbItem: React.FC<BreadcrumbItemProps> = ({ title, link, icon }) =>
|
|||||||
<>
|
<>
|
||||||
{link ? (
|
{link ? (
|
||||||
<Link href={link}>
|
<Link href={link}>
|
||||||
<a className="border-r-2 border-brand-base px-3 text-sm">
|
<a className="border-r-2 border-custom-sidebar-border-100 px-3 text-sm">
|
||||||
<p className={`${icon ? "flex items-center gap-2" : ""}`}>
|
<p className={`${icon ? "flex items-center gap-2" : ""}`}>
|
||||||
{icon ?? null}
|
{icon ?? null}
|
||||||
{title}
|
{title}
|
||||||
|
@ -34,8 +34,8 @@ export const ChangeInterfaceTheme: React.FC<Props> = ({ setIsPaletteOpen }) => {
|
|||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<SettingIcon className="h-4 w-4 text-brand-secondary" />
|
<SettingIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
{theme.label}
|
{theme.label}
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
|
@ -408,7 +408,7 @@ export const CommandPalette: React.FC = () => {
|
|||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<div className="fixed inset-0 bg-brand-backdrop bg-opacity-50 transition-opacity" />
|
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
|
|
||||||
<div className="fixed inset-0 z-30 overflow-y-auto p-4 sm:p-6 md:p-20">
|
<div className="fixed inset-0 z-30 overflow-y-auto p-4 sm:p-6 md:p-20">
|
||||||
@ -421,7 +421,7 @@ export const CommandPalette: React.FC = () => {
|
|||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative mx-auto max-w-2xl transform divide-y divide-brand-base divide-opacity-10 rounded-xl border border-brand-base bg-brand-base shadow-2xl transition-all">
|
<Dialog.Panel className="relative mx-auto max-w-2xl transform divide-y divide-custom-border-100 divide-opacity-10 rounded-xl border border-custom-border-100 bg-custom-background-100 shadow-2xl transition-all">
|
||||||
<Command
|
<Command
|
||||||
filter={(value, search) => {
|
filter={(value, search) => {
|
||||||
if (value.toLowerCase().includes(search.toLowerCase())) return 1;
|
if (value.toLowerCase().includes(search.toLowerCase())) return 1;
|
||||||
@ -444,7 +444,7 @@ export const CommandPalette: React.FC = () => {
|
|||||||
>
|
>
|
||||||
{issueId && issueDetails && (
|
{issueId && issueDetails && (
|
||||||
<div className="flex p-3">
|
<div className="flex p-3">
|
||||||
<p className="overflow-hidden truncate rounded-md bg-brand-surface-1 p-1 px-2 text-xs font-medium text-brand-secondary">
|
<p className="overflow-hidden truncate rounded-md bg-custom-background-90 p-1 px-2 text-xs font-medium text-custom-text-200">
|
||||||
{issueDetails.project_detail?.identifier}-{issueDetails.sequence_id}{" "}
|
{issueDetails.project_detail?.identifier}-{issueDetails.sequence_id}{" "}
|
||||||
{issueDetails?.name}
|
{issueDetails?.name}
|
||||||
</p>
|
</p>
|
||||||
@ -452,11 +452,11 @@ export const CommandPalette: React.FC = () => {
|
|||||||
)}
|
)}
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<MagnifyingGlassIcon
|
<MagnifyingGlassIcon
|
||||||
className="pointer-events-none absolute top-3.5 left-4 h-5 w-5 text-brand-secondary"
|
className="pointer-events-none absolute top-3.5 left-4 h-5 w-5 text-custom-text-200"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
<Command.Input
|
<Command.Input
|
||||||
className="w-full border-0 border-b border-brand-base bg-transparent p-4 pl-11 text-brand-base placeholder-gray-500 outline-none focus:ring-0 sm:text-sm"
|
className="w-full border-0 border-b border-custom-border-100 bg-transparent p-4 pl-11 text-custom-text-100 outline-none focus:ring-0 sm:text-sm"
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onValueChange={(e) => {
|
onValueChange={(e) => {
|
||||||
@ -470,7 +470,7 @@ export const CommandPalette: React.FC = () => {
|
|||||||
resultsCount === 0 &&
|
resultsCount === 0 &&
|
||||||
searchTerm !== "" &&
|
searchTerm !== "" &&
|
||||||
debouncedSearchTerm !== "" && (
|
debouncedSearchTerm !== "" && (
|
||||||
<div className="my-4 text-center text-brand-secondary">
|
<div className="my-4 text-center text-custom-text-200">
|
||||||
No results found.
|
No results found.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -533,9 +533,9 @@ export const CommandPalette: React.FC = () => {
|
|||||||
value={value}
|
value={value}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 overflow-hidden text-brand-secondary">
|
<div className="flex items-center gap-2 overflow-hidden text-custom-text-200">
|
||||||
<Icon
|
<Icon
|
||||||
className="h-4 w-4 text-brand-secondary"
|
className="h-4 w-4 text-custom-text-200"
|
||||||
color="#6b7280"
|
color="#6b7280"
|
||||||
/>
|
/>
|
||||||
<p className="block flex-1 truncate">{item.name}</p>
|
<p className="block flex-1 truncate">{item.name}</p>
|
||||||
@ -562,8 +562,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<Squares2X2Icon className="h-4 w-4 text-brand-secondary" />
|
<Squares2X2Icon className="h-4 w-4 text-custom-text-200" />
|
||||||
Change state...
|
Change state...
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
@ -575,8 +575,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<ChartBarIcon className="h-4 w-4 text-brand-secondary" />
|
<ChartBarIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Change priority...
|
Change priority...
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
@ -588,8 +588,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<UsersIcon className="h-4 w-4 text-brand-secondary" />
|
<UsersIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Assign to...
|
Assign to...
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
@ -600,15 +600,15 @@ export const CommandPalette: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
{issueDetails?.assignees.includes(user.id) ? (
|
{issueDetails?.assignees.includes(user.id) ? (
|
||||||
<>
|
<>
|
||||||
<UserMinusIcon className="h-4 w-4 text-brand-secondary" />
|
<UserMinusIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Un-assign from me
|
Un-assign from me
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<UserPlusIcon className="h-4 w-4 text-brand-secondary" />
|
<UserPlusIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Assign to me
|
Assign to me
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -616,8 +616,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
</Command.Item>
|
</Command.Item>
|
||||||
|
|
||||||
<Command.Item onSelect={deleteIssue} className="focus:outline-none">
|
<Command.Item onSelect={deleteIssue} className="focus:outline-none">
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<TrashIcon className="h-4 w-4 text-brand-secondary" />
|
<TrashIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Delete issue
|
Delete issue
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
@ -628,8 +628,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<LinkIcon className="h-4 w-4 text-brand-secondary" />
|
<LinkIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Copy issue URL to clipboard
|
Copy issue URL to clipboard
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
@ -638,9 +638,9 @@ export const CommandPalette: React.FC = () => {
|
|||||||
<Command.Group heading="Issue">
|
<Command.Group heading="Issue">
|
||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={createNewIssue}
|
onSelect={createNewIssue}
|
||||||
className="focus:bg-brand-surface-2"
|
className="focus:bg-custom-background-80"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<LayerDiagonalIcon className="h-4 w-4" color="#6b7280" />
|
<LayerDiagonalIcon className="h-4 w-4" color="#6b7280" />
|
||||||
Create new issue
|
Create new issue
|
||||||
</div>
|
</div>
|
||||||
@ -654,7 +654,7 @@ export const CommandPalette: React.FC = () => {
|
|||||||
onSelect={createNewProject}
|
onSelect={createNewProject}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<AssignmentClipboardIcon className="h-4 w-4" color="#6b7280" />
|
<AssignmentClipboardIcon className="h-4 w-4" color="#6b7280" />
|
||||||
Create new project
|
Create new project
|
||||||
</div>
|
</div>
|
||||||
@ -670,7 +670,7 @@ export const CommandPalette: React.FC = () => {
|
|||||||
onSelect={createNewCycle}
|
onSelect={createNewCycle}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<ContrastIcon className="h-4 w-4" color="#6b7280" />
|
<ContrastIcon className="h-4 w-4" color="#6b7280" />
|
||||||
Create new cycle
|
Create new cycle
|
||||||
</div>
|
</div>
|
||||||
@ -683,7 +683,7 @@ export const CommandPalette: React.FC = () => {
|
|||||||
onSelect={createNewModule}
|
onSelect={createNewModule}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<PeopleGroupIcon className="h-4 w-4" color="#6b7280" />
|
<PeopleGroupIcon className="h-4 w-4" color="#6b7280" />
|
||||||
Create new module
|
Create new module
|
||||||
</div>
|
</div>
|
||||||
@ -693,7 +693,7 @@ export const CommandPalette: React.FC = () => {
|
|||||||
|
|
||||||
<Command.Group heading="View">
|
<Command.Group heading="View">
|
||||||
<Command.Item onSelect={createNewView} className="focus:outline-none">
|
<Command.Item onSelect={createNewView} className="focus:outline-none">
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<ViewListIcon className="h-4 w-4" color="#6b7280" />
|
<ViewListIcon className="h-4 w-4" color="#6b7280" />
|
||||||
Create new view
|
Create new view
|
||||||
</div>
|
</div>
|
||||||
@ -703,7 +703,7 @@ export const CommandPalette: React.FC = () => {
|
|||||||
|
|
||||||
<Command.Group heading="Page">
|
<Command.Group heading="Page">
|
||||||
<Command.Item onSelect={createNewPage} className="focus:outline-none">
|
<Command.Item onSelect={createNewPage} className="focus:outline-none">
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<DocumentTextIcon className="h-4 w-4" color="#6b7280" />
|
<DocumentTextIcon className="h-4 w-4" color="#6b7280" />
|
||||||
Create new page
|
Create new page
|
||||||
</div>
|
</div>
|
||||||
@ -721,7 +721,7 @@ export const CommandPalette: React.FC = () => {
|
|||||||
}
|
}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<InboxIcon className="h-4 w-4" color="#6b7280" />
|
<InboxIcon className="h-4 w-4" color="#6b7280" />
|
||||||
Open inbox
|
Open inbox
|
||||||
</div>
|
</div>
|
||||||
@ -740,7 +740,7 @@ export const CommandPalette: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<SettingIcon className="h-4 w-4" color="#6b7280" />
|
<SettingIcon className="h-4 w-4" color="#6b7280" />
|
||||||
Search settings...
|
Search settings...
|
||||||
</div>
|
</div>
|
||||||
@ -751,8 +751,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
onSelect={createNewWorkspace}
|
onSelect={createNewWorkspace}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<FolderPlusIcon className="h-4 w-4 text-brand-secondary" />
|
<FolderPlusIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Create new workspace
|
Create new workspace
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
@ -764,8 +764,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<SettingIcon className="h-4 w-4 text-brand-secondary" />
|
<SettingIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Change interface theme...
|
Change interface theme...
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
@ -781,8 +781,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<RocketLaunchIcon className="h-4 w-4 text-brand-secondary" />
|
<RocketLaunchIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Open keyboard shortcuts
|
Open keyboard shortcuts
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
@ -793,8 +793,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<DocumentIcon className="h-4 w-4 text-brand-secondary" />
|
<DocumentIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Open Plane documentation
|
Open Plane documentation
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
@ -805,7 +805,7 @@ export const CommandPalette: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<DiscordIcon className="h-4 w-4" color="#6b7280" />
|
<DiscordIcon className="h-4 w-4" color="#6b7280" />
|
||||||
Join our Discord
|
Join our Discord
|
||||||
</div>
|
</div>
|
||||||
@ -820,7 +820,7 @@ export const CommandPalette: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<GithubIcon className="h-4 w-4" color="#6b7280" />
|
<GithubIcon className="h-4 w-4" color="#6b7280" />
|
||||||
Report a bug
|
Report a bug
|
||||||
</div>
|
</div>
|
||||||
@ -832,8 +832,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<ChatBubbleOvalLeftEllipsisIcon className="h-4 w-4 text-brand-secondary" />
|
<ChatBubbleOvalLeftEllipsisIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Chat with us
|
Chat with us
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
@ -847,8 +847,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
onSelect={() => redirect(`/${workspaceSlug}/settings`)}
|
onSelect={() => redirect(`/${workspaceSlug}/settings`)}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<SettingIcon className="h-4 w-4 text-brand-secondary" />
|
<SettingIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
General
|
General
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
@ -856,8 +856,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
onSelect={() => redirect(`/${workspaceSlug}/settings/members`)}
|
onSelect={() => redirect(`/${workspaceSlug}/settings/members`)}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<SettingIcon className="h-4 w-4 text-brand-secondary" />
|
<SettingIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Members
|
Members
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
@ -865,8 +865,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
onSelect={() => redirect(`/${workspaceSlug}/settings/billing`)}
|
onSelect={() => redirect(`/${workspaceSlug}/settings/billing`)}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<SettingIcon className="h-4 w-4 text-brand-secondary" />
|
<SettingIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Billing and Plans
|
Billing and Plans
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
@ -874,8 +874,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
onSelect={() => redirect(`/${workspaceSlug}/settings/integrations`)}
|
onSelect={() => redirect(`/${workspaceSlug}/settings/integrations`)}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<SettingIcon className="h-4 w-4 text-brand-secondary" />
|
<SettingIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Integrations
|
Integrations
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
@ -883,8 +883,8 @@ export const CommandPalette: React.FC = () => {
|
|||||||
onSelect={() => redirect(`/${workspaceSlug}/settings/import-export`)}
|
onSelect={() => redirect(`/${workspaceSlug}/settings/import-export`)}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 text-brand-secondary">
|
<div className="flex items-center gap-2 text-custom-text-200">
|
||||||
<SettingIcon className="h-4 w-4 text-brand-secondary" />
|
<SettingIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Import/Export
|
Import/Export
|
||||||
</div>
|
</div>
|
||||||
</Command.Item>
|
</Command.Item>
|
||||||
|
@ -85,29 +85,29 @@ export const ShortcutsModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
|
|||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-brand-surface-2 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg">
|
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-custom-background-80 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg">
|
||||||
<div className="bg-brand-surface-2 p-5">
|
<div className="bg-custom-background-80 p-5">
|
||||||
<div className="sm:flex sm:items-start">
|
<div className="sm:flex sm:items-start">
|
||||||
<div className="flex w-full flex-col gap-y-4 text-center sm:text-left">
|
<div className="flex w-full flex-col gap-y-4 text-center sm:text-left">
|
||||||
<Dialog.Title
|
<Dialog.Title
|
||||||
as="h3"
|
as="h3"
|
||||||
className="flex justify-between text-lg font-medium leading-6 text-brand-base"
|
className="flex justify-between text-lg font-medium leading-6 text-custom-text-100"
|
||||||
>
|
>
|
||||||
<span>Keyboard Shortcuts</span>
|
<span>Keyboard Shortcuts</span>
|
||||||
<span>
|
<span>
|
||||||
<button type="button" onClick={() => setIsOpen(false)}>
|
<button type="button" onClick={() => setIsOpen(false)}>
|
||||||
<XMarkIcon
|
<XMarkIcon
|
||||||
className="h-6 w-6 text-gray-400 hover:text-brand-secondary"
|
className="h-6 w-6 text-custom-text-200 hover:text-custom-text-100"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</Dialog.Title>
|
</Dialog.Title>
|
||||||
<div>
|
<div>
|
||||||
<div className="flex w-full items-center justify-start gap-1 rounded border-[0.6px] border-brand-base bg-brand-surface-1 px-3 py-2">
|
<div className="flex w-full items-center justify-start gap-1 rounded border-[0.6px] border-custom-border-100 bg-custom-background-90 px-3 py-2">
|
||||||
<MagnifyingGlassIcon className="h-3.5 w-3.5 text-brand-secondary" />
|
<MagnifyingGlassIcon className="h-3.5 w-3.5 text-custom-text-200" />
|
||||||
<Input
|
<Input
|
||||||
className="w-full border-none bg-transparent py-1 px-2 text-xs text-brand-secondary focus:outline-none"
|
className="w-full border-none bg-transparent py-1 px-2 text-xs text-custom-text-200 focus:outline-none"
|
||||||
id="search"
|
id="search"
|
||||||
name="search"
|
name="search"
|
||||||
type="text"
|
type="text"
|
||||||
@ -123,22 +123,22 @@ export const ShortcutsModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
|
|||||||
<div key={shortcut.keys} className="flex w-full flex-col">
|
<div key={shortcut.keys} className="flex w-full flex-col">
|
||||||
<div className="flex flex-col gap-y-3">
|
<div className="flex flex-col gap-y-3">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<p className="text-sm text-brand-secondary">
|
<p className="text-sm text-custom-text-200">
|
||||||
{shortcut.description}
|
{shortcut.description}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center gap-x-2.5">
|
<div className="flex items-center gap-x-2.5">
|
||||||
{shortcut.keys.split(",").map((key, index) => (
|
{shortcut.keys.split(",").map((key, index) => (
|
||||||
<span key={index} className="flex items-center gap-1">
|
<span key={index} className="flex items-center gap-1">
|
||||||
{key === "Ctrl" ? (
|
{key === "Ctrl" ? (
|
||||||
<span className="flex h-full items-center rounded-sm border border-brand-base bg-brand-surface-1 p-1.5">
|
<span className="flex h-full items-center rounded-sm border border-custom-border-100 bg-custom-background-90 p-1.5">
|
||||||
<CommandIcon className="h-4 w-4 fill-current text-brand-secondary" />
|
<CommandIcon className="h-4 w-4 fill-current text-custom-text-200" />
|
||||||
</span>
|
</span>
|
||||||
) : key === "Ctrl" ? (
|
) : key === "Ctrl" ? (
|
||||||
<kbd className="rounded-sm border border-brand-base bg-brand-surface-1 p-1.5 text-sm font-medium text-brand-secondary">
|
<kbd className="rounded-sm border border-custom-border-100 bg-custom-background-90 p-1.5 text-sm font-medium text-custom-text-200">
|
||||||
<CommandIcon className="h-4 w-4 fill-current text-brand-secondary" />
|
<CommandIcon className="h-4 w-4 fill-current text-custom-text-200" />
|
||||||
</kbd>
|
</kbd>
|
||||||
) : (
|
) : (
|
||||||
<kbd className="rounded-sm border border-brand-base bg-brand-surface-1 px-2 py-1 text-sm font-medium text-brand-secondary">
|
<kbd className="rounded-sm border border-custom-border-100 bg-custom-background-90 px-2 py-1 text-sm font-medium text-custom-text-200">
|
||||||
{key}
|
{key}
|
||||||
</kbd>
|
</kbd>
|
||||||
)}
|
)}
|
||||||
@ -151,7 +151,7 @@ export const ShortcutsModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
|
|||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col gap-y-3">
|
<div className="flex flex-col gap-y-3">
|
||||||
<p className="text-sm text-brand-secondary">
|
<p className="text-sm text-custom-text-200">
|
||||||
No shortcuts found for{" "}
|
No shortcuts found for{" "}
|
||||||
<span className="font-semibold italic">
|
<span className="font-semibold italic">
|
||||||
{`"`}
|
{`"`}
|
||||||
@ -168,20 +168,20 @@ export const ShortcutsModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
|
|||||||
<div className="flex flex-col gap-y-3">
|
<div className="flex flex-col gap-y-3">
|
||||||
{shortcuts.map(({ keys, description }, index) => (
|
{shortcuts.map(({ keys, description }, index) => (
|
||||||
<div key={index} className="flex items-center justify-between">
|
<div key={index} className="flex items-center justify-between">
|
||||||
<p className="text-sm text-brand-secondary">{description}</p>
|
<p className="text-sm text-custom-text-200">{description}</p>
|
||||||
<div className="flex items-center gap-x-2.5">
|
<div className="flex items-center gap-x-2.5">
|
||||||
{keys.split(",").map((key, index) => (
|
{keys.split(",").map((key, index) => (
|
||||||
<span key={index} className="flex items-center gap-1">
|
<span key={index} className="flex items-center gap-1">
|
||||||
{key === "Ctrl" ? (
|
{key === "Ctrl" ? (
|
||||||
<span className="flex h-full items-center rounded-sm border border-brand-base bg-brand-surface-1 p-1.5 text-brand-secondary">
|
<span className="flex h-full items-center rounded-sm border border-custom-border-100 bg-custom-background-90 p-1.5 text-custom-text-200">
|
||||||
<CommandIcon className="h-4 w-4 fill-current text-brand-secondary" />
|
<CommandIcon className="h-4 w-4 fill-current text-custom-text-200" />
|
||||||
</span>
|
</span>
|
||||||
) : key === "Ctrl" ? (
|
) : key === "Ctrl" ? (
|
||||||
<kbd className="rounded-sm border border-brand-base bg-brand-surface-1 p-1.5 text-sm font-medium text-brand-secondary">
|
<kbd className="rounded-sm border border-custom-border-100 bg-custom-background-90 p-1.5 text-sm font-medium text-custom-text-200">
|
||||||
<CommandIcon className="h-4 w-4 fill-current text-brand-secondary" />
|
<CommandIcon className="h-4 w-4 fill-current text-custom-text-200" />
|
||||||
</kbd>
|
</kbd>
|
||||||
) : (
|
) : (
|
||||||
<kbd className="rounded-sm border border-brand-base bg-brand-surface-1 px-2 py-1 text-sm font-medium text-brand-secondary">
|
<kbd className="rounded-sm border border-custom-border-100 bg-custom-background-90 px-2 py-1 text-sm font-medium text-custom-text-200">
|
||||||
{key}
|
{key}
|
||||||
</kbd>
|
</kbd>
|
||||||
)}
|
)}
|
||||||
|
@ -85,7 +85,7 @@ export const AllBoards: React.FC<Props> = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="flex items-center justify-between gap-2 rounded bg-brand-surface-1 p-2 shadow"
|
className="flex items-center justify-between gap-2 rounded bg-custom-background-90 p-2 shadow"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{currentState &&
|
{currentState &&
|
||||||
@ -96,7 +96,7 @@ export const AllBoards: React.FC<Props> = ({
|
|||||||
: addSpaceIfCamelCase(singleGroup)}
|
: addSpaceIfCamelCase(singleGroup)}
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-xs text-brand-secondary">0</span>
|
<span className="text-xs text-custom-text-200">0</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@ -113,7 +113,7 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`flex items-center justify-between px-1 ${
|
className={`flex items-center justify-between px-1 ${
|
||||||
!isCollapsed ? "flex-col rounded-md bg-brand-surface-1" : ""
|
!isCollapsed ? "flex-col rounded-md bg-custom-background-90" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className={`flex items-center ${!isCollapsed ? "flex-col gap-2" : "gap-1"}`}>
|
<div className={`flex items-center ${!isCollapsed ? "flex-col gap-2" : "gap-1"}`}>
|
||||||
@ -134,7 +134,7 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
<span
|
<span
|
||||||
className={`${
|
className={`${
|
||||||
isCollapsed ? "ml-0.5" : ""
|
isCollapsed ? "ml-0.5" : ""
|
||||||
} min-w-[2.5rem] rounded-full bg-brand-surface-2 py-1 text-center text-xs`}
|
} min-w-[2.5rem] rounded-full bg-custom-background-80 py-1 text-center text-xs`}
|
||||||
>
|
>
|
||||||
{groupedByIssues?.[groupTitle].length ?? 0}
|
{groupedByIssues?.[groupTitle].length ?? 0}
|
||||||
</span>
|
</span>
|
||||||
@ -144,7 +144,7 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
<div className={`flex items-center ${!isCollapsed ? "flex-col pb-2" : ""}`}>
|
<div className={`flex items-center ${!isCollapsed ? "flex-col pb-2" : ""}`}>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="grid h-7 w-7 place-items-center rounded p-1 text-brand-secondary outline-none duration-300 hover:bg-brand-surface-2"
|
className="grid h-7 w-7 place-items-center rounded p-1 text-custom-text-200 outline-none duration-300 hover:bg-custom-background-80"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsCollapsed((prevData) => !prevData);
|
setIsCollapsed((prevData) => !prevData);
|
||||||
}}
|
}}
|
||||||
@ -158,7 +158,7 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
{!isCompleted && selectedGroup !== "created_by" && (
|
{!isCompleted && selectedGroup !== "created_by" && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="grid h-7 w-7 place-items-center rounded p-1 text-brand-secondary outline-none duration-300 hover:bg-brand-surface-2"
|
className="grid h-7 w-7 place-items-center rounded p-1 text-custom-text-200 outline-none duration-300 hover:bg-custom-background-80"
|
||||||
onClick={addIssueToState}
|
onClick={addIssueToState}
|
||||||
>
|
>
|
||||||
<PlusIcon className="h-4 w-4" />
|
<PlusIcon className="h-4 w-4" />
|
||||||
|
@ -77,7 +77,9 @@ export const SingleBoard: React.FC<Props> = ({
|
|||||||
{(provided, snapshot) => (
|
{(provided, snapshot) => (
|
||||||
<div
|
<div
|
||||||
className={`relative h-full ${
|
className={`relative h-full ${
|
||||||
orderBy !== "sort_order" && snapshot.isDraggingOver ? "bg-brand-base/20" : ""
|
orderBy !== "sort_order" && snapshot.isDraggingOver
|
||||||
|
? "bg-custom-background-100/20"
|
||||||
|
: ""
|
||||||
} ${!isCollapsed ? "hidden" : "flex flex-col"}`}
|
} ${!isCollapsed ? "hidden" : "flex flex-col"}`}
|
||||||
ref={provided.innerRef}
|
ref={provided.innerRef}
|
||||||
{...provided.droppableProps}
|
{...provided.droppableProps}
|
||||||
@ -87,12 +89,12 @@ export const SingleBoard: React.FC<Props> = ({
|
|||||||
<div
|
<div
|
||||||
className={`absolute ${
|
className={`absolute ${
|
||||||
snapshot.isDraggingOver ? "block" : "hidden"
|
snapshot.isDraggingOver ? "block" : "hidden"
|
||||||
} pointer-events-none top-0 left-0 z-[99] h-full w-full bg-brand-surface-1 opacity-50`}
|
} pointer-events-none top-0 left-0 z-[99] h-full w-full bg-custom-background-90 opacity-50`}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className={`absolute ${
|
className={`absolute ${
|
||||||
snapshot.isDraggingOver ? "block" : "hidden"
|
snapshot.isDraggingOver ? "block" : "hidden"
|
||||||
} pointer-events-none top-1/2 left-1/2 z-[99] -translate-y-1/2 -translate-x-1/2 whitespace-nowrap rounded bg-brand-base p-2 text-xs`}
|
} pointer-events-none top-1/2 left-1/2 z-[99] -translate-y-1/2 -translate-x-1/2 whitespace-nowrap rounded bg-custom-background-100 p-2 text-xs`}
|
||||||
>
|
>
|
||||||
This board is ordered by{" "}
|
This board is ordered by{" "}
|
||||||
{replaceUnderscoreIfSnakeCase(
|
{replaceUnderscoreIfSnakeCase(
|
||||||
@ -150,7 +152,7 @@ export const SingleBoard: React.FC<Props> = ({
|
|||||||
{type === "issue" ? (
|
{type === "issue" ? (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="flex items-center gap-2 font-medium text-brand-accent outline-none p-1"
|
className="flex items-center gap-2 font-medium text-custom-primary outline-none p-1"
|
||||||
onClick={addIssueToState}
|
onClick={addIssueToState}
|
||||||
>
|
>
|
||||||
<PlusIcon className="h-4 w-4" />
|
<PlusIcon className="h-4 w-4" />
|
||||||
@ -162,7 +164,7 @@ export const SingleBoard: React.FC<Props> = ({
|
|||||||
customButton={
|
customButton={
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="flex items-center gap-2 font-medium text-brand-accent outline-none"
|
className="flex items-center gap-2 font-medium text-custom-primary outline-none"
|
||||||
>
|
>
|
||||||
<PlusIcon className="h-4 w-4" />
|
<PlusIcon className="h-4 w-4" />
|
||||||
Add Issue
|
Add Issue
|
||||||
|
@ -43,7 +43,7 @@ import {
|
|||||||
import { LayerDiagonalIcon } from "components/icons";
|
import { LayerDiagonalIcon } from "components/icons";
|
||||||
// helpers
|
// helpers
|
||||||
import { handleIssuesMutation } from "constants/issue";
|
import { handleIssuesMutation } from "constants/issue";
|
||||||
import { copyTextToClipboard, truncateText } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
import {
|
import {
|
||||||
ICurrentUserResponse,
|
ICurrentUserResponse,
|
||||||
@ -265,8 +265,8 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
</a>
|
</a>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
<div
|
<div
|
||||||
className={`mb-3 rounded bg-brand-base shadow ${
|
className={`mb-3 rounded bg-custom-background-90 shadow ${
|
||||||
snapshot.isDragging ? "border-2 border-brand-accent shadow-lg" : ""
|
snapshot.isDragging ? "border-2 border-custom-primary shadow-lg" : ""
|
||||||
}`}
|
}`}
|
||||||
ref={provided.innerRef}
|
ref={provided.innerRef}
|
||||||
{...provided.draggableProps}
|
{...provided.draggableProps}
|
||||||
@ -290,7 +290,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
<CustomMenu
|
<CustomMenu
|
||||||
customButton={
|
customButton={
|
||||||
<button
|
<button
|
||||||
className="flex w-full cursor-pointer items-center justify-between gap-1 rounded p-1 text-left text-xs duration-300 hover:bg-brand-surface-2"
|
className="flex w-full cursor-pointer items-center justify-between gap-1 rounded p-1 text-left text-xs duration-300 hover:bg-custom-background-80"
|
||||||
onClick={() => setIsMenuActive(!isMenuActive)}
|
onClick={() => setIsMenuActive(!isMenuActive)}
|
||||||
>
|
>
|
||||||
<EllipsisHorizontalIcon className="h-4 w-4" />
|
<EllipsisHorizontalIcon className="h-4 w-4" />
|
||||||
@ -330,13 +330,11 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
<Link href={`/${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`}>
|
<Link href={`/${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`}>
|
||||||
<a>
|
<a>
|
||||||
{properties.key && (
|
{properties.key && (
|
||||||
<div className="mb-2.5 text-xs font-medium text-brand-secondary">
|
<div className="mb-2.5 text-xs font-medium text-custom-text-200">
|
||||||
{issue.project_detail.identifier}-{issue.sequence_id}
|
{issue.project_detail.identifier}-{issue.sequence_id}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<h5 className="text-sm group-hover:text-brand-accent break-words line-clamp-3">
|
<h5 className="text-sm break-words line-clamp-3">{issue.name}</h5>
|
||||||
{issue.name}
|
|
||||||
</h5>
|
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<div className="relative mt-2.5 flex flex-wrap items-center gap-2 text-xs">
|
<div className="relative mt-2.5 flex flex-wrap items-center gap-2 text-xs">
|
||||||
@ -394,9 +392,9 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{properties.sub_issue_count && (
|
{properties.sub_issue_count && (
|
||||||
<div className="flex cursor-default items-center rounded-md border border-brand-base px-2.5 py-1 text-xs shadow-sm">
|
<div className="flex cursor-default items-center rounded-md border border-custom-border-100 px-2.5 py-1 text-xs shadow-sm">
|
||||||
<Tooltip tooltipHeading="Sub-issue" tooltipContent={`${issue.sub_issues_count}`}>
|
<Tooltip tooltipHeading="Sub-issue" tooltipContent={`${issue.sub_issues_count}`}>
|
||||||
<div className="flex items-center gap-1 text-brand-secondary">
|
<div className="flex items-center gap-1 text-custom-text-200">
|
||||||
<LayerDiagonalIcon className="h-3.5 w-3.5" />
|
<LayerDiagonalIcon className="h-3.5 w-3.5" />
|
||||||
{issue.sub_issues_count}
|
{issue.sub_issues_count}
|
||||||
</div>
|
</div>
|
||||||
@ -404,9 +402,9 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{properties.link && (
|
{properties.link && (
|
||||||
<div className="flex cursor-default items-center rounded-md border border-brand-base px-2.5 py-1 text-xs shadow-sm">
|
<div className="flex cursor-default items-center rounded-md border border-custom-border-100 px-2.5 py-1 text-xs shadow-sm">
|
||||||
<Tooltip tooltipHeading="Link" tooltipContent={`${issue.link_count}`}>
|
<Tooltip tooltipHeading="Link" tooltipContent={`${issue.link_count}`}>
|
||||||
<div className="flex items-center gap-1 text-brand-secondary">
|
<div className="flex items-center gap-1 text-custom-text-200">
|
||||||
<LinkIcon className="h-3.5 w-3.5" />
|
<LinkIcon className="h-3.5 w-3.5" />
|
||||||
{issue.link_count}
|
{issue.link_count}
|
||||||
</div>
|
</div>
|
||||||
@ -414,9 +412,9 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{properties.attachment_count && (
|
{properties.attachment_count && (
|
||||||
<div className="flex cursor-default items-center rounded-md border border-brand-base px-2.5 py-1 text-xs shadow-sm">
|
<div className="flex cursor-default items-center rounded-md border border-custom-border-100 px-2.5 py-1 text-xs shadow-sm">
|
||||||
<Tooltip tooltipHeading="Attachment" tooltipContent={`${issue.attachment_count}`}>
|
<Tooltip tooltipHeading="Attachment" tooltipContent={`${issue.attachment_count}`}>
|
||||||
<div className="flex items-center gap-1 text-brand-secondary">
|
<div className="flex items-center gap-1 text-custom-text-200">
|
||||||
<PaperClipIcon className="h-3.5 w-3.5 -rotate-45" />
|
<PaperClipIcon className="h-3.5 w-3.5 -rotate-45" />
|
||||||
{issue.attachment_count}
|
{issue.attachment_count}
|
||||||
</div>
|
</div>
|
||||||
|
@ -62,7 +62,7 @@ export const CalendarHeader: React.FC<Props> = ({
|
|||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<>
|
<>
|
||||||
<Popover.Button>
|
<Popover.Button>
|
||||||
<div className="flex items-center justify-center gap-2 text-2xl font-semibold text-brand-base">
|
<div className="flex items-center justify-center gap-2 text-2xl font-semibold text-custom-text-100">
|
||||||
<span>{formatDate(currentDate, "Month")}</span>{" "}
|
<span>{formatDate(currentDate, "Month")}</span>{" "}
|
||||||
<span>{formatDate(currentDate, "yyyy")}</span>
|
<span>{formatDate(currentDate, "yyyy")}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -77,30 +77,30 @@ export const CalendarHeader: React.FC<Props> = ({
|
|||||||
leaveFrom="opacity-100 translate-y-0"
|
leaveFrom="opacity-100 translate-y-0"
|
||||||
leaveTo="opacity-0 translate-y-1"
|
leaveTo="opacity-0 translate-y-1"
|
||||||
>
|
>
|
||||||
<Popover.Panel className="absolute top-10 left-0 z-20 flex w-full max-w-xs transform flex-col overflow-hidden rounded-[10px] bg-brand-surface-2 shadow-lg">
|
<Popover.Panel className="absolute top-10 left-0 z-20 flex w-full max-w-xs transform flex-col overflow-hidden rounded-[10px] bg-custom-background-80 shadow-lg">
|
||||||
<div className="flex items-center justify-center gap-5 px-2 py-2 text-sm">
|
<div className="flex items-center justify-center gap-5 px-2 py-2 text-sm">
|
||||||
{YEARS_LIST.map((year) => (
|
{YEARS_LIST.map((year) => (
|
||||||
<button
|
<button
|
||||||
onClick={() => updateDate(updateDateWithYear(year.label, currentDate))}
|
onClick={() => updateDate(updateDateWithYear(year.label, currentDate))}
|
||||||
className={` ${
|
className={` ${
|
||||||
isSameYear(year.value, currentDate)
|
isSameYear(year.value, currentDate)
|
||||||
? "text-sm font-medium text-brand-base"
|
? "text-sm font-medium text-custom-text-100"
|
||||||
: "text-xs text-brand-secondary "
|
: "text-xs text-custom-text-200 "
|
||||||
} hover:text-sm hover:font-medium hover:text-brand-base`}
|
} hover:text-sm hover:font-medium hover:text-custom-text-100`}
|
||||||
>
|
>
|
||||||
{year.label}
|
{year.label}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-4 border-t border-brand-base px-2">
|
<div className="grid grid-cols-4 border-t border-custom-border-100 px-2">
|
||||||
{MONTHS_LIST.map((month) => (
|
{MONTHS_LIST.map((month) => (
|
||||||
<button
|
<button
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
updateDate(updateDateWithMonth(`${month.value}`, currentDate))
|
updateDate(updateDateWithMonth(`${month.value}`, currentDate))
|
||||||
}
|
}
|
||||||
className={`px-2 py-2 text-xs text-brand-secondary hover:font-medium hover:text-brand-base ${
|
className={`px-2 py-2 text-xs text-custom-text-200 hover:font-medium hover:text-custom-text-100 ${
|
||||||
isSameMonth(`${month.value}`, currentDate)
|
isSameMonth(`${month.value}`, currentDate)
|
||||||
? "font-medium text-brand-base"
|
? "font-medium text-custom-text-100"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@ -152,7 +152,7 @@ export const CalendarHeader: React.FC<Props> = ({
|
|||||||
|
|
||||||
<div className="flex w-full items-center justify-end gap-2">
|
<div className="flex w-full items-center justify-end gap-2">
|
||||||
<button
|
<button
|
||||||
className="group flex cursor-pointer items-center gap-2 rounded-md border border-brand-base px-3 py-1 text-sm hover:bg-brand-surface-2 hover:text-brand-base focus:outline-none"
|
className="group flex cursor-pointer items-center gap-2 rounded-md border border-custom-border-100 px-3 py-1 text-sm hover:bg-custom-background-80 hover:text-custom-text-100 focus:outline-none"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isMonthlyView) {
|
if (isMonthlyView) {
|
||||||
updateDate(new Date());
|
updateDate(new Date());
|
||||||
@ -170,7 +170,7 @@ export const CalendarHeader: React.FC<Props> = ({
|
|||||||
|
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
customButton={
|
customButton={
|
||||||
<div className="group flex cursor-pointer items-center gap-2 rounded-md border border-brand-base px-3 py-1 text-sm hover:bg-brand-surface-2 hover:text-brand-base focus:outline-none ">
|
<div className="group flex cursor-pointer items-center gap-2 rounded-md border border-custom-border-100 px-3 py-1 text-sm hover:bg-custom-background-80 hover:text-custom-text-100 focus:outline-none ">
|
||||||
{isMonthlyView ? "Monthly" : "Weekly"}
|
{isMonthlyView ? "Monthly" : "Weekly"}
|
||||||
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
||||||
</div>
|
</div>
|
||||||
@ -181,7 +181,7 @@ export const CalendarHeader: React.FC<Props> = ({
|
|||||||
setIsMonthlyView(true);
|
setIsMonthlyView(true);
|
||||||
changeDateRange(startOfWeek(currentDate), lastDayOfWeek(currentDate));
|
changeDateRange(startOfWeek(currentDate), lastDayOfWeek(currentDate));
|
||||||
}}
|
}}
|
||||||
className="w-52 text-sm text-brand-secondary"
|
className="w-52 text-sm text-custom-text-200"
|
||||||
>
|
>
|
||||||
<div className="flex w-full max-w-[260px] items-center justify-between gap-2">
|
<div className="flex w-full max-w-[260px] items-center justify-between gap-2">
|
||||||
<span className="flex items-center gap-2">Monthly View</span>
|
<span className="flex items-center gap-2">Monthly View</span>
|
||||||
@ -198,7 +198,7 @@ export const CalendarHeader: React.FC<Props> = ({
|
|||||||
getCurrentWeekEndDate(currentDate)
|
getCurrentWeekEndDate(currentDate)
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
className="w-52 text-sm text-brand-secondary"
|
className="w-52 text-sm text-custom-text-200"
|
||||||
>
|
>
|
||||||
<div className="flex w-full items-center justify-between gap-2">
|
<div className="flex w-full items-center justify-between gap-2">
|
||||||
<span className="flex items-center gap-2">Weekly View</span>
|
<span className="flex items-center gap-2">Weekly View</span>
|
||||||
@ -207,7 +207,7 @@ export const CalendarHeader: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
<div className="mt-1 flex w-52 items-center justify-between border-t border-brand-base py-2 px-1 text-sm text-brand-secondary">
|
<div className="mt-1 flex w-52 items-center justify-between border-t border-custom-border-100 py-2 px-1 text-sm text-custom-text-200">
|
||||||
<h4>Show weekends</h4>
|
<h4>Show weekends</h4>
|
||||||
<ToggleSwitch value={showWeekEnds} onChange={() => setShowWeekEnds(!showWeekEnds)} />
|
<ToggleSwitch value={showWeekEnds} onChange={() => setShowWeekEnds(!showWeekEnds)} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -172,7 +172,7 @@ export const CalendarView: React.FC<Props> = ({
|
|||||||
return calendarIssues ? (
|
return calendarIssues ? (
|
||||||
<div className="h-full overflow-y-auto">
|
<div className="h-full overflow-y-auto">
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
<div className="h-full rounded-lg p-8 text-brand-secondary">
|
<div className="h-full rounded-lg p-8 text-custom-text-200">
|
||||||
<CalendarHeader
|
<CalendarHeader
|
||||||
isMonthlyView={isMonthlyView}
|
isMonthlyView={isMonthlyView}
|
||||||
setIsMonthlyView={setIsMonthlyView}
|
setIsMonthlyView={setIsMonthlyView}
|
||||||
@ -191,7 +191,7 @@ export const CalendarView: React.FC<Props> = ({
|
|||||||
{weeks.map((date, index) => (
|
{weeks.map((date, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className={`flex items-center justify-start gap-2 border-brand-base bg-brand-surface-1 p-1.5 text-base font-medium text-brand-secondary ${
|
className={`flex items-center justify-start gap-2 border-custom-border-100 bg-custom-background-90 p-1.5 text-base font-medium text-custom-text-200 ${
|
||||||
!isMonthlyView
|
!isMonthlyView
|
||||||
? showWeekEnds
|
? showWeekEnds
|
||||||
? (index + 1) % 7 === 0
|
? (index + 1) % 7 === 0
|
||||||
|
@ -49,7 +49,7 @@ export const SingleCalendarDate: React.FC<Props> = ({
|
|||||||
key={index}
|
key={index}
|
||||||
ref={provided.innerRef}
|
ref={provided.innerRef}
|
||||||
{...provided.droppableProps}
|
{...provided.droppableProps}
|
||||||
className={`group relative flex min-h-[150px] flex-col gap-1.5 border-t border-brand-base p-2.5 text-left text-sm font-medium hover:bg-brand-surface-1 ${
|
className={`group relative flex min-h-[150px] flex-col gap-1.5 border-t border-custom-border-100 p-2.5 text-left text-sm font-medium hover:bg-custom-background-90 ${
|
||||||
isMonthlyView ? "" : "pt-9"
|
isMonthlyView ? "" : "pt-9"
|
||||||
} ${
|
} ${
|
||||||
showWeekEnds
|
showWeekEnds
|
||||||
@ -83,7 +83,7 @@ export const SingleCalendarDate: React.FC<Props> = ({
|
|||||||
{totalIssues > 4 && (
|
{totalIssues > 4 && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="w-min whitespace-nowrap rounded-md border border-brand-base bg-brand-surface-2 px-1.5 py-1 text-xs"
|
className="w-min whitespace-nowrap rounded-md border border-custom-border-100 bg-custom-background-80 px-1.5 py-1 text-xs"
|
||||||
onClick={() => setShowAllIssues((prevData) => !prevData)}
|
onClick={() => setShowAllIssues((prevData) => !prevData)}
|
||||||
>
|
>
|
||||||
{showAllIssues ? "Hide" : totalIssues - 4 + " more"}
|
{showAllIssues ? "Hide" : totalIssues - 4 + " more"}
|
||||||
@ -91,13 +91,13 @@ export const SingleCalendarDate: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`absolute top-2 right-2 flex items-center justify-center rounded-md bg-brand-surface-2 p-1 text-xs text-brand-secondary opacity-0 group-hover:opacity-100`}
|
className={`absolute top-2 right-2 flex items-center justify-center rounded-md bg-custom-background-80 p-1 text-xs text-custom-text-200 opacity-0 group-hover:opacity-100`}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
className="flex items-center justify-center gap-1 text-center"
|
className="flex items-center justify-center gap-1 text-center"
|
||||||
onClick={() => addIssueToDate(date.date)}
|
onClick={() => addIssueToDate(date.date)}
|
||||||
>
|
>
|
||||||
<PlusSmallIcon className="h-4 w-4 text-brand-secondary" />
|
<PlusSmallIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
Add issue
|
Add issue
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -163,8 +163,8 @@ export const SingleCalendarIssue: React.FC<Props> = ({
|
|||||||
ref={provided.innerRef}
|
ref={provided.innerRef}
|
||||||
{...provided.draggableProps}
|
{...provided.draggableProps}
|
||||||
{...provided.dragHandleProps}
|
{...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 ${
|
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-brand-surface-2 shadow-lg" : ""
|
snapshot.isDragging ? "bg-custom-background-80 shadow-lg" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="group/card flex w-full flex-col items-start justify-center gap-1.5 text-xs sm:w-auto ">
|
<div className="group/card flex w-full flex-col items-start justify-center gap-1.5 text-xs sm:w-auto ">
|
||||||
@ -199,13 +199,13 @@ export const SingleCalendarIssue: React.FC<Props> = ({
|
|||||||
tooltipHeading="Issue ID"
|
tooltipHeading="Issue ID"
|
||||||
tooltipContent={`${issue.project_detail?.identifier}-${issue.sequence_id}`}
|
tooltipContent={`${issue.project_detail?.identifier}-${issue.sequence_id}`}
|
||||||
>
|
>
|
||||||
<span className="flex-shrink-0 text-xs text-brand-secondary">
|
<span className="flex-shrink-0 text-xs text-custom-text-200">
|
||||||
{issue.project_detail?.identifier}-{issue.sequence_id}
|
{issue.project_detail?.identifier}-{issue.sequence_id}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
<Tooltip position="top-left" tooltipHeading="Title" tooltipContent={issue.name}>
|
<Tooltip position="top-left" tooltipHeading="Title" tooltipContent={issue.name}>
|
||||||
<span className="text-xs text-brand-base">{truncateText(issue.name, 25)}</span>
|
<span className="text-xs text-custom-text-100">{truncateText(issue.name, 25)}</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
@ -267,9 +267,9 @@ export const SingleCalendarIssue: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{properties.sub_issue_count && (
|
{properties.sub_issue_count && (
|
||||||
<div className="flex cursor-default items-center rounded-md border border-brand-base px-2.5 py-1 text-xs shadow-sm">
|
<div className="flex cursor-default items-center rounded-md border border-custom-border-100 px-2.5 py-1 text-xs shadow-sm">
|
||||||
<Tooltip tooltipHeading="Sub-issue" tooltipContent={`${issue.sub_issues_count}`}>
|
<Tooltip tooltipHeading="Sub-issue" tooltipContent={`${issue.sub_issues_count}`}>
|
||||||
<div className="flex items-center gap-1 text-brand-secondary">
|
<div className="flex items-center gap-1 text-custom-text-200">
|
||||||
<LayerDiagonalIcon className="h-3.5 w-3.5" />
|
<LayerDiagonalIcon className="h-3.5 w-3.5" />
|
||||||
{issue.sub_issues_count}
|
{issue.sub_issues_count}
|
||||||
</div>
|
</div>
|
||||||
@ -277,9 +277,9 @@ export const SingleCalendarIssue: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{properties.link && (
|
{properties.link && (
|
||||||
<div className="flex cursor-default items-center rounded-md border border-brand-base px-2.5 py-1 text-xs shadow-sm">
|
<div className="flex cursor-default items-center rounded-md border border-custom-border-100 px-2.5 py-1 text-xs shadow-sm">
|
||||||
<Tooltip tooltipHeading="Links" tooltipContent={`${issue.link_count}`}>
|
<Tooltip tooltipHeading="Links" tooltipContent={`${issue.link_count}`}>
|
||||||
<div className="flex items-center gap-1 text-brand-secondary">
|
<div className="flex items-center gap-1 text-custom-text-200">
|
||||||
<LinkIcon className="h-3.5 w-3.5" />
|
<LinkIcon className="h-3.5 w-3.5" />
|
||||||
{issue.link_count}
|
{issue.link_count}
|
||||||
</div>
|
</div>
|
||||||
@ -287,9 +287,9 @@ export const SingleCalendarIssue: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{properties.attachment_count && (
|
{properties.attachment_count && (
|
||||||
<div className="flex cursor-default items-center rounded-md border border-brand-base px-2.5 py-1 text-xs shadow-sm">
|
<div className="flex cursor-default items-center rounded-md border border-custom-border-100 px-2.5 py-1 text-xs shadow-sm">
|
||||||
<Tooltip tooltipHeading="Attachments" tooltipContent={`${issue.attachment_count}`}>
|
<Tooltip tooltipHeading="Attachments" tooltipContent={`${issue.attachment_count}`}>
|
||||||
<div className="flex items-center gap-1 text-brand-secondary">
|
<div className="flex items-center gap-1 text-custom-text-200">
|
||||||
<PaperClipIcon className="h-3.5 w-3.5 -rotate-45" />
|
<PaperClipIcon className="h-3.5 w-3.5 -rotate-45" />
|
||||||
{issue.attachment_count}
|
{issue.attachment_count}
|
||||||
</div>
|
</div>
|
||||||
|
@ -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<ICustomTheme> | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const CustomThemeSelector: React.FC<Props> = ({ 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<any>({
|
|
||||||
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 (
|
|
||||||
<form onSubmit={handleSubmit(handleUpdateTheme)}>
|
|
||||||
<div className="space-y-5">
|
|
||||||
<h3 className="text-lg font-semibold text-brand-base">Customize your theme</h3>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-3">
|
|
||||||
<div className="flex flex-col items-start gap-2">
|
|
||||||
<h3 className="text-left text-base text-brand-secondary">Background</h3>
|
|
||||||
<ColorPickerInput
|
|
||||||
name="bgBase"
|
|
||||||
error={errors.bgBase}
|
|
||||||
watch={watch}
|
|
||||||
setValue={setValue}
|
|
||||||
register={register}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col items-start gap-2">
|
|
||||||
<h3 className="text-left text-base text-brand-secondary">Background surface 1</h3>
|
|
||||||
<ColorPickerInput
|
|
||||||
name="bgSurface1"
|
|
||||||
error={errors.bgSurface1}
|
|
||||||
watch={watch}
|
|
||||||
setValue={setValue}
|
|
||||||
register={register}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col items-start gap-2">
|
|
||||||
<h3 className="text-left text-base text-brand-secondary">Background surface 2</h3>
|
|
||||||
<ColorPickerInput
|
|
||||||
name="bgSurface2"
|
|
||||||
error={errors.bgSurface2}
|
|
||||||
watch={watch}
|
|
||||||
setValue={setValue}
|
|
||||||
register={register}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col items-start gap-2">
|
|
||||||
<h3 className="text-left text-base text-brand-secondary">Border</h3>
|
|
||||||
<ColorPickerInput
|
|
||||||
name="border"
|
|
||||||
error={errors.border}
|
|
||||||
watch={watch}
|
|
||||||
setValue={setValue}
|
|
||||||
register={register}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col items-start gap-2">
|
|
||||||
<h3 className="text-left text-base text-brand-secondary">Sidebar</h3>
|
|
||||||
<ColorPickerInput
|
|
||||||
name="sidebar"
|
|
||||||
error={errors.sidebar}
|
|
||||||
watch={watch}
|
|
||||||
setValue={setValue}
|
|
||||||
register={register}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col items-start gap-2">
|
|
||||||
<h3 className="text-left text-base text-brand-secondary">Accent</h3>
|
|
||||||
<ColorPickerInput
|
|
||||||
name="accent"
|
|
||||||
error={errors.accent}
|
|
||||||
watch={watch}
|
|
||||||
setValue={setValue}
|
|
||||||
register={register}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col items-start gap-2">
|
|
||||||
<h3 className="text-left text-base text-brand-secondary">Text primary</h3>
|
|
||||||
<ColorPickerInput
|
|
||||||
name="textBase"
|
|
||||||
error={errors.textBase}
|
|
||||||
watch={watch}
|
|
||||||
setValue={setValue}
|
|
||||||
register={register}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col items-start gap-2">
|
|
||||||
<h3 className="text-left text-base text-brand-secondary">Text secondary</h3>
|
|
||||||
<ColorPickerInput
|
|
||||||
name="textSecondary"
|
|
||||||
error={errors.textSecondary}
|
|
||||||
watch={watch}
|
|
||||||
setValue={setValue}
|
|
||||||
register={register}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mt-5 flex justify-end gap-2">
|
|
||||||
<PrimaryButton type="submit" loading={isSubmitting}>
|
|
||||||
{isSubmitting ? "Creating Theme..." : "Set Theme"}
|
|
||||||
</PrimaryButton>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
};
|
|
@ -55,55 +55,55 @@ const activityDetails: {
|
|||||||
},
|
},
|
||||||
modules: {
|
modules: {
|
||||||
message: "set the module to",
|
message: "set the module to",
|
||||||
icon: <RectangleGroupIcon className="h-3 w-3 text-brand-secondary" aria-hidden="true" />,
|
icon: <RectangleGroupIcon className="h-3 w-3 text-custom-text-200" aria-hidden="true" />,
|
||||||
},
|
},
|
||||||
state: {
|
state: {
|
||||||
message: "set the state to",
|
message: "set the state to",
|
||||||
icon: <Squares2X2Icon className="h-3 w-3 text-brand-secondary" aria-hidden="true" />,
|
icon: <Squares2X2Icon className="h-3 w-3 text-custom-text-200" aria-hidden="true" />,
|
||||||
},
|
},
|
||||||
priority: {
|
priority: {
|
||||||
message: "set the priority to",
|
message: "set the priority to",
|
||||||
icon: <ChartBarIcon className="h-3 w-3 text-brand-secondary" aria-hidden="true" />,
|
icon: <ChartBarIcon className="h-3 w-3 text-custom-text-200" aria-hidden="true" />,
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
message: "set the name to",
|
message: "set the name to",
|
||||||
icon: (
|
icon: (
|
||||||
<ChatBubbleBottomCenterTextIcon className="h-3 w-3 text-brand-secondary" aria-hidden="true" />
|
<ChatBubbleBottomCenterTextIcon className="h-3 w-3 text-custom-text-200" aria-hidden="true" />
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
message: "updated the description.",
|
message: "updated the description.",
|
||||||
icon: (
|
icon: (
|
||||||
<ChatBubbleBottomCenterTextIcon className="h-3 w-3 text-brand-secondary" aria-hidden="true" />
|
<ChatBubbleBottomCenterTextIcon className="h-3 w-3 text-custom-text-200" aria-hidden="true" />
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
estimate_point: {
|
estimate_point: {
|
||||||
message: "set the estimate point to",
|
message: "set the estimate point to",
|
||||||
icon: <PlayIcon className="h-3 w-3 -rotate-90 text-brand-secondary" aria-hidden="true" />,
|
icon: <PlayIcon className="h-3 w-3 -rotate-90 text-custom-text-200" aria-hidden="true" />,
|
||||||
},
|
},
|
||||||
target_date: {
|
target_date: {
|
||||||
message: "set the due date to",
|
message: "set the due date to",
|
||||||
icon: <CalendarDaysIcon className="h-3 w-3 text-brand-secondary" aria-hidden="true" />,
|
icon: <CalendarDaysIcon className="h-3 w-3 text-custom-text-200" aria-hidden="true" />,
|
||||||
},
|
},
|
||||||
parent: {
|
parent: {
|
||||||
message: "set the parent to",
|
message: "set the parent to",
|
||||||
icon: <UserIcon className="h-3 w-3 text-brand-secondary" aria-hidden="true" />,
|
icon: <UserIcon className="h-3 w-3 text-custom-text-200" aria-hidden="true" />,
|
||||||
},
|
},
|
||||||
issue: {
|
issue: {
|
||||||
message: "deleted the issue.",
|
message: "deleted the issue.",
|
||||||
icon: <TrashIcon className="h-3 w-3 text-brand-secondary" aria-hidden="true" />,
|
icon: <TrashIcon className="h-3 w-3 text-custom-text-200" aria-hidden="true" />,
|
||||||
},
|
},
|
||||||
estimate: {
|
estimate: {
|
||||||
message: "updated the estimate",
|
message: "updated the estimate",
|
||||||
icon: <PlayIcon className="h-3 w-3 -rotate-90 text-gray-500" aria-hidden="true" />,
|
icon: <PlayIcon className="h-3 w-3 -rotate-90 text-custom-text-200" aria-hidden="true" />,
|
||||||
},
|
},
|
||||||
link: {
|
link: {
|
||||||
message: "updated the link",
|
message: "updated the link",
|
||||||
icon: <LinkIcon className="h-3 w-3 text-gray-500" aria-hidden="true" />,
|
icon: <LinkIcon className="h-3 w-3 text-custom-text-200" aria-hidden="true" />,
|
||||||
},
|
},
|
||||||
attachment: {
|
attachment: {
|
||||||
message: "updated the attachment",
|
message: "updated the attachment",
|
||||||
icon: <PaperClipIcon className="h-3 w-3 text-gray-500 " aria-hidden="true" />,
|
icon: <PaperClipIcon className="h-3 w-3 text-custom-text-200 " aria-hidden="true" />,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
|||||||
) {
|
) {
|
||||||
const { workspace_detail, project, issue } = activity;
|
const { workspace_detail, project, issue } = activity;
|
||||||
value = (
|
value = (
|
||||||
<span className="text-brand-secondary">
|
<span className="text-custom-text-200">
|
||||||
created{" "}
|
created{" "}
|
||||||
<Link href={`/${workspace_detail.slug}/projects/${project}/issues/${issue}`}>
|
<Link href={`/${workspace_detail.slug}/projects/${project}/issues/${issue}`}>
|
||||||
<a className="inline-flex items-center hover:underline">
|
<a className="inline-flex items-center hover:underline">
|
||||||
@ -221,9 +221,9 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<span className="absolute -bottom-0.5 -right-1 rounded-tl bg-brand-surface-2 px-0.5 py-px">
|
<span className="absolute -bottom-0.5 -right-1 rounded-tl bg-custom-background-80 px-0.5 py-px">
|
||||||
<ChatBubbleLeftEllipsisIcon
|
<ChatBubbleLeftEllipsisIcon
|
||||||
className="h-3.5 w-3.5 text-brand-secondary"
|
className="h-3.5 w-3.5 text-custom-text-200"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
@ -234,7 +234,7 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
|||||||
{activity.actor_detail.first_name}
|
{activity.actor_detail.first_name}
|
||||||
{activity.actor_detail.is_bot ? "Bot" : " " + activity.actor_detail.last_name}
|
{activity.actor_detail.is_bot ? "Bot" : " " + activity.actor_detail.last_name}
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-0.5 text-xs text-brand-secondary">
|
<p className="mt-0.5 text-xs text-custom-text-200">
|
||||||
Commented {timeAgo(activity.created_at)}
|
Commented {timeAgo(activity.created_at)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -247,7 +247,7 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
|||||||
}
|
}
|
||||||
editable={false}
|
editable={false}
|
||||||
noBorder
|
noBorder
|
||||||
customClassName="text-xs border border-brand-base bg-brand-base"
|
customClassName="text-xs border border-custom-border-100 bg-custom-background-100"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -262,7 +262,7 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
|||||||
<div className="relative pb-1">
|
<div className="relative pb-1">
|
||||||
{activities.length > 1 && activityIdx !== activities.length - 1 ? (
|
{activities.length > 1 && activityIdx !== activities.length - 1 ? (
|
||||||
<span
|
<span
|
||||||
className="absolute top-5 left-5 -ml-px h-full w-0.5 bg-brand-surface-2"
|
className="absolute top-5 left-5 -ml-px h-full w-0.5 bg-custom-background-80"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
@ -271,7 +271,7 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
|||||||
<div>
|
<div>
|
||||||
<div className="relative px-1.5">
|
<div className="relative px-1.5">
|
||||||
<div className="mt-1.5">
|
<div className="mt-1.5">
|
||||||
<div className="ring-6 flex h-7 w-7 items-center justify-center rounded-full bg-brand-surface-2 ring-white">
|
<div className="ring-6 flex h-7 w-7 items-center justify-center rounded-full bg-custom-background-80 ring-white">
|
||||||
{activity.field ? (
|
{activity.field ? (
|
||||||
activityDetails[activity.field as keyof typeof activityDetails]?.icon
|
activityDetails[activity.field as keyof typeof activityDetails]?.icon
|
||||||
) : activity.actor_detail.avatar &&
|
) : activity.actor_detail.avatar &&
|
||||||
@ -295,7 +295,7 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1 py-3">
|
<div className="min-w-0 flex-1 py-3">
|
||||||
<div className="text-xs text-brand-secondary">
|
<div className="text-xs text-custom-text-200">
|
||||||
<span className="text-gray font-medium">
|
<span className="text-gray font-medium">
|
||||||
{activity.actor_detail.first_name}
|
{activity.actor_detail.first_name}
|
||||||
{activity.actor_detail.is_bot
|
{activity.actor_detail.is_bot
|
||||||
@ -303,7 +303,7 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
|||||||
: " " + activity.actor_detail.last_name}
|
: " " + activity.actor_detail.last_name}
|
||||||
</span>
|
</span>
|
||||||
<span> {action} </span>
|
<span> {action} </span>
|
||||||
<span className="text-xs font-medium text-brand-base"> {value} </span>
|
<span className="text-xs font-medium text-custom-text-100"> {value} </span>
|
||||||
<span className="whitespace-nowrap">{timeAgo(activity.created_at)}</span>
|
<span className="whitespace-nowrap">{timeAgo(activity.created_at)}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -96,7 +96,7 @@ export const DueDateFilterModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
|||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<div className="fixed inset-0 bg-brand-backdrop bg-opacity-50 transition-opacity" />
|
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
<div className="fixed inset-0 z-20 flex w-full justify-center overflow-y-auto">
|
<div className="fixed inset-0 z-20 flex w-full justify-center overflow-y-auto">
|
||||||
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
|
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
|
||||||
@ -109,7 +109,7 @@ export const DueDateFilterModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
|||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative flex transform rounded-lg border border-brand-base bg-brand-base px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
<Dialog.Panel className="relative flex transform rounded-lg border border-custom-border-100 bg-custom-background-100 px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
||||||
<form className="space-y-4" onSubmit={handleSubmit(handleFormSubmit)}>
|
<form className="space-y-4" onSubmit={handleSubmit(handleFormSubmit)}>
|
||||||
<div className="flex w-full justify-between">
|
<div className="flex w-full justify-between">
|
||||||
<Controller
|
<Controller
|
||||||
@ -157,9 +157,9 @@ export const DueDateFilterModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
|||||||
</div>
|
</div>
|
||||||
{watch("filterType") === "range" && (
|
{watch("filterType") === "range" && (
|
||||||
<h6 className="text-xs flex items-center gap-1">
|
<h6 className="text-xs flex items-center gap-1">
|
||||||
<span className="text-brand-secondary">After:</span>
|
<span className="text-custom-text-200">After:</span>
|
||||||
<span>{renderShortDateWithYearFormat(watch("date1"))}</span>
|
<span>{renderShortDateWithYearFormat(watch("date1"))}</span>
|
||||||
<span className="text-brand-secondary ml-1">Before:</span>
|
<span className="text-custom-text-200 ml-1">Before:</span>
|
||||||
{!isInvalid && <span>{renderShortDateWithYearFormat(watch("date2"))}</span>}
|
{!isInvalid && <span>{renderShortDateWithYearFormat(watch("date2"))}</span>}
|
||||||
</h6>
|
</h6>
|
||||||
)}
|
)}
|
||||||
|
@ -58,9 +58,9 @@ export const FilterList: React.FC<any> = ({ filters, setFilters }) => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={key}
|
key={key}
|
||||||
className="flex items-center gap-x-2 rounded-full border border-brand-base bg-brand-surface-2 px-2 py-1"
|
className="flex items-center gap-x-2 rounded-full border border-custom-border-100 bg-custom-background-80 px-2 py-1"
|
||||||
>
|
>
|
||||||
<span className="capitalize text-brand-secondary">
|
<span className="capitalize text-custom-text-200">
|
||||||
{key === "target_date" ? "Due Date" : replaceUnderscoreIfSnakeCase(key)}:
|
{key === "target_date" ? "Due Date" : replaceUnderscoreIfSnakeCase(key)}:
|
||||||
</span>
|
</span>
|
||||||
{filters[key as keyof IIssueFilterOptions] === null ||
|
{filters[key as keyof IIssueFilterOptions] === null ||
|
||||||
@ -132,7 +132,7 @@ export const FilterList: React.FC<any> = ({ filters, setFilters }) => {
|
|||||||
? "bg-yellow-500/20 text-yellow-500"
|
? "bg-yellow-500/20 text-yellow-500"
|
||||||
: priority === "low"
|
: priority === "low"
|
||||||
? "bg-green-500/20 text-green-500"
|
? "bg-green-500/20 text-green-500"
|
||||||
: "bg-brand-surface-1 text-brand-secondary"
|
: "bg-custom-background-90 text-custom-text-200"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<span>{getPriorityIcon(priority)}</span>
|
<span>{getPriorityIcon(priority)}</span>
|
||||||
@ -171,7 +171,7 @@ export const FilterList: React.FC<any> = ({ filters, setFilters }) => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={memberId}
|
key={memberId}
|
||||||
className="inline-flex items-center gap-x-1 rounded-full bg-brand-surface-1 px-1 capitalize"
|
className="inline-flex items-center gap-x-1 rounded-full bg-custom-background-90 px-1 capitalize"
|
||||||
>
|
>
|
||||||
<Avatar user={member} />
|
<Avatar user={member} />
|
||||||
<span>{member?.first_name}</span>
|
<span>{member?.first_name}</span>
|
||||||
@ -212,7 +212,7 @@ export const FilterList: React.FC<any> = ({ filters, setFilters }) => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={`${memberId}-${key}`}
|
key={`${memberId}-${key}`}
|
||||||
className="inline-flex items-center gap-x-1 rounded-full bg-brand-surface-1 px-1 capitalize"
|
className="inline-flex items-center gap-x-1 rounded-full bg-custom-background-90 px-1 capitalize"
|
||||||
>
|
>
|
||||||
<Avatar user={member} />
|
<Avatar user={member} />
|
||||||
<span>{member?.first_name}</span>
|
<span>{member?.first_name}</span>
|
||||||
@ -310,7 +310,7 @@ export const FilterList: React.FC<any> = ({ filters, setFilters }) => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={date}
|
key={date}
|
||||||
className="inline-flex items-center gap-x-1 rounded-full border border-brand-base bg-brand-base px-1 py-0.5"
|
className="inline-flex items-center gap-x-1 rounded-full border border-custom-border-100 bg-custom-background-100 px-1 py-0.5"
|
||||||
>
|
>
|
||||||
<div className="h-1.5 w-1.5 rounded-full" />
|
<div className="h-1.5 w-1.5 rounded-full" />
|
||||||
<span className="capitalize">
|
<span className="capitalize">
|
||||||
@ -381,7 +381,7 @@ export const FilterList: React.FC<any> = ({ filters, setFilters }) => {
|
|||||||
target_date: null,
|
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"
|
||||||
>
|
>
|
||||||
<span>Clear all filters</span>
|
<span>Clear all filters</span>
|
||||||
<XMarkIcon className="h-3 w-3" />
|
<XMarkIcon className="h-3 w-3" />
|
||||||
|
@ -23,10 +23,33 @@ import {
|
|||||||
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
|
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
|
||||||
import { checkIfArraysHaveSameElements } from "helpers/array.helper";
|
import { checkIfArraysHaveSameElements } from "helpers/array.helper";
|
||||||
// types
|
// types
|
||||||
import { Properties } from "types";
|
import { Properties, TIssueViewOptions } from "types";
|
||||||
// constants
|
// constants
|
||||||
import { GROUP_BY_OPTIONS, ORDER_BY_OPTIONS, FILTER_ISSUE_OPTIONS } from "constants/issue";
|
import { GROUP_BY_OPTIONS, ORDER_BY_OPTIONS, FILTER_ISSUE_OPTIONS } from "constants/issue";
|
||||||
|
|
||||||
|
const issueViewOptions: { type: TIssueViewOptions; icon: any }[] = [
|
||||||
|
{
|
||||||
|
type: "list",
|
||||||
|
icon: <ListBulletIcon className="h-4 w-4" />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "kanban",
|
||||||
|
icon: <Squares2X2Icon className="h-4 w-4" />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "calendar",
|
||||||
|
icon: <CalendarDaysIcon className="h-4 w-4" />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "spreadsheet",
|
||||||
|
icon: <Icon iconName="table_chart" />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "gantt_chart",
|
||||||
|
icon: <Icon iconName="waterfall_chart" className="rotate-90" />,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const IssuesFilterView: React.FC = () => {
|
export const IssuesFilterView: React.FC = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, viewId } = router.query;
|
const { workspaceSlug, projectId, viewId } = router.query;
|
||||||
@ -56,53 +79,20 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="flex items-center gap-x-1">
|
<div className="flex items-center gap-x-1">
|
||||||
|
{issueViewOptions.map((option) => (
|
||||||
<button
|
<button
|
||||||
|
key={option.type}
|
||||||
type="button"
|
type="button"
|
||||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-brand-surface-2 ${
|
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80 duration-300 ${
|
||||||
issueView === "list" ? "bg-brand-surface-2" : ""
|
issueView === option.type
|
||||||
|
? "bg-custom-sidebar-background-80"
|
||||||
|
: "text-custom-sidebar-text-200"
|
||||||
}`}
|
}`}
|
||||||
onClick={() => setIssueView("list")}
|
onClick={() => setIssueView(option.type)}
|
||||||
>
|
>
|
||||||
<ListBulletIcon className="h-4 w-4 text-brand-secondary" />
|
{option.icon}
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-brand-surface-2 ${
|
|
||||||
issueView === "kanban" ? "bg-brand-surface-2" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => setIssueView("kanban")}
|
|
||||||
>
|
|
||||||
<Squares2X2Icon className="h-4 w-4 text-brand-secondary" />
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-brand-surface-2 ${
|
|
||||||
issueView === "calendar" ? "bg-brand-surface-2" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => setIssueView("calendar")}
|
|
||||||
>
|
|
||||||
<CalendarDaysIcon className="h-4 w-4 text-brand-secondary" />
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-brand-surface-2 ${
|
|
||||||
issueView === "spreadsheet" ? "bg-brand-surface-2" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => setIssueView("spreadsheet")}
|
|
||||||
>
|
|
||||||
<Icon iconName="table_chart" className="text-brand-secondary" />
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`grid h-7 w-7 place-items-center rounded outline-none duration-300 hover:bg-brand-surface-2 ${
|
|
||||||
issueView === "gantt_chart" ? "bg-brand-surface-2" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => setIssueView("gantt_chart")}
|
|
||||||
>
|
|
||||||
<span className="material-symbols-rounded text-brand-secondary text-[18px] rotate-90">
|
|
||||||
waterfall_chart
|
|
||||||
</span>
|
|
||||||
</button>
|
</button>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<SelectFilters
|
<SelectFilters
|
||||||
filters={filters}
|
filters={filters}
|
||||||
@ -146,8 +136,10 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<>
|
<>
|
||||||
<Popover.Button
|
<Popover.Button
|
||||||
className={`group flex items-center gap-2 rounded-md border border-brand-base bg-transparent px-3 py-1.5 text-xs hover:bg-brand-surface-1 hover:text-brand-base focus:outline-none ${
|
className={`group flex items-center gap-2 rounded-md border border-custom-sidebar-border-100 bg-transparent px-3 py-1.5 text-xs hover:bg-custom-sidebar-background-90 hover:text-custom-sidebar-text-100 focus:outline-none duration-300 ${
|
||||||
open ? "bg-brand-surface-1 text-brand-base" : "text-brand-secondary"
|
open
|
||||||
|
? "bg-custom-sidebar-background-90 text-custom-sidebar-text-100"
|
||||||
|
: "text-custom-sidebar-text-200"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
View
|
View
|
||||||
@ -163,13 +155,13 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
leaveFrom="opacity-100 translate-y-0"
|
leaveFrom="opacity-100 translate-y-0"
|
||||||
leaveTo="opacity-0 translate-y-1"
|
leaveTo="opacity-0 translate-y-1"
|
||||||
>
|
>
|
||||||
<Popover.Panel className="absolute right-0 z-30 mt-1 w-screen max-w-xs transform rounded-lg border border-brand-base bg-brand-surface-1 p-3 shadow-lg">
|
<Popover.Panel className="absolute right-0 z-30 mt-1 w-screen max-w-xs transform rounded-lg border border-custom-border-100 bg-custom-background-90 p-3 shadow-lg">
|
||||||
<div className="relative divide-y-2 divide-brand-base">
|
<div className="relative divide-y-2 divide-custom-border-100">
|
||||||
<div className="space-y-4 pb-3 text-xs">
|
<div className="space-y-4 pb-3 text-xs">
|
||||||
{issueView !== "calendar" && issueView !== "spreadsheet" && (
|
{issueView !== "calendar" && issueView !== "spreadsheet" && (
|
||||||
<>
|
<>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h4 className="text-brand-secondary">Group by</h4>
|
<h4 className="text-custom-text-200">Group by</h4>
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
label={
|
label={
|
||||||
GROUP_BY_OPTIONS.find((option) => option.key === groupByProperty)
|
GROUP_BY_OPTIONS.find((option) => option.key === groupByProperty)
|
||||||
@ -190,7 +182,7 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
</CustomMenu>
|
</CustomMenu>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h4 className="text-brand-secondary">Order by</h4>
|
<h4 className="text-custom-text-200">Order by</h4>
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
label={
|
label={
|
||||||
ORDER_BY_OPTIONS.find((option) => option.key === orderBy)?.name ??
|
ORDER_BY_OPTIONS.find((option) => option.key === orderBy)?.name ??
|
||||||
@ -215,7 +207,7 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h4 className="text-brand-secondary">Issue type</h4>
|
<h4 className="text-custom-text-200">Issue type</h4>
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
label={
|
label={
|
||||||
FILTER_ISSUE_OPTIONS.find((option) => option.key === filters.type)
|
FILTER_ISSUE_OPTIONS.find((option) => option.key === filters.type)
|
||||||
@ -241,7 +233,7 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
{issueView !== "calendar" && issueView !== "spreadsheet" && (
|
{issueView !== "calendar" && issueView !== "spreadsheet" && (
|
||||||
<>
|
<>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h4 className="text-brand-secondary">Show empty states</h4>
|
<h4 className="text-custom-text-200">Show empty states</h4>
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
value={showEmptyGroups}
|
value={showEmptyGroups}
|
||||||
onChange={() => setShowEmptyGroups(!showEmptyGroups)}
|
onChange={() => setShowEmptyGroups(!showEmptyGroups)}
|
||||||
@ -253,7 +245,7 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="font-medium text-brand-accent"
|
className="font-medium text-custom-primary"
|
||||||
onClick={() => setNewFilterDefaultView()}
|
onClick={() => setNewFilterDefaultView()}
|
||||||
>
|
>
|
||||||
Set as default
|
Set as default
|
||||||
@ -264,7 +256,7 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2 py-3">
|
<div className="space-y-2 py-3">
|
||||||
<h4 className="text-sm text-brand-secondary">Display Properties</h4>
|
<h4 className="text-sm text-custom-text-200">Display Properties</h4>
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
{Object.keys(properties).map((key) => {
|
{Object.keys(properties).map((key) => {
|
||||||
if (key === "estimate" && !isEstimateActive) return null;
|
if (key === "estimate" && !isEstimateActive) return null;
|
||||||
@ -289,8 +281,8 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
type="button"
|
type="button"
|
||||||
className={`rounded border px-2 py-1 text-xs capitalize ${
|
className={`rounded border px-2 py-1 text-xs capitalize ${
|
||||||
properties[key as keyof Properties]
|
properties[key as keyof Properties]
|
||||||
? "border-brand-accent bg-brand-accent text-white"
|
? "border-custom-primary bg-custom-primary text-white"
|
||||||
: "border-brand-base"
|
: "border-custom-border-100"
|
||||||
}`}
|
}`}
|
||||||
onClick={() => setProperties(key as keyof Properties)}
|
onClick={() => setProperties(key as keyof Properties)}
|
||||||
>
|
>
|
||||||
|
@ -62,7 +62,7 @@ export const ImagePickerPopover: React.FC<Props> = ({ label, value, onChange })
|
|||||||
return (
|
return (
|
||||||
<Popover className="relative z-[2]" ref={ref}>
|
<Popover className="relative z-[2]" ref={ref}>
|
||||||
<Popover.Button
|
<Popover.Button
|
||||||
className="rounded-md border border-brand-base bg-brand-surface-2 px-2 py-1 text-xs text-brand-secondary"
|
className="rounded-md border border-custom-border-100 bg-custom-background-80 px-2 py-1 text-xs text-custom-text-200"
|
||||||
onClick={() => setIsOpen((prev) => !prev)}
|
onClick={() => setIsOpen((prev) => !prev)}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
@ -76,16 +76,16 @@ export const ImagePickerPopover: React.FC<Props> = ({ label, value, onChange })
|
|||||||
leaveFrom="transform opacity-100 scale-100"
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
leaveTo="transform opacity-0 scale-95"
|
leaveTo="transform opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<Popover.Panel className="absolute right-0 z-10 mt-2 rounded-md border border-brand-base bg-brand-surface-2 shadow-lg">
|
<Popover.Panel className="absolute right-0 z-10 mt-2 rounded-md border border-custom-border-100 bg-custom-background-80 shadow-lg">
|
||||||
<div className="h-96 w-80 overflow-auto rounded border border-brand-base bg-brand-surface-2 p-5 shadow-2xl sm:max-w-2xl md:w-96 lg:w-[40rem]">
|
<div className="h-96 w-80 overflow-auto rounded border border-custom-border-100 bg-custom-background-80 p-5 shadow-2xl sm:max-w-2xl md:w-96 lg:w-[40rem]">
|
||||||
<Tab.Group>
|
<Tab.Group>
|
||||||
<Tab.List as="span" className="inline-block rounded bg-brand-surface-2 p-1">
|
<Tab.List as="span" className="inline-block rounded bg-custom-background-80 p-1">
|
||||||
{tabOptions.map((tab) => (
|
{tabOptions.map((tab) => (
|
||||||
<Tab
|
<Tab
|
||||||
key={tab.key}
|
key={tab.key}
|
||||||
className={({ selected }) =>
|
className={({ selected }) =>
|
||||||
`rounded py-1 px-4 text-center text-sm outline-none transition-colors ${
|
`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"
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -5,10 +5,8 @@ export * from "./gantt-chart-view";
|
|||||||
export * from "./list-view";
|
export * from "./list-view";
|
||||||
export * from "./modals";
|
export * from "./modals";
|
||||||
export * from "./spreadsheet-view";
|
export * from "./spreadsheet-view";
|
||||||
|
export * from "./theme";
|
||||||
export * from "./sidebar";
|
export * from "./sidebar";
|
||||||
export * from "./issues-view";
|
export * from "./issues-view";
|
||||||
export * from "./image-picker-popover";
|
export * from "./image-picker-popover";
|
||||||
export * from "./feeds";
|
export * from "./feeds";
|
||||||
export * from "./theme-switch";
|
|
||||||
export * from "./custom-theme-selector";
|
|
||||||
export * from "./color-picker-input";
|
|
||||||
|
@ -29,19 +29,13 @@ import {
|
|||||||
} from "components/core";
|
} from "components/core";
|
||||||
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
||||||
import { CreateUpdateViewModal } from "components/views";
|
import { CreateUpdateViewModal } from "components/views";
|
||||||
import { CycleIssuesGanttChartView, TransferIssues, TransferIssuesModal } from "components/cycles";
|
import { TransferIssues, TransferIssuesModal } from "components/cycles";
|
||||||
import { IssueGanttChartView } from "components/issues/gantt-chart";
|
|
||||||
// ui
|
// ui
|
||||||
import { EmptySpace, EmptySpaceItem, EmptyState, PrimaryButton, Spinner } from "components/ui";
|
import { EmptyState, PrimaryButton, Spinner } from "components/ui";
|
||||||
// icons
|
// icons
|
||||||
import {
|
import { PlusIcon, TrashIcon } from "@heroicons/react/24/outline";
|
||||||
ListBulletIcon,
|
|
||||||
PlusIcon,
|
|
||||||
RectangleStackIcon,
|
|
||||||
TrashIcon,
|
|
||||||
} from "@heroicons/react/24/outline";
|
|
||||||
// images
|
// images
|
||||||
import emptyIssue from "public/empty-state/empty-issue.svg";
|
import emptyIssue from "public/empty-state/issue.svg";
|
||||||
// helpers
|
// helpers
|
||||||
import { getStatesList } from "helpers/state.helper";
|
import { getStatesList } from "helpers/state.helper";
|
||||||
import { orderArrayBy } from "helpers/array.helper";
|
import { orderArrayBy } from "helpers/array.helper";
|
||||||
@ -56,7 +50,6 @@ import {
|
|||||||
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
||||||
STATES_LIST,
|
STATES_LIST,
|
||||||
} from "constants/fetch-keys";
|
} from "constants/fetch-keys";
|
||||||
import { ModuleIssuesGanttChartView } from "components/modules";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
type?: "issue" | "cycle" | "module";
|
type?: "issue" | "cycle" | "module";
|
||||||
@ -107,7 +100,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
groupByProperty: selectedGroup,
|
groupByProperty: selectedGroup,
|
||||||
orderBy,
|
orderBy,
|
||||||
filters,
|
filters,
|
||||||
isNotEmpty,
|
isEmpty,
|
||||||
setFilters,
|
setFilters,
|
||||||
params,
|
params,
|
||||||
} = useIssuesView();
|
} = useIssuesView();
|
||||||
@ -495,7 +488,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
{viewId ? "Update" : "Save"} view
|
{viewId ? "Update" : "Save"} view
|
||||||
</PrimaryButton>
|
</PrimaryButton>
|
||||||
</div>
|
</div>
|
||||||
{<div className="mt-3 border-t border-brand-base" />}
|
{<div className="mt-3 border-t border-custom-border-100" />}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -505,7 +498,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
trashBox ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"
|
trashBox ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"
|
||||||
} fixed top-4 left-1/2 -translate-x-1/2 z-40 w-72 flex items-center justify-center gap-2 rounded border-2 border-red-500/20 bg-brand-base px-3 py-5 text-xs font-medium italic text-red-500 ${
|
} fixed top-4 left-1/2 -translate-x-1/2 z-40 w-72 flex items-center justify-center gap-2 rounded border-2 border-red-500/20 bg-custom-background-100 px-3 py-5 text-xs font-medium italic text-red-500 ${
|
||||||
snapshot.isDraggingOver ? "bg-red-500 blur-2xl opacity-70" : ""
|
snapshot.isDraggingOver ? "bg-red-500 blur-2xl opacity-70" : ""
|
||||||
} transition duration-300`}
|
} transition duration-300`}
|
||||||
ref={provided.innerRef}
|
ref={provided.innerRef}
|
||||||
@ -517,7 +510,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
</StrictModeDroppable>
|
</StrictModeDroppable>
|
||||||
{groupedByIssues ? (
|
{groupedByIssues ? (
|
||||||
isNotEmpty ? (
|
!isEmpty || issueView === "kanban" || issueView === "calendar" ? (
|
||||||
<>
|
<>
|
||||||
{isCompleted && <TransferIssues handleClick={() => setTransferIssuesModal(true)} />}
|
{isCompleted && <TransferIssues handleClick={() => setTransferIssuesModal(true)} />}
|
||||||
{issueView === "list" ? (
|
{issueView === "list" ? (
|
||||||
@ -584,46 +577,20 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
issueView === "gantt_chart" && <GanttChartView />
|
issueView === "gantt_chart" && <GanttChartView />
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : type === "issue" ? (
|
|
||||||
<EmptyState
|
|
||||||
type="issue"
|
|
||||||
title="Create New Issue"
|
|
||||||
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
|
|
||||||
imgURL={emptyIssue}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<div className="grid h-full w-full place-items-center px-4 sm:px-0">
|
<EmptyState
|
||||||
<EmptySpace
|
title="Project issues will appear here"
|
||||||
title="You don't have any issue yet."
|
|
||||||
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
|
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
|
||||||
Icon={RectangleStackIcon}
|
image={emptyIssue}
|
||||||
>
|
buttonText="New Issue"
|
||||||
<EmptySpaceItem
|
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||||
title="Create a new issue"
|
onClick={() => {
|
||||||
description={
|
|
||||||
<span>
|
|
||||||
Use <pre className="inline rounded bg-brand-surface-2 px-2 py-1">C</pre>{" "}
|
|
||||||
shortcut to create a new issue
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
Icon={PlusIcon}
|
|
||||||
action={() => {
|
|
||||||
const e = new KeyboardEvent("keydown", {
|
const e = new KeyboardEvent("keydown", {
|
||||||
key: "c",
|
key: "c",
|
||||||
});
|
});
|
||||||
document.dispatchEvent(e);
|
document.dispatchEvent(e);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{openIssuesListModal && (
|
|
||||||
<EmptySpaceItem
|
|
||||||
title="Add an existing issue"
|
|
||||||
description="Open list"
|
|
||||||
Icon={ListBulletIcon}
|
|
||||||
action={openIssuesListModal}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</EmptySpace>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
<div className="flex h-full w-full items-center justify-center">
|
<div className="flex h-full w-full items-center justify-center">
|
||||||
|
@ -218,7 +218,7 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
</a>
|
</a>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
<div
|
<div
|
||||||
className="flex flex-wrap items-center justify-between px-4 py-2.5 gap-2 border-b border-brand-base bg-brand-base last:border-b-0"
|
className="flex flex-wrap items-center justify-between px-4 py-2.5 gap-2 border-b border-custom-border-100 bg-custom-background-100 last:border-b-0"
|
||||||
onContextMenu={(e) => {
|
onContextMenu={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setContextMenu(true);
|
setContextMenu(true);
|
||||||
@ -233,13 +233,13 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
tooltipHeading="Issue ID"
|
tooltipHeading="Issue ID"
|
||||||
tooltipContent={`${issue.project_detail?.identifier}-${issue.sequence_id}`}
|
tooltipContent={`${issue.project_detail?.identifier}-${issue.sequence_id}`}
|
||||||
>
|
>
|
||||||
<span className="flex-shrink-0 text-xs text-brand-secondary">
|
<span className="flex-shrink-0 text-xs text-custom-text-200">
|
||||||
{issue.project_detail?.identifier}-{issue.sequence_id}
|
{issue.project_detail?.identifier}-{issue.sequence_id}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
<Tooltip position="top-left" tooltipHeading="Title" tooltipContent={issue.name}>
|
<Tooltip position="top-left" tooltipHeading="Title" tooltipContent={issue.name}>
|
||||||
<span className="text-[0.825rem] text-brand-base">
|
<span className="text-[0.825rem] text-custom-text-100">
|
||||||
{truncateText(issue.name, 50)}
|
{truncateText(issue.name, 50)}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -302,9 +302,9 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{properties.sub_issue_count && (
|
{properties.sub_issue_count && (
|
||||||
<div className="flex cursor-default items-center rounded-md border border-brand-base px-2.5 py-1 text-xs shadow-sm">
|
<div className="flex cursor-default items-center rounded-md border border-custom-border-100 px-2.5 py-1 text-xs shadow-sm">
|
||||||
<Tooltip tooltipHeading="Sub-issue" tooltipContent={`${issue.sub_issues_count}`}>
|
<Tooltip tooltipHeading="Sub-issue" tooltipContent={`${issue.sub_issues_count}`}>
|
||||||
<div className="flex items-center gap-1 text-brand-secondary">
|
<div className="flex items-center gap-1 text-custom-text-200">
|
||||||
<LayerDiagonalIcon className="h-3.5 w-3.5" />
|
<LayerDiagonalIcon className="h-3.5 w-3.5" />
|
||||||
{issue.sub_issues_count}
|
{issue.sub_issues_count}
|
||||||
</div>
|
</div>
|
||||||
@ -312,9 +312,9 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{properties.link && (
|
{properties.link && (
|
||||||
<div className="flex cursor-default items-center rounded-md border border-brand-base px-2.5 py-1 text-xs shadow-sm">
|
<div className="flex cursor-default items-center rounded-md border border-custom-border-100 px-2.5 py-1 text-xs shadow-sm">
|
||||||
<Tooltip tooltipHeading="Links" tooltipContent={`${issue.link_count}`}>
|
<Tooltip tooltipHeading="Links" tooltipContent={`${issue.link_count}`}>
|
||||||
<div className="flex items-center gap-1 text-brand-secondary">
|
<div className="flex items-center gap-1 text-custom-text-200">
|
||||||
<LinkIcon className="h-3.5 w-3.5" />
|
<LinkIcon className="h-3.5 w-3.5" />
|
||||||
{issue.link_count}
|
{issue.link_count}
|
||||||
</div>
|
</div>
|
||||||
@ -322,9 +322,9 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{properties.attachment_count && (
|
{properties.attachment_count && (
|
||||||
<div className="flex cursor-default items-center rounded-md border border-brand-base px-2.5 py-1 text-xs shadow-sm">
|
<div className="flex cursor-default items-center rounded-md border border-custom-border-100 px-2.5 py-1 text-xs shadow-sm">
|
||||||
<Tooltip tooltipHeading="Attachments" tooltipContent={`${issue.attachment_count}`}>
|
<Tooltip tooltipHeading="Attachments" tooltipContent={`${issue.attachment_count}`}>
|
||||||
<div className="flex items-center gap-1 text-brand-secondary">
|
<div className="flex items-center gap-1 text-custom-text-200">
|
||||||
<PaperClipIcon className="h-3.5 w-3.5 -rotate-45" />
|
<PaperClipIcon className="h-3.5 w-3.5 -rotate-45" />
|
||||||
{issue.attachment_count}
|
{issue.attachment_count}
|
||||||
</div>
|
</div>
|
||||||
|
@ -141,20 +141,20 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
<Disclosure as="div" defaultOpen>
|
<Disclosure as="div" defaultOpen>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center justify-between px-4 py-2.5">
|
<div className="flex items-center justify-between px-4 py-2.5 bg-custom-background-90">
|
||||||
<Disclosure.Button>
|
<Disclosure.Button>
|
||||||
<div className="flex items-center gap-x-3">
|
<div className="flex items-center gap-x-3">
|
||||||
{selectedGroup !== null && (
|
{selectedGroup !== null && (
|
||||||
<div className="flex items-center">{getGroupIcon()}</div>
|
<div className="flex items-center">{getGroupIcon()}</div>
|
||||||
)}
|
)}
|
||||||
{selectedGroup !== null ? (
|
{selectedGroup !== null ? (
|
||||||
<h2 className="text-sm font-semibold capitalize leading-6 text-brand-base">
|
<h2 className="text-sm font-semibold capitalize leading-6 text-custom-text-100">
|
||||||
{getGroupTitle()}
|
{getGroupTitle()}
|
||||||
</h2>
|
</h2>
|
||||||
) : (
|
) : (
|
||||||
<h2 className="font-medium leading-5">All Issues</h2>
|
<h2 className="font-medium leading-5">All Issues</h2>
|
||||||
)}
|
)}
|
||||||
<span className="text-brand-2 min-w-[2.5rem] rounded-full bg-brand-surface-2 py-1 text-center text-xs">
|
<span className="text-custom-text-200 min-w-[2.5rem] rounded-full bg-custom-background-80 py-1 text-center text-xs">
|
||||||
{groupedByIssues[groupTitle as keyof IIssue].length}
|
{groupedByIssues[groupTitle as keyof IIssue].length}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -162,7 +162,7 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
{type === "issue" ? (
|
{type === "issue" ? (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="p-1 text-brand-secondary hover:bg-brand-surface-2"
|
className="p-1 text-custom-text-200 hover:bg-custom-background-80"
|
||||||
onClick={addIssueToState}
|
onClick={addIssueToState}
|
||||||
>
|
>
|
||||||
<PlusIcon className="h-4 w-4" />
|
<PlusIcon className="h-4 w-4" />
|
||||||
@ -221,7 +221,7 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<p className="bg-brand-base px-4 py-2.5 text-sm text-brand-secondary">
|
<p className="bg-custom-background-100 px-4 py-2.5 text-sm text-custom-text-200">
|
||||||
No issues.
|
No issues.
|
||||||
</p>
|
</p>
|
||||||
)
|
)
|
||||||
|
@ -173,7 +173,7 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
|
|||||||
leaveFrom="opacity-100 scale-100"
|
leaveFrom="opacity-100 scale-100"
|
||||||
leaveTo="opacity-0 scale-95"
|
leaveTo="opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative mx-auto max-w-2xl transform divide-y divide-gray-500 rounded-xl border border-brand-base bg-brand-base shadow-2xl transition-all">
|
<Dialog.Panel className="relative mx-auto max-w-2xl transform rounded-xl border border-custom-border-100 bg-custom-background-100 shadow-2xl transition-all">
|
||||||
<form>
|
<form>
|
||||||
<Combobox
|
<Combobox
|
||||||
onChange={(val: string) => {
|
onChange={(val: string) => {
|
||||||
@ -188,12 +188,12 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
|
|||||||
>
|
>
|
||||||
<div className="relative m-1">
|
<div className="relative m-1">
|
||||||
<MagnifyingGlassIcon
|
<MagnifyingGlassIcon
|
||||||
className="pointer-events-none absolute top-3.5 left-4 h-5 w-5 text-brand-base text-opacity-40"
|
className="pointer-events-none absolute top-3.5 left-4 h-5 w-5 text-custom-text-100 text-opacity-40"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="h-12 w-full border-0 bg-transparent pl-11 pr-4 text-brand-base placeholder-gray-500 outline-none focus:ring-0 sm:text-sm"
|
className="h-12 w-full border-0 bg-transparent pl-11 pr-4 text-custom-text-100 outline-none focus:ring-0 sm:text-sm"
|
||||||
placeholder="Search..."
|
placeholder="Search..."
|
||||||
onChange={(event) => setQuery(event.target.value)}
|
onChange={(event) => setQuery(event.target.value)}
|
||||||
/>
|
/>
|
||||||
@ -201,16 +201,16 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
|
|||||||
|
|
||||||
<Combobox.Options
|
<Combobox.Options
|
||||||
static
|
static
|
||||||
className="max-h-80 scroll-py-2 divide-y divide-brand-base overflow-y-auto"
|
className="max-h-80 scroll-py-2 divide-y divide-custom-border-100 overflow-y-auto"
|
||||||
>
|
>
|
||||||
{filteredIssues.length > 0 ? (
|
{filteredIssues.length > 0 ? (
|
||||||
<li className="p-2">
|
<li className="p-2">
|
||||||
{query === "" && (
|
{query === "" && (
|
||||||
<h2 className="mt-4 mb-2 px-3 text-xs font-semibold text-brand-base">
|
<h2 className="mt-4 mb-2 px-3 text-xs font-semibold text-custom-text-100">
|
||||||
Select issues to delete
|
Select issues to delete
|
||||||
</h2>
|
</h2>
|
||||||
)}
|
)}
|
||||||
<ul className="text-sm text-brand-secondary">
|
<ul className="text-sm text-custom-text-200">
|
||||||
{filteredIssues.map((issue) => (
|
{filteredIssues.map((issue) => (
|
||||||
<Combobox.Option
|
<Combobox.Option
|
||||||
key={issue.id}
|
key={issue.id}
|
||||||
@ -218,7 +218,7 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
|
|||||||
value={issue.id}
|
value={issue.id}
|
||||||
className={({ active, selected }) =>
|
className={({ active, selected }) =>
|
||||||
`flex cursor-pointer select-none items-center justify-between rounded-md px-3 py-2 ${
|
`flex cursor-pointer select-none items-center justify-between rounded-md px-3 py-2 ${
|
||||||
active ? "bg-brand-surface-2 text-brand-base" : ""
|
active ? "bg-custom-background-80 text-custom-text-100" : ""
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -246,9 +246,9 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
|
|||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col items-center justify-center gap-4 px-3 py-8 text-center">
|
<div className="flex flex-col items-center justify-center gap-4 px-3 py-8 text-center">
|
||||||
<LayerDiagonalIcon height="56" width="56" />
|
<LayerDiagonalIcon height="56" width="56" />
|
||||||
<h3 className="text-brand-secondary">
|
<h3 className="text-custom-text-200">
|
||||||
No issues found. Create a new issue with{" "}
|
No issues found. Create a new issue with{" "}
|
||||||
<pre className="inline rounded bg-brand-surface-2 px-2 py-1">C</pre>.
|
<pre className="inline rounded bg-custom-background-80 px-2 py-1">C</pre>.
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -141,7 +141,7 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
|||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<div className="fixed inset-0 bg-brand-backdrop bg-opacity-50 transition-opacity" />
|
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
|
|
||||||
<div className="fixed inset-0 z-10 overflow-y-auto p-4 sm:p-6 md:p-20">
|
<div className="fixed inset-0 z-10 overflow-y-auto p-4 sm:p-6 md:p-20">
|
||||||
@ -154,7 +154,7 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
|||||||
leaveFrom="opacity-100 scale-100"
|
leaveFrom="opacity-100 scale-100"
|
||||||
leaveTo="opacity-0 scale-95"
|
leaveTo="opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative mx-auto max-w-2xl transform rounded-xl border border-brand-base bg-brand-base shadow-2xl transition-all">
|
<Dialog.Panel className="relative mx-auto max-w-2xl transform rounded-xl border border-custom-border-100 bg-custom-background-100 shadow-2xl transition-all">
|
||||||
<Combobox
|
<Combobox
|
||||||
as="div"
|
as="div"
|
||||||
onChange={(val: ISearchIssueResponse) => {
|
onChange={(val: ISearchIssueResponse) => {
|
||||||
@ -165,24 +165,24 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
|||||||
>
|
>
|
||||||
<div className="relative m-1">
|
<div className="relative m-1">
|
||||||
<MagnifyingGlassIcon
|
<MagnifyingGlassIcon
|
||||||
className="pointer-events-none absolute top-3.5 left-4 h-5 w-5 text-brand-base text-opacity-40"
|
className="pointer-events-none absolute top-3.5 left-4 h-5 w-5 text-custom-text-100 text-opacity-40"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
<Combobox.Input
|
<Combobox.Input
|
||||||
className="h-12 w-full border-0 bg-transparent pl-11 pr-4 text-brand-base placeholder-gray-500 outline-none focus:ring-0 sm:text-sm"
|
className="h-12 w-full border-0 bg-transparent pl-11 pr-4 text-custom-text-100 outline-none focus:ring-0 sm:text-sm"
|
||||||
placeholder="Type to search..."
|
placeholder="Type to search..."
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="text-brand-secondary text-[0.825rem] p-2">
|
<div className="text-custom-text-200 text-[0.825rem] p-2">
|
||||||
{selectedIssues.length > 0 ? (
|
{selectedIssues.length > 0 ? (
|
||||||
<div className="flex items-center gap-2 flex-wrap mt-1">
|
<div className="flex items-center gap-2 flex-wrap mt-1">
|
||||||
{selectedIssues.map((issue) => (
|
{selectedIssues.map((issue) => (
|
||||||
<div
|
<div
|
||||||
key={issue.id}
|
key={issue.id}
|
||||||
className="flex items-center gap-1 text-xs border border-brand-base bg-brand-surface-2 pl-2 py-1 rounded-md text-brand-base whitespace-nowrap"
|
className="flex items-center gap-1 text-xs border border-custom-border-100 bg-custom-background-80 pl-2 py-1 rounded-md text-custom-text-100 whitespace-nowrap"
|
||||||
>
|
>
|
||||||
{issue.project__identifier}-{issue.sequence_id}
|
{issue.project__identifier}-{issue.sequence_id}
|
||||||
<button
|
<button
|
||||||
@ -194,13 +194,13 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<XMarkIcon className="h-3 w-3 text-brand-secondary group-hover:text-brand-base" />
|
<XMarkIcon className="h-3 w-3 text-custom-text-200 group-hover:text-custom-text-100" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="w-min text-xs border border-brand-base bg-brand-surface-2 p-2 rounded-md whitespace-nowrap">
|
<div className="w-min text-xs border border-custom-border-100 bg-custom-background-80 p-2 rounded-md whitespace-nowrap">
|
||||||
No issues selected
|
No issues selected
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -208,9 +208,9 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
|||||||
|
|
||||||
<Combobox.Options static className="max-h-80 scroll-py-2 overflow-y-auto mt-2">
|
<Combobox.Options static className="max-h-80 scroll-py-2 overflow-y-auto mt-2">
|
||||||
{debouncedSearchTerm !== "" && (
|
{debouncedSearchTerm !== "" && (
|
||||||
<h5 className="text-[0.825rem] text-brand-secondary mx-2">
|
<h5 className="text-[0.825rem] text-custom-text-200 mx-2">
|
||||||
Search results for{" "}
|
Search results for{" "}
|
||||||
<span className="text-brand-base">
|
<span className="text-custom-text-100">
|
||||||
{'"'}
|
{'"'}
|
||||||
{debouncedSearchTerm}
|
{debouncedSearchTerm}
|
||||||
{'"'}
|
{'"'}
|
||||||
@ -225,9 +225,9 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
|||||||
debouncedSearchTerm !== "" && (
|
debouncedSearchTerm !== "" && (
|
||||||
<div className="flex flex-col items-center justify-center gap-4 px-3 py-8 text-center">
|
<div className="flex flex-col items-center justify-center gap-4 px-3 py-8 text-center">
|
||||||
<LayerDiagonalIcon height="52" width="52" />
|
<LayerDiagonalIcon height="52" width="52" />
|
||||||
<h3 className="text-brand-secondary">
|
<h3 className="text-custom-text-200">
|
||||||
No issues found. Create a new issue with{" "}
|
No issues found. Create a new issue with{" "}
|
||||||
<pre className="inline rounded bg-brand-surface-2 px-2 py-1 text-sm">
|
<pre className="inline rounded bg-custom-background-80 px-2 py-1 text-sm">
|
||||||
C
|
C
|
||||||
</pre>
|
</pre>
|
||||||
.
|
.
|
||||||
@ -243,7 +243,9 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
|||||||
<Loader.Item height="40px" />
|
<Loader.Item height="40px" />
|
||||||
</Loader>
|
</Loader>
|
||||||
) : (
|
) : (
|
||||||
<ul className={`text-sm text-brand-base ${issues.length > 0 ? "p-2" : ""}`}>
|
<ul
|
||||||
|
className={`text-sm text-custom-text-100 ${issues.length > 0 ? "p-2" : ""}`}
|
||||||
|
>
|
||||||
{issues.map((issue) => {
|
{issues.map((issue) => {
|
||||||
const selected = selectedIssues.some((i) => i.id === issue.id);
|
const selected = selectedIssues.some((i) => i.id === issue.id);
|
||||||
|
|
||||||
@ -254,9 +256,9 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
|||||||
htmlFor={`issue-${issue.id}`}
|
htmlFor={`issue-${issue.id}`}
|
||||||
value={issue}
|
value={issue}
|
||||||
className={({ active }) =>
|
className={({ active }) =>
|
||||||
`flex w-full cursor-pointer select-none items-center gap-2 rounded-md px-3 py-2 text-brand-secondary ${
|
`flex w-full cursor-pointer select-none items-center gap-2 rounded-md px-3 py-2 text-custom-text-200 ${
|
||||||
active ? "bg-brand-surface-2 text-brand-base" : ""
|
active ? "bg-custom-background-80 text-custom-text-100" : ""
|
||||||
} ${selected ? "text-brand-base" : ""}`
|
} ${selected ? "text-custom-text-100" : ""}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<input type="checkbox" checked={selected} readOnly />
|
<input type="checkbox" checked={selected} readOnly />
|
||||||
|
@ -143,7 +143,7 @@ export const GptAssistantModal: React.FC<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`absolute ${inset} z-20 w-full space-y-4 rounded-[10px] border border-brand-base bg-brand-base p-4 shadow ${
|
className={`absolute ${inset} z-20 w-full space-y-4 rounded-[10px] border border-custom-border-100 bg-custom-background-100 p-4 shadow ${
|
||||||
isOpen ? "block" : "hidden"
|
isOpen ? "block" : "hidden"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
@ -104,7 +104,7 @@ export const ImageUploadModal: React.FC<Props> = ({
|
|||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<div className="fixed inset-0 bg-brand-backdrop bg-opacity-50 transition-opacity" />
|
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
|
|
||||||
<div className="fixed inset-0 z-30 overflow-y-auto">
|
<div className="fixed inset-0 z-30 overflow-y-auto">
|
||||||
@ -118,18 +118,21 @@ export const ImageUploadModal: React.FC<Props> = ({
|
|||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative transform overflow-hidden rounded-lg border border-brand-base bg-brand-base px-5 py-8 text-left shadow-xl transition-all sm:w-full sm:max-w-xl sm:p-6">
|
<Dialog.Panel className="relative transform overflow-hidden rounded-lg border border-custom-border-100 bg-custom-background-100 px-5 py-8 text-left shadow-xl transition-all sm:w-full sm:max-w-xl sm:p-6">
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-brand-base">
|
<Dialog.Title
|
||||||
|
as="h3"
|
||||||
|
className="text-lg font-medium leading-6 text-custom-text-100"
|
||||||
|
>
|
||||||
Upload Image
|
Upload Image
|
||||||
</Dialog.Title>
|
</Dialog.Title>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div
|
<div
|
||||||
{...getRootProps()}
|
{...getRootProps()}
|
||||||
className={`relative grid h-80 w-full cursor-pointer place-items-center rounded-lg p-12 text-center focus:outline-none focus:ring-2 focus:ring-brand-accent focus:ring-offset-2 ${
|
className={`relative grid h-80 w-full cursor-pointer place-items-center rounded-lg p-12 text-center focus:outline-none focus:ring-2 focus:ring-custom-primary focus:ring-offset-2 ${
|
||||||
(image === null && isDragActive) || !value
|
(image === null && isDragActive) || !value
|
||||||
? "border-2 border-dashed border-brand-base hover:bg-brand-surface-1"
|
? "border-2 border-dashed border-custom-border-100 hover:bg-custom-background-90"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@ -137,7 +140,7 @@ export const ImageUploadModal: React.FC<Props> = ({
|
|||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="absolute top-0 right-0 z-40 translate-x-1/2 -translate-y-1/2 rounded bg-brand-surface-1 px-2 py-0.5 text-xs font-medium text-brand-secondary"
|
className="absolute top-0 right-0 z-40 translate-x-1/2 -translate-y-1/2 rounded bg-custom-background-90 px-2 py-0.5 text-xs font-medium text-custom-text-200"
|
||||||
>
|
>
|
||||||
Edit
|
Edit
|
||||||
</button>
|
</button>
|
||||||
@ -151,8 +154,8 @@ export const ImageUploadModal: React.FC<Props> = ({
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<UserCircleIcon className="mx-auto h-16 w-16 text-brand-secondary" />
|
<UserCircleIcon className="mx-auto h-16 w-16 text-custom-text-200" />
|
||||||
<span className="mt-2 block text-sm font-medium text-brand-secondary">
|
<span className="mt-2 block text-sm font-medium text-custom-text-200">
|
||||||
{isDragActive
|
{isDragActive
|
||||||
? "Drop image here to upload"
|
? "Drop image here to upload"
|
||||||
: "Drag & drop image here"}
|
: "Drag & drop image here"}
|
||||||
|
@ -70,11 +70,14 @@ export const LinkModal: React.FC<Props> = ({ isOpen, handleClose, onFormSubmit }
|
|||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-brand-surface-2 px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-custom-background-80 px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div>
|
<div>
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-brand-base">
|
<Dialog.Title
|
||||||
|
as="h3"
|
||||||
|
className="text-lg font-medium leading-6 text-custom-text-100"
|
||||||
|
>
|
||||||
Add Link
|
Add Link
|
||||||
</Dialog.Title>
|
</Dialog.Title>
|
||||||
<div className="mt-2 space-y-3">
|
<div className="mt-2 space-y-3">
|
||||||
|
@ -32,15 +32,15 @@ export const LinksList: React.FC<Props> = ({ links, handleDeleteLink, userAuth }
|
|||||||
<div className="absolute top-1.5 right-1.5 z-[1] flex items-center gap-1">
|
<div className="absolute top-1.5 right-1.5 z-[1] flex items-center gap-1">
|
||||||
<Link href={link.url}>
|
<Link href={link.url}>
|
||||||
<a
|
<a
|
||||||
className="grid h-7 w-7 place-items-center rounded bg-brand-surface-1 p-1 outline-none hover:bg-brand-surface-2"
|
className="grid h-7 w-7 place-items-center rounded bg-custom-background-90 p-1 outline-none hover:bg-custom-background-80"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<ArrowTopRightOnSquareIcon className="h-4 w-4 text-brand-secondary" />
|
<ArrowTopRightOnSquareIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="grid h-7 w-7 place-items-center rounded bg-brand-surface-1 p-1 text-red-500 outline-none duration-300 hover:bg-red-500/20"
|
className="grid h-7 w-7 place-items-center rounded bg-custom-background-90 p-1 text-red-500 outline-none duration-300 hover:bg-red-500/20"
|
||||||
onClick={() => handleDeleteLink(link.id)}
|
onClick={() => handleDeleteLink(link.id)}
|
||||||
>
|
>
|
||||||
<TrashIcon className="h-4 w-4" />
|
<TrashIcon className="h-4 w-4" />
|
||||||
@ -48,13 +48,16 @@ export const LinksList: React.FC<Props> = ({ links, handleDeleteLink, userAuth }
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Link href={link.url}>
|
<Link href={link.url}>
|
||||||
<a className="relative flex gap-2 rounded-md bg-brand-base p-2" target="_blank">
|
<a
|
||||||
|
className="relative flex gap-2 rounded-md bg-custom-background-100 p-2"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
<div className="mt-0.5">
|
<div className="mt-0.5">
|
||||||
<LinkIcon className="h-3.5 w-3.5" />
|
<LinkIcon className="h-3.5 w-3.5" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h5 className="w-4/5 break-words">{link.title}</h5>
|
<h5 className="w-4/5 break-words">{link.title}</h5>
|
||||||
<p className="mt-0.5 text-brand-secondary">
|
<p className="mt-0.5 text-custom-text-200">
|
||||||
Added {timeAgo(link.created_at)}
|
Added {timeAgo(link.created_at)}
|
||||||
<br />
|
<br />
|
||||||
by{" "}
|
by{" "}
|
||||||
|
@ -119,9 +119,9 @@ const ProgressChart: React.FC<Props> = ({ distribution, startDate, endDate, tota
|
|||||||
gridXValues={chartData.map((item, index) => (index % 2 === 0 ? item.currentDate : ""))}
|
gridXValues={chartData.map((item, index) => (index % 2 === 0 ? item.currentDate : ""))}
|
||||||
enableSlices="x"
|
enableSlices="x"
|
||||||
sliceTooltip={(datum) => (
|
sliceTooltip={(datum) => (
|
||||||
<div className="rounded-md border border-brand-base bg-brand-surface-2 p-2 text-xs">
|
<div className="rounded-md border border-custom-border-100 bg-custom-background-80 p-2 text-xs">
|
||||||
{datum.slice.points[0].data.yFormatted}
|
{datum.slice.points[0].data.yFormatted}
|
||||||
<span className="text-brand-secondary"> issues pending on </span>
|
<span className="text-custom-text-200"> issues pending on </span>
|
||||||
{datum.slice.points[0].data.xFormatted}
|
{datum.slice.points[0].data.xFormatted}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -80,16 +80,16 @@ export const SidebarProgressStats: React.FC<Props> = ({
|
|||||||
<Tab.List
|
<Tab.List
|
||||||
as="div"
|
as="div"
|
||||||
className={`flex w-full items-center gap-2 justify-between rounded-md ${
|
className={`flex w-full items-center gap-2 justify-between rounded-md ${
|
||||||
noBackground ? "" : "bg-brand-surface-1"
|
noBackground ? "" : "bg-custom-background-90"
|
||||||
} px-1 py-1.5
|
} px-1 py-1.5
|
||||||
${module ? "text-xs" : "text-sm"} `}
|
${module ? "text-xs" : "text-sm"} `}
|
||||||
>
|
>
|
||||||
<Tab
|
<Tab
|
||||||
className={({ selected }) =>
|
className={({ selected }) =>
|
||||||
`w-full ${
|
`w-full ${
|
||||||
roundedTab ? "rounded-3xl border border-brand-base" : "rounded"
|
roundedTab ? "rounded-3xl border border-custom-border-100" : "rounded"
|
||||||
} px-3 py-1 text-brand-base ${
|
} px-3 py-1 text-custom-text-100 ${
|
||||||
selected ? " bg-brand-accent text-white" : " hover:bg-brand-surface-2"
|
selected ? " bg-custom-primary text-white" : " hover:bg-custom-background-80"
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -98,9 +98,9 @@ export const SidebarProgressStats: React.FC<Props> = ({
|
|||||||
<Tab
|
<Tab
|
||||||
className={({ selected }) =>
|
className={({ selected }) =>
|
||||||
`w-full ${
|
`w-full ${
|
||||||
roundedTab ? "rounded-3xl border border-brand-base" : "rounded"
|
roundedTab ? "rounded-3xl border border-custom-border-100" : "rounded"
|
||||||
} px-3 py-1 text-brand-base ${
|
} px-3 py-1 text-custom-text-100 ${
|
||||||
selected ? " bg-brand-accent text-white" : " hover:bg-brand-surface-2"
|
selected ? " bg-custom-primary text-white" : " hover:bg-custom-background-80"
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -109,16 +109,16 @@ export const SidebarProgressStats: React.FC<Props> = ({
|
|||||||
<Tab
|
<Tab
|
||||||
className={({ selected }) =>
|
className={({ selected }) =>
|
||||||
`w-full ${
|
`w-full ${
|
||||||
roundedTab ? "rounded-3xl border border-brand-base" : "rounded"
|
roundedTab ? "rounded-3xl border border-custom-border-100" : "rounded"
|
||||||
} px-3 py-1 text-brand-base ${
|
} px-3 py-1 text-custom-text-100 ${
|
||||||
selected ? " bg-brand-accent text-white" : " hover:bg-brand-surface-2"
|
selected ? " bg-custom-primary text-white" : " hover:bg-custom-background-80"
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
States
|
States
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tab.List>
|
</Tab.List>
|
||||||
<Tab.Panels className="flex w-full items-center justify-between pt-1 text-brand-secondary">
|
<Tab.Panels className="flex w-full items-center justify-between pt-1 text-custom-text-200">
|
||||||
<Tab.Panel as="div" className="w-full space-y-1">
|
<Tab.Panel as="div" className="w-full space-y-1">
|
||||||
{distribution.assignees.map((assignee, index) => {
|
{distribution.assignees.map((assignee, index) => {
|
||||||
if (assignee.assignee_id)
|
if (assignee.assignee_id)
|
||||||
@ -159,7 +159,7 @@ export const SidebarProgressStats: React.FC<Props> = ({
|
|||||||
key={`unassigned-${index}`}
|
key={`unassigned-${index}`}
|
||||||
title={
|
title={
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="h-5 w-5 rounded-full border-2 border-brand-base bg-brand-surface-2">
|
<div className="h-5 w-5 rounded-full border-2 border-custom-border-100 bg-custom-background-80">
|
||||||
<img
|
<img
|
||||||
src="/user.png"
|
src="/user.png"
|
||||||
height="100%"
|
height="100%"
|
||||||
|
@ -19,8 +19,8 @@ export const SingleProgressStats: React.FC<TSingleProgressStatsProps> = ({
|
|||||||
}) => (
|
}) => (
|
||||||
<div
|
<div
|
||||||
className={`flex w-full items-center gap-4 justify-between rounded-sm p-1 text-xs ${
|
className={`flex w-full items-center gap-4 justify-between rounded-sm p-1 text-xs ${
|
||||||
onClick ? "cursor-pointer hover:bg-brand-surface-1" : ""
|
onClick ? "cursor-pointer hover:bg-custom-background-90" : ""
|
||||||
} ${selected ? "bg-brand-surface-1" : ""}`}
|
} ${selected ? "bg-custom-background-90" : ""}`}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
<div className="w-1/2">{title}</div>
|
<div className="w-1/2">{title}</div>
|
||||||
|
@ -179,12 +179,12 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="relative group grid auto-rows-[minmax(44px,1fr)] hover:rounded-sm hover:bg-brand-surface-2 border-b border-brand-base w-full min-w-max"
|
className="relative group grid auto-rows-[minmax(44px,1fr)] hover:rounded-sm hover:bg-custom-background-80 border-b border-custom-border-100 w-full min-w-max"
|
||||||
style={{ gridTemplateColumns }}
|
style={{ gridTemplateColumns }}
|
||||||
>
|
>
|
||||||
<div className="flex gap-1.5 items-center px-4 sticky z-[1] left-0 text-brand-secondary bg-brand-base group-hover:text-brand-base group-hover:bg-brand-surface-2 border-brand-base w-full">
|
<div className="flex gap-1.5 items-center px-4 sticky z-[1] left-0 text-custom-text-200 bg-custom-background-100 group-hover:text-custom-text-100 group-hover:bg-custom-background-80 border-custom-border-100 w-full">
|
||||||
<div className="flex gap-1.5 items-center" style={issue.parent ? { paddingLeft } : {}}>
|
<div className="flex gap-1.5 items-center" style={issue.parent ? { paddingLeft } : {}}>
|
||||||
<div className="relative flex items-center cursor-pointer text-xs text-center hover:text-brand-base w-14">
|
<div className="relative flex items-center cursor-pointer text-xs text-center hover:text-custom-text-100 w-14">
|
||||||
{properties.key && (
|
{properties.key && (
|
||||||
<span className="flex items-center justify-center opacity-100 group-hover:opacity-0">
|
<span className="flex items-center justify-center opacity-100 group-hover:opacity-0">
|
||||||
{issue.project_detail?.identifier}-{issue.sequence_id}
|
{issue.project_detail?.identifier}-{issue.sequence_id}
|
||||||
@ -198,11 +198,11 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
onInteraction={(nextOpenState) => setIsOpen(nextOpenState)}
|
onInteraction={(nextOpenState) => setIsOpen(nextOpenState)}
|
||||||
content={
|
content={
|
||||||
<div
|
<div
|
||||||
className={`flex flex-col gap-1.5 overflow-y-scroll whitespace-nowrap rounded-md border p-1 text-xs shadow-lg focus:outline-none max-h-44 min-w-full border-brand-base bg-brand-surface-1`}
|
className={`flex flex-col gap-1.5 overflow-y-scroll whitespace-nowrap rounded-md border p-1 text-xs shadow-lg focus:outline-none max-h-44 min-w-full border-custom-border-100 bg-custom-background-90`}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="hover:text-brand-muted-1 w-full select-none gap-2 truncate rounded px-1 py-1.5 text-left text-brand-secondary hover:bg-brand-surface-2"
|
className="hover:text-custom-text-200 w-full select-none gap-2 truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleEditIssue(issue);
|
handleEditIssue(issue);
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
@ -216,7 +216,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="hover:text-brand-muted-1 w-full select-none gap-2 truncate rounded px-1 py-1.5 text-left text-brand-secondary hover:bg-brand-surface-2"
|
className="hover:text-custom-text-200 w-full select-none gap-2 truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleDeleteIssue(issue);
|
handleDeleteIssue(issue);
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
@ -230,7 +230,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="hover:text-brand-muted-1 w-full select-none gap-2 truncate rounded px-1 py-1.5 text-left text-brand-secondary hover:bg-brand-surface-2"
|
className="hover:text-custom-text-200 w-full select-none gap-2 truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleCopyText();
|
handleCopyText();
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
@ -245,7 +245,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
placement="bottom-start"
|
placement="bottom-start"
|
||||||
>
|
>
|
||||||
<EllipsisHorizontalIcon className="h-5 w-5 text-brand-secondary" />
|
<EllipsisHorizontalIcon className="h-5 w-5 text-custom-text-200" />
|
||||||
</Popover2>
|
</Popover2>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -254,7 +254,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
{issue.sub_issues_count > 0 && (
|
{issue.sub_issues_count > 0 && (
|
||||||
<div className="h-6 w-6 flex justify-center items-center">
|
<div className="h-6 w-6 flex justify-center items-center">
|
||||||
<button
|
<button
|
||||||
className="h-5 w-5 hover:bg-brand-surface-1 hover:text-brand-base rounded-sm cursor-pointer"
|
className="h-5 w-5 hover:bg-custom-background-90 hover:text-custom-text-100 rounded-sm cursor-pointer"
|
||||||
onClick={() => handleToggleExpand(issue.id)}
|
onClick={() => handleToggleExpand(issue.id)}
|
||||||
>
|
>
|
||||||
<Icon iconName="chevron_right" className={`${expanded ? "rotate-90" : ""}`} />
|
<Icon iconName="chevron_right" className={`${expanded ? "rotate-90" : ""}`} />
|
||||||
@ -264,13 +264,13 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Link href={`/${workspaceSlug}/projects/${issue?.project_detail?.id}/issues/${issue.id}`}>
|
<Link href={`/${workspaceSlug}/projects/${issue?.project_detail?.id}/issues/${issue.id}`}>
|
||||||
<a className="truncate text-brand-base cursor-pointer w-full text-[0.825rem]">
|
<a className="truncate text-custom-text-100 cursor-pointer w-full text-[0.825rem]">
|
||||||
{issue.name}
|
{issue.name}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
{properties.state && (
|
{properties.state && (
|
||||||
<div className="flex items-center text-xs text-brand-secondary text-center p-2 group-hover:bg-brand-surface-2 border-brand-base">
|
<div className="flex items-center text-xs text-custom-text-200 text-center p-2 group-hover:bg-custom-background-80 border-custom-border-100">
|
||||||
<ViewStateSelect
|
<ViewStateSelect
|
||||||
issue={issue}
|
issue={issue}
|
||||||
partialUpdateIssue={partialUpdateIssue}
|
partialUpdateIssue={partialUpdateIssue}
|
||||||
@ -284,7 +284,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{properties.priority && (
|
{properties.priority && (
|
||||||
<div className="flex items-center text-xs text-brand-secondary text-center p-2 group-hover:bg-brand-surface-2 border-brand-base">
|
<div className="flex items-center text-xs text-custom-text-200 text-center p-2 group-hover:bg-custom-background-80 border-custom-border-100">
|
||||||
<ViewPrioritySelect
|
<ViewPrioritySelect
|
||||||
issue={issue}
|
issue={issue}
|
||||||
partialUpdateIssue={partialUpdateIssue}
|
partialUpdateIssue={partialUpdateIssue}
|
||||||
@ -297,7 +297,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{properties.assignee && (
|
{properties.assignee && (
|
||||||
<div className="flex items-center text-xs text-brand-secondary text-center p-2 group-hover:bg-brand-surface-2 border-brand-base">
|
<div className="flex items-center text-xs text-custom-text-200 text-center p-2 group-hover:bg-custom-background-80 border-custom-border-100">
|
||||||
<ViewAssigneeSelect
|
<ViewAssigneeSelect
|
||||||
issue={issue}
|
issue={issue}
|
||||||
partialUpdateIssue={partialUpdateIssue}
|
partialUpdateIssue={partialUpdateIssue}
|
||||||
@ -310,7 +310,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{properties.labels && (
|
{properties.labels && (
|
||||||
<div className="flex items-center text-xs text-brand-secondary text-center p-2 group-hover:bg-brand-surface-2 border-brand-base">
|
<div className="flex items-center text-xs text-custom-text-200 text-center p-2 group-hover:bg-custom-background-80 border-custom-border-100">
|
||||||
<ViewLabelSelect
|
<ViewLabelSelect
|
||||||
issue={issue}
|
issue={issue}
|
||||||
partialUpdateIssue={partialUpdateIssue}
|
partialUpdateIssue={partialUpdateIssue}
|
||||||
@ -324,7 +324,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{properties.due_date && (
|
{properties.due_date && (
|
||||||
<div className="flex items-center text-xs text-brand-secondary text-center p-2 group-hover:bg-brand-surface-2 border-brand-base">
|
<div className="flex items-center text-xs text-custom-text-200 text-center p-2 group-hover:bg-custom-background-80 border-custom-border-100">
|
||||||
<ViewDueDateSelect
|
<ViewDueDateSelect
|
||||||
issue={issue}
|
issue={issue}
|
||||||
partialUpdateIssue={partialUpdateIssue}
|
partialUpdateIssue={partialUpdateIssue}
|
||||||
@ -336,7 +336,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{properties.estimate && (
|
{properties.estimate && (
|
||||||
<div className="flex items-center text-xs text-brand-secondary text-center p-2 group-hover:bg-brand-surface-2 border-brand-base">
|
<div className="flex items-center text-xs text-custom-text-200 text-center p-2 group-hover:bg-custom-background-80 border-custom-border-100">
|
||||||
<ViewEstimateSelect
|
<ViewEstimateSelect
|
||||||
issue={issue}
|
issue={issue}
|
||||||
partialUpdateIssue={partialUpdateIssue}
|
partialUpdateIssue={partialUpdateIssue}
|
||||||
|
@ -39,13 +39,15 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
if (col.isActive) {
|
if (col.isActive) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`bg-brand-surface-1 w-full ${
|
className={`bg-custom-background-90 w-full ${
|
||||||
col.propertyName === "title" ? "sticky left-0 z-20 bg-brand-surface-1 pl-24" : ""
|
col.propertyName === "title"
|
||||||
|
? "sticky left-0 z-20 bg-custom-background-90 pl-24"
|
||||||
|
: ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{col.propertyName === "title" ? (
|
{col.propertyName === "title" ? (
|
||||||
<div
|
<div
|
||||||
className={`flex items-center justify-start gap-1.5 cursor-default text-sm text-brand-secondary text-current w-full py-2.5 px-2`}
|
className={`flex items-center justify-start gap-1.5 cursor-default text-sm text-custom-text-200 text-current w-full py-2.5 px-2`}
|
||||||
>
|
>
|
||||||
{col.colName}
|
{col.colName}
|
||||||
</div>
|
</div>
|
||||||
@ -54,22 +56,22 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
className="!w-full"
|
className="!w-full"
|
||||||
customButton={
|
customButton={
|
||||||
<div
|
<div
|
||||||
className={`relative group flex items-center justify-start gap-1.5 cursor-pointer text-sm text-brand-secondary text-current hover:text-brand-base w-full py-3 px-2 ${
|
className={`relative group flex items-center justify-start gap-1.5 cursor-pointer text-sm text-custom-text-200 text-current hover:text-custom-text-100 w-full py-3 px-2 ${
|
||||||
activeSortingProperty === col.propertyName ? "bg-brand-surface-2" : ""
|
activeSortingProperty === col.propertyName ? "bg-custom-background-80" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{activeSortingProperty === col.propertyName && (
|
{activeSortingProperty === col.propertyName && (
|
||||||
<div className="absolute top-1 right-1.5">
|
<div className="absolute top-1 right-1.5">
|
||||||
<Icon
|
<Icon
|
||||||
iconName="filter_list"
|
iconName="filter_list"
|
||||||
className="flex items-center justify-center h-3.5 w-3.5 rounded-full bg-brand-accent text-xs text-white"
|
className="flex items-center justify-center h-3.5 w-3.5 rounded-full bg-custom-primary text-xs text-white"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{col.icon ? (
|
{col.icon ? (
|
||||||
<col.icon
|
<col.icon
|
||||||
className={`text-brand-secondary group-hover:text-brand-base ${
|
className={`text-custom-text-200 group-hover:text-custom-text-100 ${
|
||||||
col.propertyName === "estimate" ? "-rotate-90" : ""
|
col.propertyName === "estimate" ? "-rotate-90" : ""
|
||||||
}`}
|
}`}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
@ -77,7 +79,7 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
width="14"
|
width="14"
|
||||||
/>
|
/>
|
||||||
) : col.propertyName === "priority" ? (
|
) : col.propertyName === "priority" ? (
|
||||||
<span className="text-sm material-symbols-rounded text-brand-secondary">
|
<span className="text-sm material-symbols-rounded text-custom-text-200">
|
||||||
signal_cellular_alt
|
signal_cellular_alt
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
@ -94,7 +96,7 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
className={`${
|
className={`${
|
||||||
selectedMenuItem === `${col.ascendingOrder}_${col.propertyName}`
|
selectedMenuItem === `${col.ascendingOrder}_${col.propertyName}`
|
||||||
? "bg-brand-surface-2"
|
? "bg-custom-background-80"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
key={col.propertyName}
|
key={col.propertyName}
|
||||||
@ -105,8 +107,8 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
<div
|
<div
|
||||||
className={`group flex gap-1.5 px-1 items-center justify-between ${
|
className={`group flex gap-1.5 px-1 items-center justify-between ${
|
||||||
selectedMenuItem === `${col.ascendingOrder}_${col.propertyName}`
|
selectedMenuItem === `${col.ascendingOrder}_${col.propertyName}`
|
||||||
? "text-brand-base"
|
? "text-custom-text-100"
|
||||||
: "text-brand-secondary hover:text-brand-base"
|
: "text-custom-text-200 hover:text-custom-text-100"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex gap-2 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
@ -166,7 +168,7 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
className={`mt-0.5 ${
|
className={`mt-0.5 ${
|
||||||
selectedMenuItem === `${col.descendingOrder}_${col.propertyName}`
|
selectedMenuItem === `${col.descendingOrder}_${col.propertyName}`
|
||||||
? "bg-brand-surface-2"
|
? "bg-custom-background-80"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
key={col.property}
|
key={col.property}
|
||||||
@ -177,8 +179,8 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
<div
|
<div
|
||||||
className={`group flex gap-1.5 px-1 items-center justify-between ${
|
className={`group flex gap-1.5 px-1 items-center justify-between ${
|
||||||
selectedMenuItem === `${col.descendingOrder}_${col.propertyName}`
|
selectedMenuItem === `${col.descendingOrder}_${col.propertyName}`
|
||||||
? "text-brand-base"
|
? "text-custom-text-100"
|
||||||
: "text-brand-secondary hover:text-brand-base"
|
: "text-custom-text-200 hover:text-custom-text-100"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex gap-2 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
@ -249,7 +251,7 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
|||||||
<CustomMenu.MenuItem
|
<CustomMenu.MenuItem
|
||||||
className={`mt-0.5${
|
className={`mt-0.5${
|
||||||
selectedMenuItem === `-created_at_${col.propertyName}`
|
selectedMenuItem === `-created_at_${col.propertyName}`
|
||||||
? "bg-brand-surface-2"
|
? "bg-custom-background-80"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
key={col.property}
|
key={col.property}
|
||||||
|
@ -61,12 +61,12 @@ export const SpreadsheetView: React.FC<Props> = ({
|
|||||||
.join(" ");
|
.join(" ");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full rounded-lg text-brand-secondary overflow-x-auto whitespace-nowrap bg-brand-base">
|
<div className="h-full rounded-lg text-custom-text-200 overflow-x-auto whitespace-nowrap bg-custom-background-100">
|
||||||
<div className="sticky z-[2] top-0 border-b border-brand-base bg-brand-surface-1 w-full min-w-max">
|
<div className="sticky z-[2] top-0 border-b border-custom-border-100 bg-custom-background-90 w-full min-w-max">
|
||||||
<SpreadsheetColumns columnData={columnData} gridTemplateColumns={gridTemplateColumns} />
|
<SpreadsheetColumns columnData={columnData} gridTemplateColumns={gridTemplateColumns} />
|
||||||
</div>
|
</div>
|
||||||
{spreadsheetIssues ? (
|
{spreadsheetIssues ? (
|
||||||
<div className="flex flex-col h-full w-full bg-brand-base rounded-sm ">
|
<div className="flex flex-col h-full w-full bg-custom-background-100 rounded-sm ">
|
||||||
{spreadsheetIssues.map((issue: IIssue, index) => (
|
{spreadsheetIssues.map((issue: IIssue, index) => (
|
||||||
<SpreadsheetIssues
|
<SpreadsheetIssues
|
||||||
key={`${issue.id}_${index}`}
|
key={`${issue.id}_${index}`}
|
||||||
@ -84,12 +84,12 @@ export const SpreadsheetView: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<div
|
<div
|
||||||
className="relative group grid auto-rows-[minmax(44px,1fr)] hover:rounded-sm hover:bg-brand-surface-2 border-b border-brand-base w-full min-w-max"
|
className="relative group grid auto-rows-[minmax(44px,1fr)] hover:rounded-sm hover:bg-custom-background-80 border-b border-custom-border-100 w-full min-w-max"
|
||||||
style={{ gridTemplateColumns }}
|
style={{ gridTemplateColumns }}
|
||||||
>
|
>
|
||||||
{type === "issue" ? (
|
{type === "issue" ? (
|
||||||
<button
|
<button
|
||||||
className="flex gap-1.5 items-center pl-7 py-2.5 text-sm sticky left-0 z-[1] text-brand-secondary bg-brand-base group-hover:text-brand-base group-hover:bg-brand-surface-2 border-brand-base w-full"
|
className="flex gap-1.5 items-center pl-7 py-2.5 text-sm sticky left-0 z-[1] text-custom-text-200 bg-custom-background-100 group-hover:text-custom-text-100 group-hover:bg-custom-background-80 border-custom-border-100 w-full"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const e = new KeyboardEvent("keydown", { key: "c" });
|
const e = new KeyboardEvent("keydown", { key: "c" });
|
||||||
document.dispatchEvent(e);
|
document.dispatchEvent(e);
|
||||||
@ -104,7 +104,7 @@ export const SpreadsheetView: React.FC<Props> = ({
|
|||||||
className="sticky left-0 z-[1]"
|
className="sticky left-0 z-[1]"
|
||||||
customButton={
|
customButton={
|
||||||
<button
|
<button
|
||||||
className="flex gap-1.5 items-center pl-7 py-2.5 text-sm sticky left-0 z-[1] text-brand-secondary bg-brand-base group-hover:text-brand-base group-hover:bg-brand-surface-2 border-brand-base w-full"
|
className="flex gap-1.5 items-center pl-7 py-2.5 text-sm sticky left-0 z-[1] text-custom-text-200 bg-custom-background-100 group-hover:text-custom-text-100 group-hover:bg-custom-background-80 border-custom-border-100 w-full"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<PlusIcon className="h-4 w-4" />
|
<PlusIcon className="h-4 w-4" />
|
||||||
|
@ -16,9 +16,11 @@ import { Popover, Transition } from "@headlessui/react";
|
|||||||
import { Input } from "components/ui";
|
import { Input } from "components/ui";
|
||||||
// icons
|
// icons
|
||||||
import { ColorPickerIcon } from "components/icons";
|
import { ColorPickerIcon } from "components/icons";
|
||||||
|
// types
|
||||||
|
import { ICustomTheme } from "types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
name: string;
|
name: keyof ICustomTheme;
|
||||||
watch: UseFormWatch<any>;
|
watch: UseFormWatch<any>;
|
||||||
setValue: UseFormSetValue<any>;
|
setValue: UseFormSetValue<any>;
|
||||||
error: FieldError | Merge<FieldError, FieldErrorsImpl<any>> | undefined;
|
error: FieldError | Merge<FieldError, FieldErrorsImpl<any>> | undefined;
|
||||||
@ -31,24 +33,18 @@ export const ColorPickerInput: React.FC<Props> = ({ name, watch, setValue, error
|
|||||||
setValue(name, hex);
|
setValue(name, hex);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getColorText = (colorName: string) => {
|
const getColorText = (colorName: keyof ICustomTheme) => {
|
||||||
switch (colorName) {
|
switch (colorName) {
|
||||||
case "accent":
|
case "background":
|
||||||
return "Accent";
|
|
||||||
case "bgBase":
|
|
||||||
return "Background";
|
return "Background";
|
||||||
case "bgSurface1":
|
case "text":
|
||||||
return "Background surface 1";
|
return "Text";
|
||||||
case "bgSurface2":
|
case "primary":
|
||||||
return "Background surface 2";
|
return "Primary(Theme)";
|
||||||
case "border":
|
case "sidebarBackground":
|
||||||
return "Border";
|
return "Sidebar Background";
|
||||||
case "sidebar":
|
case "sidebarText":
|
||||||
return "Sidebar";
|
return "Sidebar Text";
|
||||||
case "textBase":
|
|
||||||
return "Text primary";
|
|
||||||
case "textSecondary":
|
|
||||||
return "Text secondary";
|
|
||||||
default:
|
default:
|
||||||
return "Color";
|
return "Color";
|
||||||
}
|
}
|
||||||
@ -80,12 +76,12 @@ export const ColorPickerInput: React.FC<Props> = ({ name, watch, setValue, error
|
|||||||
<Popover.Button
|
<Popover.Button
|
||||||
type="button"
|
type="button"
|
||||||
className={`group inline-flex items-center outline-none ${
|
className={`group inline-flex items-center outline-none ${
|
||||||
open ? "text-brand-base" : "text-brand-secondary"
|
open ? "text-custom-text-100" : "text-custom-text-200"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{watch(name) && watch(name) !== "" ? (
|
{watch(name) && watch(name) !== "" ? (
|
||||||
<span
|
<span
|
||||||
className="h-4 w-4 rounded border border-brand-base"
|
className="h-4 w-4 rounded border border-custom-border-100"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: `${watch(name)}`,
|
backgroundColor: `${watch(name)}`,
|
||||||
}}
|
}}
|
||||||
@ -94,7 +90,7 @@ export const ColorPickerInput: React.FC<Props> = ({ name, watch, setValue, error
|
|||||||
<ColorPickerIcon
|
<ColorPickerIcon
|
||||||
height={14}
|
height={14}
|
||||||
width={14}
|
width={14}
|
||||||
className="fill-current text-brand-base"
|
className="fill-current text-custom-text-100"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Popover.Button>
|
</Popover.Button>
|
167
apps/app/components/core/theme/custom-theme-selector.tsx
Normal file
167
apps/app/components/core/theme/custom-theme-selector.tsx
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
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<ICustomTheme> | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultValues: ICustomTheme = {
|
||||||
|
background: "#fff7f7",
|
||||||
|
text: "#ffc9c9",
|
||||||
|
primary: "#fe5050",
|
||||||
|
sidebarBackground: "#ffffff",
|
||||||
|
sidebarText: "#000000",
|
||||||
|
darkPalette: false,
|
||||||
|
palette: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CustomThemeSelector: React.FC<Props> = ({ preLoadedData }) => {
|
||||||
|
const [darkPalette, setDarkPalette] = useState(false);
|
||||||
|
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
formState: { errors, isSubmitting },
|
||||||
|
handleSubmit,
|
||||||
|
watch,
|
||||||
|
setValue,
|
||||||
|
reset,
|
||||||
|
} = useForm<ICustomTheme>({
|
||||||
|
defaultValues,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { setTheme } = useTheme();
|
||||||
|
const { mutateUser } = useUser();
|
||||||
|
|
||||||
|
const handleFormSubmit = async (formData: ICustomTheme) => {
|
||||||
|
const payload: ICustomTheme = {
|
||||||
|
background: formData.background,
|
||||||
|
text: formData.text,
|
||||||
|
primary: formData.primary,
|
||||||
|
sidebarBackground: formData.sidebarBackground,
|
||||||
|
sidebarText: formData.sidebarText,
|
||||||
|
darkPalette: darkPalette,
|
||||||
|
palette: `${formData.background},${formData.text},${formData.primary},${formData.sidebarBackground},${formData.sidebarText}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
await userService
|
||||||
|
.updateUser({
|
||||||
|
theme: payload,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
mutateUser((prevData) => {
|
||||||
|
if (!prevData) return prevData;
|
||||||
|
|
||||||
|
return { ...prevData, ...res };
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
applyTheme(payload.palette, darkPalette);
|
||||||
|
setTheme("custom");
|
||||||
|
})
|
||||||
|
.catch((err) => console.log(err));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUpdateTheme = async (formData: any) => {
|
||||||
|
await handleFormSubmit({ ...formData, darkPalette });
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
reset({
|
||||||
|
...defaultValues,
|
||||||
|
...preLoadedData,
|
||||||
|
});
|
||||||
|
}, [preLoadedData, reset]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit(handleUpdateTheme)}>
|
||||||
|
<div className="space-y-5">
|
||||||
|
<h3 className="text-lg font-semibold text-custom-text-100">Customize your theme</h3>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-2 md:grid-cols-3">
|
||||||
|
<div className="flex flex-col items-start gap-2">
|
||||||
|
<h3 className="text-left text-sm font-medium text-custom-text-200">
|
||||||
|
Background color
|
||||||
|
</h3>
|
||||||
|
<ColorPickerInput
|
||||||
|
name="background"
|
||||||
|
error={errors.background}
|
||||||
|
watch={watch}
|
||||||
|
setValue={setValue}
|
||||||
|
register={register}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col items-start gap-2">
|
||||||
|
<h3 className="text-left text-sm font-medium text-custom-text-200">Text color</h3>
|
||||||
|
<ColorPickerInput
|
||||||
|
name="text"
|
||||||
|
error={errors.text}
|
||||||
|
watch={watch}
|
||||||
|
setValue={setValue}
|
||||||
|
register={register}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col items-start gap-2">
|
||||||
|
<h3 className="text-left text-sm font-medium text-custom-text-200">
|
||||||
|
Primary(Theme) color
|
||||||
|
</h3>
|
||||||
|
<ColorPickerInput
|
||||||
|
name="primary"
|
||||||
|
error={errors.primary}
|
||||||
|
watch={watch}
|
||||||
|
setValue={setValue}
|
||||||
|
register={register}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col items-start gap-2">
|
||||||
|
<h3 className="text-left text-sm font-medium text-custom-text-200">
|
||||||
|
Sidebar background color
|
||||||
|
</h3>
|
||||||
|
<ColorPickerInput
|
||||||
|
name="sidebarBackground"
|
||||||
|
error={errors.sidebarBackground}
|
||||||
|
watch={watch}
|
||||||
|
setValue={setValue}
|
||||||
|
register={register}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col items-start gap-2">
|
||||||
|
<h3 className="text-left text-sm font-medium text-custom-text-200">
|
||||||
|
Sidebar text color
|
||||||
|
</h3>
|
||||||
|
<ColorPickerInput
|
||||||
|
name="sidebarText"
|
||||||
|
error={errors.sidebarText}
|
||||||
|
watch={watch}
|
||||||
|
setValue={setValue}
|
||||||
|
register={register}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-5 flex justify-end gap-2">
|
||||||
|
<PrimaryButton type="submit" loading={isSubmitting}>
|
||||||
|
{isSubmitting ? "Creating Theme..." : "Set Theme"}
|
||||||
|
</PrimaryButton>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
3
apps/app/components/core/theme/index.ts
Normal file
3
apps/app/components/core/theme/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from "./color-picker-input";
|
||||||
|
export * from "./custom-theme-selector";
|
||||||
|
export * from "./theme-switch";
|
@ -6,8 +6,6 @@ import { useTheme } from "next-themes";
|
|||||||
import { THEMES_OBJ } from "constants/themes";
|
import { THEMES_OBJ } from "constants/themes";
|
||||||
// ui
|
// ui
|
||||||
import { CustomSelect } from "components/ui";
|
import { CustomSelect } from "components/ui";
|
||||||
// helper
|
|
||||||
import { applyTheme } from "helpers/theme.helper";
|
|
||||||
// types
|
// types
|
||||||
import { ICustomTheme, IUser } from "types";
|
import { ICustomTheme, IUser } from "types";
|
||||||
|
|
||||||
@ -79,19 +77,14 @@ export const ThemeSwitch: React.FC<Props> = ({
|
|||||||
if (!customThemeSelectorOptions) setCustomThemeSelectorOptions(true);
|
if (!customThemeSelectorOptions) setCustomThemeSelectorOptions(true);
|
||||||
} else {
|
} else {
|
||||||
if (customThemeSelectorOptions) setCustomThemeSelectorOptions(false);
|
if (customThemeSelectorOptions) setCustomThemeSelectorOptions(false);
|
||||||
const cssVars = [
|
|
||||||
"--color-bg-base",
|
|
||||||
"--color-bg-surface-1",
|
|
||||||
"--color-bg-surface-2",
|
|
||||||
|
|
||||||
"--color-border",
|
for (let i = 10; i <= 900; i >= 100 ? (i += 100) : (i += 10)) {
|
||||||
"--color-bg-sidebar",
|
document.documentElement.style.removeProperty(`--color-background-${i}`);
|
||||||
"--color-accent",
|
document.documentElement.style.removeProperty(`--color-text-${i}`);
|
||||||
|
document.documentElement.style.removeProperty(`--color-primary-${i}`);
|
||||||
"--color-text-base",
|
document.documentElement.style.removeProperty(`--color-sidebar-background-${i}`);
|
||||||
"--color-text-secondary",
|
document.documentElement.style.removeProperty(`--color-sidebar-text-${i}`);
|
||||||
];
|
}
|
||||||
cssVars.forEach((cssVar) => document.documentElement.style.removeProperty(cssVar));
|
|
||||||
}
|
}
|
||||||
setTheme(value);
|
setTheme(value);
|
||||||
document.documentElement.style.setProperty("color-scheme", type);
|
document.documentElement.style.setProperty("color-scheme", type);
|
@ -110,8 +110,8 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
|
|
||||||
if (!cycle)
|
if (!cycle)
|
||||||
return (
|
return (
|
||||||
<div className="flex w-full items-center justify-start rounded-[10px] bg-brand-surface-2 px-6 py-4">
|
<div className="flex w-full items-center justify-start rounded-[10px] bg-custom-background-80 px-6 py-4">
|
||||||
<h3 className="text-base font-medium text-brand-base ">No active cycle is present.</h3>
|
<h3 className="text-base font-medium text-custom-text-100 ">No active cycle is present.</h3>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -209,8 +209,8 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid-row-2 grid rounded-[10px] shadow divide-y bg-brand-base border border-brand-base">
|
<div className="grid-row-2 grid rounded-[10px] shadow divide-y bg-custom-background-100 border border-custom-border-100">
|
||||||
<div className="grid grid-cols-1 divide-y border-brand-base lg:divide-y-0 lg:divide-x lg:grid-cols-3">
|
<div className="grid grid-cols-1 divide-y border-custom-border-100 lg:divide-y-0 lg:divide-x lg:grid-cols-3">
|
||||||
<div className="flex flex-col text-xs">
|
<div className="flex flex-col text-xs">
|
||||||
<div className="h-full w-full">
|
<div className="h-full w-full">
|
||||||
<div className="flex h-60 flex-col gap-5 justify-between rounded-b-[10px] p-4">
|
<div className="flex h-60 flex-col gap-5 justify-between rounded-b-[10px] p-4">
|
||||||
@ -227,7 +227,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
: cycleStatus === "completed"
|
: cycleStatus === "completed"
|
||||||
? "#3F76FF"
|
? "#3F76FF"
|
||||||
: cycleStatus === "draft"
|
: cycleStatus === "draft"
|
||||||
? "#858E96"
|
? "rgb(var(--color-text-200))"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
@ -300,18 +300,18 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
handleAddToFavorites();
|
handleAddToFavorites();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StarIcon className="h-4 w-4 " color="#858E96" />
|
<StarIcon className="h-4 w-4 " color="rgb(var(--color-text-200))" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center justify-start gap-5 text-brand-secondary">
|
<div className="flex items-center justify-start gap-5 text-custom-text-200">
|
||||||
<div className="flex items-start gap-1">
|
<div className="flex items-start gap-1">
|
||||||
<CalendarDaysIcon className="h-4 w-4" />
|
<CalendarDaysIcon className="h-4 w-4" />
|
||||||
<span>{renderShortDateWithYearFormat(startDate)}</span>
|
<span>{renderShortDateWithYearFormat(startDate)}</span>
|
||||||
</div>
|
</div>
|
||||||
<ArrowRightIcon className="h-4 w-4 text-brand-secondary" />
|
<ArrowRightIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
<div className="flex items-start gap-1">
|
<div className="flex items-start gap-1">
|
||||||
<TargetIcon className="h-4 w-4" />
|
<TargetIcon className="h-4 w-4" />
|
||||||
<span>{renderShortDateWithYearFormat(endDate)}</span>
|
<span>{renderShortDateWithYearFormat(endDate)}</span>
|
||||||
@ -319,7 +319,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<div className="flex items-center gap-2.5 text-brand-secondary">
|
<div className="flex items-center gap-2.5 text-custom-text-200">
|
||||||
{cycle.owned_by.avatar && cycle.owned_by.avatar !== "" ? (
|
{cycle.owned_by.avatar && cycle.owned_by.avatar !== "" ? (
|
||||||
<img
|
<img
|
||||||
src={cycle.owned_by.avatar}
|
src={cycle.owned_by.avatar}
|
||||||
@ -329,21 +329,21 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
alt={cycle.owned_by.first_name}
|
alt={cycle.owned_by.first_name}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span className="bg-brand-secondary flex h-5 w-5 items-center justify-center rounded-full bg-brand-base capitalize">
|
<span className="flex h-5 w-5 items-center justify-center rounded-full bg-custom-background-100 capitalize">
|
||||||
{cycle.owned_by.first_name.charAt(0)}
|
{cycle.owned_by.first_name.charAt(0)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<span className="text-brand-secondary">{cycle.owned_by.first_name}</span>
|
<span className="text-custom-text-200">{cycle.owned_by.first_name}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{cycle.assignees.length > 0 && (
|
{cycle.assignees.length > 0 && (
|
||||||
<div className="flex items-center gap-1 text-brand-secondary">
|
<div className="flex items-center gap-1 text-custom-text-200">
|
||||||
<AssigneesList users={cycle.assignees} length={4} />
|
<AssigneesList users={cycle.assignees} length={4} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-4 text-brand-secondary">
|
<div className="flex items-center gap-4 text-custom-text-200">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<LayerDiagonalIcon className="h-4 w-4 flex-shrink-0" />
|
<LayerDiagonalIcon className="h-4 w-4 flex-shrink-0" />
|
||||||
{cycle.total_issues} issues
|
{cycle.total_issues} issues
|
||||||
@ -355,16 +355,16 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Link href={`/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`}>
|
<Link href={`/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`}>
|
||||||
<a className="bg-brand-accent text-white px-4 rounded-md py-2 text-center text-sm font-medium w-full hover:bg-brand-accent/90">
|
<a className="bg-custom-primary text-white px-4 rounded-md py-2 text-center text-sm font-medium w-full hover:bg-custom-primary/90">
|
||||||
View Cycle
|
View Cycle
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid col-span-2 grid-cols-1 divide-y border-brand-base md:divide-y-0 md:divide-x md:grid-cols-2">
|
<div className="grid col-span-2 grid-cols-1 divide-y border-custom-border-100 md:divide-y-0 md:divide-x md:grid-cols-2">
|
||||||
<div className="flex h-60 flex-col border-brand-base">
|
<div className="flex h-60 flex-col border-custom-border-100">
|
||||||
<div className="flex h-full w-full flex-col text-brand-secondary p-4">
|
<div className="flex h-full w-full flex-col text-custom-text-200 p-4">
|
||||||
<div className="flex w-full items-center gap-2 py-1">
|
<div className="flex w-full items-center gap-2 py-1">
|
||||||
<span>Progress</span>
|
<span>Progress</span>
|
||||||
<LinearProgressIndicator data={progressIndicatorData} />
|
<LinearProgressIndicator data={progressIndicatorData} />
|
||||||
@ -391,22 +391,22 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="border-brand-base h-60 overflow-y-scroll">
|
<div className="border-custom-border-100 h-60 overflow-y-scroll">
|
||||||
<ActiveCycleProgressStats cycle={cycle} />
|
<ActiveCycleProgressStats cycle={cycle} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 divide-y border-brand-base lg:divide-y-0 lg:divide-x lg:grid-cols-2">
|
<div className="grid grid-cols-1 divide-y border-custom-border-100 lg:divide-y-0 lg:divide-x lg:grid-cols-2">
|
||||||
<div className="flex flex-col justify-between p-4">
|
<div className="flex flex-col justify-between p-4">
|
||||||
<div>
|
<div>
|
||||||
<div className="text-brand-primary">High Priority Issues</div>
|
<div className="text-custom-primary">High Priority Issues</div>
|
||||||
<div className="my-3 flex max-h-[240px] min-h-[240px] flex-col gap-2.5 overflow-y-scroll rounded-md">
|
<div className="my-3 flex max-h-[240px] min-h-[240px] flex-col gap-2.5 overflow-y-scroll rounded-md">
|
||||||
{issues ? (
|
{issues ? (
|
||||||
issues.length > 0 ? (
|
issues.length > 0 ? (
|
||||||
issues.map((issue) => (
|
issues.map((issue) => (
|
||||||
<div
|
<div
|
||||||
key={issue.id}
|
key={issue.id}
|
||||||
className="flex flex-wrap rounded-md items-center justify-between gap-2 border border-brand-base bg-brand-surface-1 px-3 py-1.5"
|
className="flex flex-wrap rounded-md items-center justify-between gap-2 border border-custom-border-100 bg-custom-background-90 px-3 py-1.5"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<div>
|
<div>
|
||||||
@ -414,7 +414,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
tooltipHeading="Issue ID"
|
tooltipHeading="Issue ID"
|
||||||
tooltipContent={`${issue.project_detail?.identifier}-${issue.sequence_id}`}
|
tooltipContent={`${issue.project_detail?.identifier}-${issue.sequence_id}`}
|
||||||
>
|
>
|
||||||
<span className="flex-shrink-0 text-xs text-brand-secondary">
|
<span className="flex-shrink-0 text-xs text-custom-text-200">
|
||||||
{issue.project_detail?.identifier}-{issue.sequence_id}
|
{issue.project_detail?.identifier}-{issue.sequence_id}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -424,7 +424,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
tooltipHeading="Title"
|
tooltipHeading="Title"
|
||||||
tooltipContent={issue.name}
|
tooltipContent={issue.name}
|
||||||
>
|
>
|
||||||
<span className="text-[0.825rem] text-brand-base">
|
<span className="text-[0.825rem] text-custom-text-100">
|
||||||
{truncateText(issue.name, 30)}
|
{truncateText(issue.name, 30)}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -444,7 +444,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
{issue.label_details.map((label) => (
|
{issue.label_details.map((label) => (
|
||||||
<span
|
<span
|
||||||
key={label.id}
|
key={label.id}
|
||||||
className="group flex items-center gap-1 rounded-2xl border border-brand-base px-2 py-0.5 text-xs text-brand-secondary"
|
className="group flex items-center gap-1 rounded-2xl border border-custom-border-100 px-2 py-0.5 text-xs text-custom-text-200"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="h-1.5 w-1.5 rounded-full"
|
className="h-1.5 w-1.5 rounded-full"
|
||||||
@ -460,7 +460,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
) : (
|
) : (
|
||||||
""
|
""
|
||||||
)}
|
)}
|
||||||
<div className={`flex items-center gap-2 text-brand-secondary`}>
|
<div className={`flex items-center gap-2 text-custom-text-200`}>
|
||||||
{issue.assignees &&
|
{issue.assignees &&
|
||||||
issue.assignees.length > 0 &&
|
issue.assignees.length > 0 &&
|
||||||
Array.isArray(issue.assignees) ? (
|
Array.isArray(issue.assignees) ? (
|
||||||
@ -479,7 +479,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<div className="grid place-items-center text-brand-secondary text-sm text-center">
|
<div className="grid place-items-center text-custom-text-200 text-sm text-center">
|
||||||
No issues present in the cycle.
|
No issues present in the cycle.
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -495,7 +495,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
|
|
||||||
{issues && issues.length > 0 && (
|
{issues && issues.length > 0 && (
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<div className="h-1 w-full rounded-full bg-brand-surface-2">
|
<div className="h-1 w-full rounded-full bg-custom-background-80">
|
||||||
<div
|
<div
|
||||||
className="h-1 rounded-full bg-green-600"
|
className="h-1 rounded-full bg-green-600"
|
||||||
style={{
|
style={{
|
||||||
@ -510,16 +510,16 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-16 text-end text-xs text-brand-secondary">
|
<div className="w-16 text-end text-xs text-custom-text-200">
|
||||||
{issues?.filter((issue) => issue?.state_detail?.group === "completed")?.length} of{" "}
|
{issues?.filter((issue) => issue?.state_detail?.group === "completed")?.length} of{" "}
|
||||||
{issues?.length}
|
{issues?.length}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col justify-between border-brand-base p-4">
|
<div className="flex flex-col justify-between border-custom-border-100 p-4">
|
||||||
<div className="flex items-start justify-between gap-4 py-1.5 text-xs">
|
<div className="flex items-start justify-between gap-4 py-1.5 text-xs">
|
||||||
<div className="flex items-center gap-3 text-brand-base">
|
<div className="flex items-center gap-3 text-custom-text-100">
|
||||||
<div className="flex items-center justify-center gap-1">
|
<div className="flex items-center justify-center gap-1">
|
||||||
<span className="h-2.5 w-2.5 rounded-full bg-[#a9bbd0]" />
|
<span className="h-2.5 w-2.5 rounded-full bg-[#a9bbd0]" />
|
||||||
<span>Ideal</span>
|
<span>Ideal</span>
|
||||||
@ -531,7 +531,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<span>
|
<span>
|
||||||
<LayerDiagonalIcon className="h-5 w-5 flex-shrink-0 text-brand-secondary" />
|
<LayerDiagonalIcon className="h-5 w-5 flex-shrink-0 text-custom-text-200" />
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
Pending Issues -{" "}
|
Pending Issues -{" "}
|
||||||
|
@ -48,12 +48,12 @@ export const ActiveCycleProgressStats: React.FC<Props> = ({ cycle }) => {
|
|||||||
>
|
>
|
||||||
<Tab.List
|
<Tab.List
|
||||||
as="div"
|
as="div"
|
||||||
className="flex sticky top-0 z-10 bg-brand-base w-full px-4 pt-4 pb-1 flex-wrap items-center justify-start gap-4 text-sm"
|
className="flex sticky top-0 z-10 bg-custom-background-100 w-full px-4 pt-4 pb-1 flex-wrap items-center justify-start gap-4 text-sm"
|
||||||
>
|
>
|
||||||
<Tab
|
<Tab
|
||||||
className={({ selected }) =>
|
className={({ selected }) =>
|
||||||
`px-3 py-1 text-brand-base rounded-3xl border border-brand-base ${
|
`px-3 py-1 text-custom-text-100 rounded-3xl border border-custom-border-100 ${
|
||||||
selected ? " bg-brand-accent text-white" : " hover:bg-brand-surface-2"
|
selected ? " bg-custom-primary text-white" : " hover:bg-custom-background-80"
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -61,8 +61,8 @@ export const ActiveCycleProgressStats: React.FC<Props> = ({ cycle }) => {
|
|||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
className={({ selected }) =>
|
className={({ selected }) =>
|
||||||
`px-3 py-1 text-brand-base rounded-3xl border border-brand-base ${
|
`px-3 py-1 text-custom-text-100 rounded-3xl border border-custom-border-100 ${
|
||||||
selected ? " bg-brand-accent text-white" : " hover:bg-brand-surface-2"
|
selected ? " bg-custom-primary text-white" : " hover:bg-custom-background-80"
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -73,7 +73,7 @@ export const ActiveCycleProgressStats: React.FC<Props> = ({ cycle }) => {
|
|||||||
<Tab.Panels as={Fragment}>
|
<Tab.Panels as={Fragment}>
|
||||||
<Tab.Panel
|
<Tab.Panel
|
||||||
as="div"
|
as="div"
|
||||||
className="w-full gap-1 overflow-y-scroll items-center text-brand-secondary p-4"
|
className="w-full gap-1 overflow-y-scroll items-center text-custom-text-200 p-4"
|
||||||
>
|
>
|
||||||
{cycle.distribution.assignees.map((assignee, index) => {
|
{cycle.distribution.assignees.map((assignee, index) => {
|
||||||
if (assignee.assignee_id)
|
if (assignee.assignee_id)
|
||||||
@ -103,7 +103,7 @@ export const ActiveCycleProgressStats: React.FC<Props> = ({ cycle }) => {
|
|||||||
key={`unassigned-${index}`}
|
key={`unassigned-${index}`}
|
||||||
title={
|
title={
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="h-5 w-5 rounded-full border-2 border-brand-base bg-brand-surface-2">
|
<div className="h-5 w-5 rounded-full border-2 border-custom-border-100 bg-custom-background-80">
|
||||||
<img
|
<img
|
||||||
src="/user.png"
|
src="/user.png"
|
||||||
height="100%"
|
height="100%"
|
||||||
@ -123,7 +123,7 @@ export const ActiveCycleProgressStats: React.FC<Props> = ({ cycle }) => {
|
|||||||
</Tab.Panel>
|
</Tab.Panel>
|
||||||
<Tab.Panel
|
<Tab.Panel
|
||||||
as="div"
|
as="div"
|
||||||
className="w-full gap-1 overflow-y-scroll items-center text-brand-secondary p-4"
|
className="w-full gap-1 overflow-y-scroll items-center text-custom-text-200 p-4"
|
||||||
>
|
>
|
||||||
{cycle.distribution.labels.map((label, index) => (
|
{cycle.distribution.labels.map((label, index) => (
|
||||||
<SingleProgressStats
|
<SingleProgressStats
|
||||||
@ -146,7 +146,7 @@ export const ActiveCycleProgressStats: React.FC<Props> = ({ cycle }) => {
|
|||||||
</Tab.Panel>
|
</Tab.Panel>
|
||||||
</Tab.Panels>
|
</Tab.Panels>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid place-items-center text-brand-secondary text-sm text-center mt-4">
|
<div className="grid place-items-center text-custom-text-200 text-sm text-center mt-4">
|
||||||
No issues present in the cycle.
|
No issues present in the cycle.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -24,7 +24,7 @@ export const CyclesListGanttChartView: FC<Props> = ({ cycles }) => {
|
|||||||
className="rounded-sm flex-shrink-0 w-[10px] h-[10px] flex justify-center items-center"
|
className="rounded-sm flex-shrink-0 w-[10px] h-[10px] flex justify-center items-center"
|
||||||
style={{ backgroundColor: "#858e96" }}
|
style={{ backgroundColor: "#858e96" }}
|
||||||
/>
|
/>
|
||||||
<div className="text-brand-base text-sm">{data?.name}</div>
|
<div className="text-custom-text-100 text-sm">{data?.name}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ export const CyclesListGanttChartView: FC<Props> = ({ cycles }) => {
|
|||||||
<a className="relative flex items-center w-full h-full overflow-hidden shadow-sm">
|
<a className="relative flex items-center w-full h-full overflow-hidden shadow-sm">
|
||||||
<div className="flex-shrink-0 w-[4px] h-full" style={{ backgroundColor: "#858e96" }} />
|
<div className="flex-shrink-0 w-[4px] h-full" style={{ backgroundColor: "#858e96" }} />
|
||||||
<Tooltip tooltipContent={data?.name} className={`z-[999999]`}>
|
<Tooltip tooltipContent={data?.name} className={`z-[999999]`}>
|
||||||
<div className="text-brand-base text-[15px] whitespace-nowrap py-[4px] px-2.5 overflow-hidden w-full">
|
<div className="text-custom-text-100 text-[15px] whitespace-nowrap py-[4px] px-2.5 overflow-hidden w-full">
|
||||||
{data?.name}
|
{data?.name}
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -19,8 +19,10 @@ import {
|
|||||||
} from "components/cycles";
|
} from "components/cycles";
|
||||||
// ui
|
// ui
|
||||||
import { EmptyState, Loader } from "components/ui";
|
import { EmptyState, Loader } from "components/ui";
|
||||||
|
// icons
|
||||||
|
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||||
// images
|
// images
|
||||||
import emptyCycle from "public/empty-state/empty-cycle.svg";
|
import emptyCycle from "public/empty-state/cycle.svg";
|
||||||
// helpers
|
// helpers
|
||||||
import { getDateRangeStatus } from "helpers/date-time.helper";
|
import { getDateRangeStatus } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
@ -171,10 +173,10 @@ export const CyclesView: React.FC<Props> = ({ cycles, viewType }) => {
|
|||||||
{cycles ? (
|
{cycles ? (
|
||||||
cycles.length > 0 ? (
|
cycles.length > 0 ? (
|
||||||
viewType === "list" ? (
|
viewType === "list" ? (
|
||||||
<div className="divide-y divide-brand-base">
|
<div className="divide-y divide-custom-border-100">
|
||||||
{cycles.map((cycle) => (
|
{cycles.map((cycle) => (
|
||||||
<div className="hover:bg-brand-surface-2">
|
<div className="hover:bg-custom-background-80">
|
||||||
<div className="flex flex-col border-brand-base">
|
<div className="flex flex-col border-custom-border-100">
|
||||||
<SingleCycleList
|
<SingleCycleList
|
||||||
key={cycle.id}
|
key={cycle.id}
|
||||||
cycle={cycle}
|
cycle={cycle}
|
||||||
@ -205,10 +207,17 @@ export const CyclesView: React.FC<Props> = ({ cycles, viewType }) => {
|
|||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
<EmptyState
|
<EmptyState
|
||||||
type="cycle"
|
title="Plan your project with cycles"
|
||||||
title="Create New Cycle"
|
description="Cycle is a custom time period in which a team works to complete items on their backlog."
|
||||||
description="Sprint more effectively with Cycles by confining your project to a fixed amount of time. Create new cycle now."
|
image={emptyCycle}
|
||||||
imgURL={emptyCycle}
|
buttonText="New Cycle"
|
||||||
|
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||||
|
onClick={() => {
|
||||||
|
const e = new KeyboardEvent("keydown", {
|
||||||
|
key: "q",
|
||||||
|
});
|
||||||
|
document.dispatchEvent(e);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
) : viewType === "list" ? (
|
) : viewType === "list" ? (
|
||||||
|
@ -110,7 +110,7 @@ export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
|
|||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<div className="fixed inset-0 bg-brand-backdrop bg-opacity-50 transition-opacity" />
|
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
|
|
||||||
<div className="fixed inset-0 z-20 overflow-y-auto">
|
<div className="fixed inset-0 z-20 overflow-y-auto">
|
||||||
@ -124,7 +124,7 @@ export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
|
|||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative transform overflow-hidden rounded-lg border border-brand-base bg-brand-base text-left shadow-xl transition-all sm:my-8 sm:w-[40rem]">
|
<Dialog.Panel className="relative transform overflow-hidden rounded-lg border border-custom-border-100 bg-custom-background-100 text-left shadow-xl transition-all sm:my-8 sm:w-[40rem]">
|
||||||
<div className="px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
<div className="px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||||
<div className="sm:flex sm:items-start">
|
<div className="sm:flex sm:items-start">
|
||||||
<div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-red-500/20 sm:mx-0 sm:h-10 sm:w-10">
|
<div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-red-500/20 sm:mx-0 sm:h-10 sm:w-10">
|
||||||
@ -136,14 +136,14 @@ export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
|
|||||||
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||||
<Dialog.Title
|
<Dialog.Title
|
||||||
as="h3"
|
as="h3"
|
||||||
className="text-lg font-medium leading-6 text-brand-base"
|
className="text-lg font-medium leading-6 text-custom-text-100"
|
||||||
>
|
>
|
||||||
Delete Cycle
|
Delete Cycle
|
||||||
</Dialog.Title>
|
</Dialog.Title>
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<p className="text-sm text-brand-secondary">
|
<p className="text-sm text-custom-text-200">
|
||||||
Are you sure you want to delete cycle-{" "}
|
Are you sure you want to delete cycle-{" "}
|
||||||
<span className="break-words font-medium text-brand-base">
|
<span className="break-words font-medium text-custom-text-100">
|
||||||
{data?.name}
|
{data?.name}
|
||||||
</span>
|
</span>
|
||||||
? All of the data related to the cycle will be permanently removed. This
|
? All of the data related to the cycle will be permanently removed. This
|
||||||
|
@ -51,7 +51,7 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
|
|||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(handleCreateUpdateCycle)}>
|
<form onSubmit={handleSubmit(handleCreateUpdateCycle)}>
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
<h3 className="text-lg font-medium leading-6 text-brand-base">
|
<h3 className="text-lg font-medium leading-6 text-custom-text-100">
|
||||||
{status ? "Update" : "Create"} Cycle
|
{status ? "Update" : "Create"} Cycle
|
||||||
</h3>
|
</h3>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
@ -107,7 +107,7 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="-mx-5 mt-5 flex justify-end gap-2 border-t border-brand-base px-5 pt-5">
|
<div className="-mx-5 mt-5 flex justify-end gap-2 border-t border-custom-border-100 px-5 pt-5">
|
||||||
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
|
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
|
||||||
<PrimaryButton type="submit" loading={isSubmitting}>
|
<PrimaryButton type="submit" loading={isSubmitting}>
|
||||||
{status
|
{status
|
||||||
|
@ -28,7 +28,7 @@ export const CycleIssuesGanttChartView: FC<Props> = ({}) => {
|
|||||||
className="rounded-sm flex-shrink-0 w-[10px] h-[10px] flex justify-center items-center"
|
className="rounded-sm flex-shrink-0 w-[10px] h-[10px] flex justify-center items-center"
|
||||||
style={{ backgroundColor: data?.state_detail?.color || "#858e96" }}
|
style={{ backgroundColor: data?.state_detail?.color || "#858e96" }}
|
||||||
/>
|
/>
|
||||||
<div className="text-brand-base text-sm">{data?.name}</div>
|
<div className="text-custom-text-100 text-sm">{data?.name}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ export const CycleIssuesGanttChartView: FC<Props> = ({}) => {
|
|||||||
style={{ backgroundColor: data?.state_detail?.color || "#858e96" }}
|
style={{ backgroundColor: data?.state_detail?.color || "#858e96" }}
|
||||||
/>
|
/>
|
||||||
<Tooltip tooltipContent={data?.name} className={`z-[999999]`}>
|
<Tooltip tooltipContent={data?.name} className={`z-[999999]`}>
|
||||||
<div className="text-brand-base text-[15px] whitespace-nowrap py-[4px] px-2.5 overflow-hidden w-full">
|
<div className="text-custom-text-100 text-[15px] whitespace-nowrap py-[4px] px-2.5 overflow-hidden w-full">
|
||||||
{data?.name}
|
{data?.name}
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -51,7 +51,7 @@ export const CycleIssuesGanttChartView: FC<Props> = ({}) => {
|
|||||||
className={`z-[999999]`}
|
className={`z-[999999]`}
|
||||||
>
|
>
|
||||||
<div className="flex-shrink-0 mx-2 w-[18px] h-[18px] overflow-hidden flex justify-center items-center">
|
<div className="flex-shrink-0 mx-2 w-[18px] h-[18px] overflow-hidden flex justify-center items-center">
|
||||||
<span className="material-symbols-rounded text-brand-secondary text-[18px]">
|
<span className="material-symbols-rounded text-custom-text-200 text-[18px]">
|
||||||
info
|
info
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -234,7 +234,7 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
|
|||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<div className="fixed inset-0 bg-brand-backdrop bg-opacity-50 transition-opacity" />
|
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
<div className="fixed inset-0 z-20 overflow-y-auto">
|
<div className="fixed inset-0 z-20 overflow-y-auto">
|
||||||
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
|
<div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
|
||||||
@ -247,7 +247,7 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
|
|||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative transform rounded-lg border border-brand-base bg-brand-base px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-100 bg-custom-background-100 px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
||||||
<CycleForm
|
<CycleForm
|
||||||
handleFormSubmit={handleFormSubmit}
|
handleFormSubmit={handleFormSubmit}
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
|
@ -66,9 +66,9 @@ export const CycleSelect: React.FC<IssueCycleSelectProps> = ({
|
|||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<>
|
<>
|
||||||
<Listbox.Button
|
<Listbox.Button
|
||||||
className={`flex cursor-pointer items-center gap-1 rounded-md border border-brand-base px-2 py-1 text-xs shadow-sm duration-300 hover:bg-brand-surface-1 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500`}
|
className={`flex cursor-pointer items-center gap-1 rounded-md border border-custom-border-100 px-2 py-1 text-xs shadow-sm duration-300 hover:bg-custom-background-90 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500`}
|
||||||
>
|
>
|
||||||
<CyclesIcon className="h-3 w-3 text-brand-secondary" />
|
<CyclesIcon className="h-3 w-3 text-custom-text-200" />
|
||||||
<div className="flex items-center gap-2 truncate">
|
<div className="flex items-center gap-2 truncate">
|
||||||
{cycles?.find((c) => c.id === value)?.name ?? "Cycles"}
|
{cycles?.find((c) => c.id === value)?.name ?? "Cycles"}
|
||||||
</div>
|
</div>
|
||||||
@ -82,7 +82,7 @@ export const CycleSelect: React.FC<IssueCycleSelectProps> = ({
|
|||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<Listbox.Options
|
<Listbox.Options
|
||||||
className={`absolute mt-1 max-h-32 min-w-[8rem] overflow-y-auto whitespace-nowrap bg-brand-surface-2 shadow-lg text-xs z-10 rounded-md py-1 ring-1 ring-black ring-opacity-5 focus:outline-none`}
|
className={`absolute mt-1 max-h-32 min-w-[8rem] overflow-y-auto whitespace-nowrap bg-custom-background-80 shadow-lg text-xs z-10 rounded-md py-1 ring-1 ring-black ring-opacity-5 focus:outline-none`}
|
||||||
>
|
>
|
||||||
<div className="py-1">
|
<div className="py-1">
|
||||||
{options ? (
|
{options ? (
|
||||||
@ -100,7 +100,7 @@ export const CycleSelect: React.FC<IssueCycleSelectProps> = ({
|
|||||||
: ""
|
: ""
|
||||||
} ${
|
} ${
|
||||||
active ? "bg-indigo-50" : ""
|
active ? "bg-indigo-50" : ""
|
||||||
} relative cursor-pointer select-none p-2 text-brand-base`
|
} relative cursor-pointer select-none p-2 text-custom-text-100`
|
||||||
}
|
}
|
||||||
value={option.value}
|
value={option.value}
|
||||||
>
|
>
|
||||||
@ -110,14 +110,14 @@ export const CycleSelect: React.FC<IssueCycleSelectProps> = ({
|
|||||||
</Listbox.Option>
|
</Listbox.Option>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<p className="text-center text-sm text-brand-secondary">No options</p>
|
<p className="text-center text-sm text-custom-text-200">No options</p>
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
<p className="text-center text-sm text-brand-secondary">Loading...</p>
|
<p className="text-center text-sm text-custom-text-200">Loading...</p>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="relative w-full flex select-none items-center gap-x-2 p-2 text-gray-400 hover:bg-indigo-50 hover:text-brand-base"
|
className="relative w-full flex select-none items-center gap-x-2 p-2 text-gray-400 hover:bg-indigo-50 hover:text-custom-text-100"
|
||||||
onClick={openCycleModal}
|
onClick={openCycleModal}
|
||||||
>
|
>
|
||||||
<PlusIcon className="h-4 w-4 text-gray-400" aria-hidden="true" />
|
<PlusIcon className="h-4 w-4 text-gray-400" aria-hidden="true" />
|
||||||
|
@ -292,14 +292,14 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
<div
|
<div
|
||||||
className={`fixed top-[66px] ${
|
className={`fixed top-[66px] ${
|
||||||
isOpen ? "right-0" : "-right-[24rem]"
|
isOpen ? "right-0" : "-right-[24rem]"
|
||||||
} h-full w-[24rem] overflow-y-auto border-l border-brand-base bg-brand-sidebar pt-5 pb-10 duration-300`}
|
} h-full w-[24rem] overflow-y-auto border-l border-custom-border-100 bg-custom-sidebar-background-100 pt-5 pb-10 duration-300`}
|
||||||
>
|
>
|
||||||
{cycle ? (
|
{cycle ? (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-col items-start justify-center">
|
<div className="flex flex-col items-start justify-center">
|
||||||
<div className="flex gap-2.5 px-5 text-sm">
|
<div className="flex gap-2.5 px-5 text-sm">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span className="flex items-center rounded border-[0.5px] border-brand-base bg-brand-surface-1 px-2 py-1 text-center text-xs capitalize">
|
<span className="flex items-center rounded border-[0.5px] border-custom-border-100 bg-custom-background-90 px-2 py-1 text-center text-xs capitalize">
|
||||||
{capitalizeFirstLetter(cycleStatus)}
|
{capitalizeFirstLetter(cycleStatus)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -309,8 +309,8 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
<>
|
<>
|
||||||
<Popover.Button
|
<Popover.Button
|
||||||
disabled={isCompleted ?? false}
|
disabled={isCompleted ?? false}
|
||||||
className={`group flex h-full items-center gap-2 whitespace-nowrap rounded border-[0.5px] border-brand-base bg-brand-surface-1 px-2 py-1 text-xs ${
|
className={`group flex h-full items-center gap-2 whitespace-nowrap rounded border-[0.5px] border-custom-border-100 bg-custom-background-90 px-2 py-1 text-xs ${
|
||||||
cycle.start_date ? "" : "text-brand-secondary"
|
cycle.start_date ? "" : "text-custom-text-200"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<CalendarDaysIcon className="h-3 w-3" />
|
<CalendarDaysIcon className="h-3 w-3" />
|
||||||
@ -352,15 +352,15 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
</Popover>
|
</Popover>
|
||||||
<span>
|
<span>
|
||||||
<ArrowLongRightIcon className="h-3 w-3 text-brand-secondary" />
|
<ArrowLongRightIcon className="h-3 w-3 text-custom-text-200" />
|
||||||
</span>
|
</span>
|
||||||
<Popover className="flex h-full items-center justify-center rounded-lg">
|
<Popover className="flex h-full items-center justify-center rounded-lg">
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<>
|
<>
|
||||||
<Popover.Button
|
<Popover.Button
|
||||||
disabled={isCompleted ?? false}
|
disabled={isCompleted ?? false}
|
||||||
className={`group flex items-center gap-2 whitespace-nowrap rounded border-[0.5px] border-brand-base bg-brand-surface-1 px-2 py-1 text-xs ${
|
className={`group flex items-center gap-2 whitespace-nowrap rounded border-[0.5px] border-custom-border-100 bg-custom-background-90 px-2 py-1 text-xs ${
|
||||||
cycle.end_date ? "" : "text-brand-secondary"
|
cycle.end_date ? "" : "text-custom-text-200"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<CalendarDaysIcon className="h-3 w-3" />
|
<CalendarDaysIcon className="h-3 w-3" />
|
||||||
@ -409,7 +409,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
<div className="flex w-full flex-col items-start justify-start gap-2">
|
<div className="flex w-full flex-col items-start justify-start gap-2">
|
||||||
<div className="flex w-full items-start justify-between gap-2">
|
<div className="flex w-full items-start justify-between gap-2">
|
||||||
<div className="max-w-[300px]">
|
<div className="max-w-[300px]">
|
||||||
<h4 className="text-xl font-semibold text-brand-base break-words w-full">
|
<h4 className="text-xl font-semibold text-custom-text-100 break-words w-full">
|
||||||
{cycle.name}
|
{cycle.name}
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
@ -431,14 +431,14 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
</CustomMenu>
|
</CustomMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span className="whitespace-normal text-sm leading-5 text-brand-secondary break-words w-full">
|
<span className="whitespace-normal text-sm leading-5 text-custom-text-200 break-words w-full">
|
||||||
{cycle.description}
|
{cycle.description}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col gap-4 text-sm">
|
<div className="flex flex-col gap-4 text-sm">
|
||||||
<div className="flex items-center justify-start gap-1">
|
<div className="flex items-center justify-start gap-1">
|
||||||
<div className="flex w-40 items-center justify-start gap-2 text-brand-secondary">
|
<div className="flex w-40 items-center justify-start gap-2 text-custom-text-200">
|
||||||
<UserCircleIcon className="h-5 w-5" />
|
<UserCircleIcon className="h-5 w-5" />
|
||||||
<span>Lead</span>
|
<span>Lead</span>
|
||||||
</div>
|
</div>
|
||||||
@ -457,17 +457,17 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
{cycle.owned_by.first_name.charAt(0)}
|
{cycle.owned_by.first_name.charAt(0)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<span className="text-brand-secondary">{cycle.owned_by.first_name}</span>
|
<span className="text-custom-text-200">{cycle.owned_by.first_name}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center justify-start gap-1">
|
<div className="flex items-center justify-start gap-1">
|
||||||
<div className="flex w-40 items-center justify-start gap-2 text-brand-secondary">
|
<div className="flex w-40 items-center justify-start gap-2 text-custom-text-200">
|
||||||
<ChartPieIcon className="h-5 w-5" />
|
<ChartPieIcon className="h-5 w-5" />
|
||||||
<span>Progress</span>
|
<span>Progress</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2.5 text-brand-secondary">
|
<div className="flex items-center gap-2.5 text-custom-text-200">
|
||||||
<span className="h-4 w-4">
|
<span className="h-4 w-4">
|
||||||
<ProgressBar value={cycle.completed_issues} maxValue={cycle.total_issues} />
|
<ProgressBar value={cycle.completed_issues} maxValue={cycle.total_issues} />
|
||||||
</span>
|
</span>
|
||||||
@ -477,7 +477,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-full flex-col items-center justify-start gap-2 border-t border-brand-base p-6">
|
<div className="flex w-full flex-col items-center justify-start gap-2 border-t border-custom-border-100 p-6">
|
||||||
<Disclosure defaultOpen>
|
<Disclosure defaultOpen>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<div
|
<div
|
||||||
@ -485,7 +485,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
>
|
>
|
||||||
<div className="flex w-full items-center justify-between gap-2 ">
|
<div className="flex w-full items-center justify-between gap-2 ">
|
||||||
<div className="flex items-center justify-start gap-2 text-sm">
|
<div className="flex items-center justify-start gap-2 text-sm">
|
||||||
<span className="font-medium text-brand-secondary">Progress</span>
|
<span className="font-medium text-custom-text-200">Progress</span>
|
||||||
{!open && progressPercentage ? (
|
{!open && progressPercentage ? (
|
||||||
<span className="rounded bg-[#09A953]/10 px-1.5 py-0.5 text-xs text-[#09A953]">
|
<span className="rounded bg-[#09A953]/10 px-1.5 py-0.5 text-xs text-[#09A953]">
|
||||||
{progressPercentage ? `${progressPercentage}%` : ""}
|
{progressPercentage ? `${progressPercentage}%` : ""}
|
||||||
@ -506,9 +506,9 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
<ExclamationIcon
|
<ExclamationIcon
|
||||||
height={14}
|
height={14}
|
||||||
width={14}
|
width={14}
|
||||||
className="fill-current text-brand-secondary"
|
className="fill-current text-custom-text-200"
|
||||||
/>
|
/>
|
||||||
<span className="text-xs italic text-brand-secondary">
|
<span className="text-xs italic text-custom-text-200">
|
||||||
{cycleStatus === "upcoming"
|
{cycleStatus === "upcoming"
|
||||||
? "Cycle is yet to start."
|
? "Cycle is yet to start."
|
||||||
: "Invalid date. Please enter valid date."}
|
: "Invalid date. Please enter valid date."}
|
||||||
@ -523,7 +523,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
<div className="flex items-start justify-between gap-4 py-2 text-xs">
|
<div className="flex items-start justify-between gap-4 py-2 text-xs">
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<span>
|
<span>
|
||||||
<DocumentIcon className="h-3 w-3 text-brand-secondary" />
|
<DocumentIcon className="h-3 w-3 text-custom-text-200" />
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
Pending Issues -{" "}
|
Pending Issues -{" "}
|
||||||
@ -532,7 +532,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-3 text-brand-base">
|
<div className="flex items-center gap-3 text-custom-text-100">
|
||||||
<div className="flex items-center justify-center gap-1">
|
<div className="flex items-center justify-center gap-1">
|
||||||
<span className="h-2.5 w-2.5 rounded-full bg-[#A9BBD0]" />
|
<span className="h-2.5 w-2.5 rounded-full bg-[#A9BBD0]" />
|
||||||
<span>Ideal</span>
|
<span>Ideal</span>
|
||||||
@ -561,7 +561,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
</Disclosure>
|
</Disclosure>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-full flex-col items-center justify-start gap-2 border-t border-brand-base p-6">
|
<div className="flex w-full flex-col items-center justify-start gap-2 border-t border-custom-border-100 p-6">
|
||||||
<Disclosure defaultOpen>
|
<Disclosure defaultOpen>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<div
|
<div
|
||||||
@ -569,7 +569,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
>
|
>
|
||||||
<div className="flex w-full items-center justify-between gap-2">
|
<div className="flex w-full items-center justify-between gap-2">
|
||||||
<div className="flex items-center justify-start gap-2 text-sm">
|
<div className="flex items-center justify-start gap-2 text-sm">
|
||||||
<span className="font-medium text-brand-secondary">Other Information</span>
|
<span className="font-medium text-custom-text-200">Other Information</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{cycle.total_issues > 0 ? (
|
{cycle.total_issues > 0 ? (
|
||||||
@ -584,9 +584,9 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
|||||||
<ExclamationIcon
|
<ExclamationIcon
|
||||||
height={14}
|
height={14}
|
||||||
width={14}
|
width={14}
|
||||||
className="fill-current text-brand-secondary"
|
className="fill-current text-custom-text-200"
|
||||||
/>
|
/>
|
||||||
<span className="text-xs italic text-brand-secondary">
|
<span className="text-xs italic text-custom-text-200">
|
||||||
No issues found. Please add issue.
|
No issues found. Please add issue.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -128,7 +128,7 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex flex-col rounded-[10px] bg-brand-base border border-brand-base text-xs shadow">
|
<div className="flex flex-col rounded-[10px] bg-custom-background-100 border border-custom-border-100 text-xs shadow">
|
||||||
<Link href={`/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`}>
|
<Link href={`/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`}>
|
||||||
<a className="w-full">
|
<a className="w-full">
|
||||||
<div className="flex h-full flex-col gap-4 rounded-b-[10px] p-4">
|
<div className="flex h-full flex-col gap-4 rounded-b-[10px] p-4">
|
||||||
@ -145,7 +145,7 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
|||||||
: cycleStatus === "completed"
|
: cycleStatus === "completed"
|
||||||
? "#3F76FF"
|
? "#3F76FF"
|
||||||
: cycleStatus === "draft"
|
: cycleStatus === "draft"
|
||||||
? "#858E96"
|
? "rgb(var(--color-text-200))"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
@ -218,12 +218,12 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
|||||||
handleAddToFavorites();
|
handleAddToFavorites();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StarIcon className="h-4 w-4 " color="#858E96" />
|
<StarIcon className="h-4 w-4 " color="rgb(var(--color-text-200))" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex h-4 items-center justify-start gap-5 text-brand-secondary">
|
<div className="flex h-4 items-center justify-start gap-5 text-custom-text-200">
|
||||||
{cycleStatus !== "draft" && (
|
{cycleStatus !== "draft" && (
|
||||||
<>
|
<>
|
||||||
<div className="flex items-start gap-1">
|
<div className="flex items-start gap-1">
|
||||||
@ -240,10 +240,10 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-between items-end">
|
<div className="flex justify-between items-end">
|
||||||
<div className="flex flex-col gap-2 text-xs text-brand-secondary">
|
<div className="flex flex-col gap-2 text-xs text-custom-text-200">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="w-16">Creator:</div>
|
<div className="w-16">Creator:</div>
|
||||||
<div className="flex items-center gap-2.5 text-brand-secondary">
|
<div className="flex items-center gap-2.5 text-custom-text-200">
|
||||||
{cycle.owned_by.avatar && cycle.owned_by.avatar !== "" ? (
|
{cycle.owned_by.avatar && cycle.owned_by.avatar !== "" ? (
|
||||||
<img
|
<img
|
||||||
src={cycle.owned_by.avatar}
|
src={cycle.owned_by.avatar}
|
||||||
@ -253,17 +253,17 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
|||||||
alt={cycle.owned_by.first_name}
|
alt={cycle.owned_by.first_name}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span className="bg-brand-secondary flex h-5 w-5 items-center justify-center rounded-full bg-orange-300 capitalize text-white">
|
<span className="flex h-5 w-5 items-center justify-center rounded-full bg-orange-300 capitalize text-white">
|
||||||
{cycle.owned_by.first_name.charAt(0)}
|
{cycle.owned_by.first_name.charAt(0)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<span className="text-brand-secondary">{cycle.owned_by.first_name}</span>
|
<span className="text-custom-text-200">{cycle.owned_by.first_name}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex h-5 items-center gap-2">
|
<div className="flex h-5 items-center gap-2">
|
||||||
<div className="w-16">Members:</div>
|
<div className="w-16">Members:</div>
|
||||||
{cycle.assignees.length > 0 ? (
|
{cycle.assignees.length > 0 ? (
|
||||||
<div className="flex items-center gap-1 text-brand-secondary">
|
<div className="flex items-center gap-1 text-custom-text-200">
|
||||||
<AssigneesList users={cycle.assignees} length={4} />
|
<AssigneesList users={cycle.assignees} length={4} />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@ -279,11 +279,9 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handleEditCycle();
|
handleEditCycle();
|
||||||
}}
|
}}
|
||||||
className="flex cursor-pointer items-center rounded p-1 text-brand-secondary duration-300 hover:bg-brand-surface-1"
|
className="cursor-pointer rounded p-1 text-custom-text-200 duration-300 hover:bg-custom-background-80"
|
||||||
>
|
>
|
||||||
<span>
|
|
||||||
<PencilIcon className="h-4 w-4" />
|
<PencilIcon className="h-4 w-4" />
|
||||||
</span>
|
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -323,7 +321,7 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
|||||||
<Disclosure>
|
<Disclosure>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<div
|
<div
|
||||||
className={`flex h-full w-full flex-col rounded-b-[10px] border-t border-brand-base bg-brand-surface-2 text-brand-secondary ${
|
className={`flex h-full w-full flex-col rounded-b-[10px] border-t border-custom-border-100 bg-custom-background-80 text-custom-text-200 ${
|
||||||
open ? "" : "flex-row"
|
open ? "" : "flex-row"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@ -369,7 +367,7 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
<Transition show={open}>
|
<Transition show={open}>
|
||||||
<Disclosure.Panel>
|
<Disclosure.Panel>
|
||||||
<div className="overflow-hidden rounded-b-md bg-brand-surface-2 py-3 shadow">
|
<div className="overflow-hidden rounded-b-md bg-custom-background-80 py-3 shadow">
|
||||||
<div className="col-span-2 space-y-3 px-4">
|
<div className="col-span-2 space-y-3 px-4">
|
||||||
<div className="space-y-3 text-xs">
|
<div className="space-y-3 text-xs">
|
||||||
{stateGroups.map((group) => (
|
{stateGroups.map((group) => (
|
||||||
@ -389,7 +387,7 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
|||||||
<div>
|
<div>
|
||||||
<span>
|
<span>
|
||||||
{cycle[group.key as keyof ICycle] as number}{" "}
|
{cycle[group.key as keyof ICycle] as number}{" "}
|
||||||
<span className="text-brand-secondary">
|
<span className="text-custom-text-200">
|
||||||
-{" "}
|
-{" "}
|
||||||
{cycle.total_issues > 0
|
{cycle.total_issues > 0
|
||||||
? `${Math.round(
|
? `${Math.round(
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Image from "next/image";
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
@ -152,12 +151,12 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex flex-col text-xs hover:bg-brand-surface-2">
|
<div className="flex flex-col text-xs hover:bg-custom-background-80">
|
||||||
<Link href={`/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`}>
|
<Link href={`/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`}>
|
||||||
<a className="w-full">
|
<a className="w-full">
|
||||||
<div className="flex h-full flex-col gap-4 rounded-b-[10px] p-4">
|
<div className="flex h-full flex-col gap-4 rounded-b-[10px] p-4">
|
||||||
<div className="flex items-center justify-between gap-1">
|
<div className="flex items-center justify-between gap-1">
|
||||||
<span className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<ContrastIcon
|
<ContrastIcon
|
||||||
className="mt-1 h-5 w-5"
|
className="mt-1 h-5 w-5"
|
||||||
color={`${
|
color={`${
|
||||||
@ -168,7 +167,7 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
|||||||
: cycleStatus === "completed"
|
: cycleStatus === "completed"
|
||||||
? "#3F76FF"
|
? "#3F76FF"
|
||||||
: cycleStatus === "draft"
|
: cycleStatus === "draft"
|
||||||
? "#858E96"
|
? "rgb(var(--color-text-200))"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
@ -179,15 +178,15 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
|||||||
position="top-left"
|
position="top-left"
|
||||||
>
|
>
|
||||||
<h3 className="break-words w-full text-base font-semibold">
|
<h3 className="break-words w-full text-base font-semibold">
|
||||||
{truncateText(cycle.name, 70)}
|
{truncateText(cycle.name, 60)}
|
||||||
</h3>
|
</h3>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<p className="mt-2 text-brand-secondary break-words w-full">
|
<p className="mt-2 text-custom-text-200 break-words w-full">
|
||||||
{cycle.description}
|
{cycle.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</div>
|
||||||
<span className="flex items-center gap-4 capitalize">
|
<div className="flex-shrink-0 flex items-center gap-4">
|
||||||
<span
|
<span
|
||||||
className={`rounded-full px-1.5 py-0.5
|
className={`rounded-full px-1.5 py-0.5
|
||||||
${
|
${
|
||||||
@ -203,14 +202,14 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{cycleStatus === "current" ? (
|
{cycleStatus === "current" ? (
|
||||||
<span className="flex gap-1">
|
<span className="flex gap-1 whitespace-nowrap">
|
||||||
<PersonRunningIcon className="h-4 w-4" />
|
<PersonRunningIcon className="h-4 w-4" />
|
||||||
{findHowManyDaysLeft(cycle.end_date ?? new Date())} Days Left
|
{findHowManyDaysLeft(cycle.end_date ?? new Date())} days left
|
||||||
</span>
|
</span>
|
||||||
) : cycleStatus === "upcoming" ? (
|
) : cycleStatus === "upcoming" ? (
|
||||||
<span className="flex gap-1">
|
<span className="flex gap-1">
|
||||||
<AlarmClockIcon className="h-4 w-4" />
|
<AlarmClockIcon className="h-4 w-4" />
|
||||||
{findHowManyDaysLeft(cycle.start_date ?? new Date())} Days Left
|
{findHowManyDaysLeft(cycle.start_date ?? new Date())} days left
|
||||||
</span>
|
</span>
|
||||||
) : cycleStatus === "completed" ? (
|
) : cycleStatus === "completed" ? (
|
||||||
<span className="flex items-center gap-1">
|
<span className="flex items-center gap-1">
|
||||||
@ -235,20 +234,20 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
{cycleStatus !== "draft" && (
|
{cycleStatus !== "draft" && (
|
||||||
<div className="flex items-center justify-start gap-2 text-brand-secondary">
|
<div className="flex items-center justify-start gap-2 text-custom-text-200">
|
||||||
<div className="flex items-start gap-1 ">
|
<div className="flex items-start gap-1 whitespace-nowrap">
|
||||||
<CalendarDaysIcon className="h-4 w-4" />
|
<CalendarDaysIcon className="h-4 w-4" />
|
||||||
<span>{renderShortDateWithYearFormat(startDate)}</span>
|
<span>{renderShortDateWithYearFormat(startDate)}</span>
|
||||||
</div>
|
</div>
|
||||||
<ArrowRightIcon className="h-4 w-4" />
|
<ArrowRightIcon className="h-4 w-4" />
|
||||||
<div className="flex items-start gap-1 ">
|
<div className="flex items-start gap-1 whitespace-nowrap">
|
||||||
<TargetIcon className="h-4 w-4" />
|
<TargetIcon className="h-4 w-4" />
|
||||||
<span>{renderShortDateWithYearFormat(endDate)}</span>
|
<span>{renderShortDateWithYearFormat(endDate)}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex items-center gap-2.5 text-brand-secondary">
|
<div className="flex items-center gap-2.5 text-custom-text-200">
|
||||||
{cycle.owned_by.avatar && cycle.owned_by.avatar !== "" ? (
|
{cycle.owned_by.avatar && cycle.owned_by.avatar !== "" ? (
|
||||||
<img
|
<img
|
||||||
src={cycle.owned_by.avatar}
|
src={cycle.owned_by.avatar}
|
||||||
@ -258,7 +257,7 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
|||||||
alt={cycle.owned_by.first_name}
|
alt={cycle.owned_by.first_name}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span className="bg-brand-secondary flex h-5 w-5 items-center justify-center rounded-full bg-orange-300 capitalize text-white">
|
<span className="flex h-5 w-5 items-center justify-center rounded-full bg-orange-300 capitalize text-white">
|
||||||
{cycle.owned_by.first_name.charAt(0)}
|
{cycle.owned_by.first_name.charAt(0)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@ -287,7 +286,7 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{cycleStatus === "current" ? (
|
{cycleStatus === "current" ? (
|
||||||
<span className="flex gap-1">
|
<span className="flex gap-1 whitespace-nowrap">
|
||||||
{cycle.total_issues > 0 ? (
|
{cycle.total_issues > 0 ? (
|
||||||
<>
|
<>
|
||||||
<RadialProgressBar
|
<RadialProgressBar
|
||||||
@ -336,7 +335,7 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
|||||||
handleAddToFavorites();
|
handleAddToFavorites();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StarIcon className="h-4 w-4 " color="#858E96" />
|
<StarIcon className="h-4 w-4 " color="rgb(var(--color-text-200))" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
@ -380,7 +379,7 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
|||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
</CustomMenu>
|
</CustomMenu>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
@ -108,21 +108,21 @@ export const TransferIssuesModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
|||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative transform rounded-lg bg-brand-surface-1 py-5 text-left shadow-xl transition-all sm:w-full sm:max-w-2xl">
|
<Dialog.Panel className="relative transform rounded-lg bg-custom-background-90 py-5 text-left shadow-xl transition-all sm:w-full sm:max-w-2xl">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div className="flex items-center justify-between px-5">
|
<div className="flex items-center justify-between px-5">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<TransferIcon className="h-4 w-5" color="#495057" />
|
<TransferIcon className="h-4 w-5" color="#495057" />
|
||||||
<h4 className="text-xl font-medium text-brand-base">Transfer Issues</h4>
|
<h4 className="text-xl font-medium text-custom-text-100">Transfer Issues</h4>
|
||||||
</div>
|
</div>
|
||||||
<button onClick={handleClose}>
|
<button onClick={handleClose}>
|
||||||
<XMarkIcon className="h-4 w-4" />
|
<XMarkIcon className="h-4 w-4" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 border-b border-brand-base px-5 pb-3">
|
<div className="flex items-center gap-2 border-b border-custom-border-100 px-5 pb-3">
|
||||||
<MagnifyingGlassIcon className="h-4 w-4 text-brand-secondary" />
|
<MagnifyingGlassIcon className="h-4 w-4 text-custom-text-200" />
|
||||||
<input
|
<input
|
||||||
className="bg-brand-surface-1 outline-none"
|
className="bg-custom-background-90 outline-none"
|
||||||
placeholder="Search for a cycle..."
|
placeholder="Search for a cycle..."
|
||||||
onChange={(e) => setQuery(e.target.value)}
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
value={query}
|
value={query}
|
||||||
@ -134,7 +134,7 @@ export const TransferIssuesModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
|||||||
filteredOptions.map((option: ICycle) => (
|
filteredOptions.map((option: ICycle) => (
|
||||||
<button
|
<button
|
||||||
key={option.id}
|
key={option.id}
|
||||||
className="flex w-full items-center gap-4 rounded px-4 py-3 text-sm text-brand-secondary hover:bg-brand-surface-1"
|
className="flex w-full items-center gap-4 rounded px-4 py-3 text-sm text-custom-text-200 hover:bg-custom-background-90"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
transferIssue({
|
transferIssue({
|
||||||
new_cycle_id: option?.id,
|
new_cycle_id: option?.id,
|
||||||
@ -145,7 +145,7 @@ export const TransferIssuesModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
|||||||
<ContrastIcon className="h-5 w-5" />
|
<ContrastIcon className="h-5 w-5" />
|
||||||
<div className="flex w-full justify-between">
|
<div className="flex w-full justify-between">
|
||||||
<span>{option?.name}</span>
|
<span>{option?.name}</span>
|
||||||
<span className=" flex items-center rounded-full bg-brand-surface-2 px-2 capitalize">
|
<span className=" flex items-center rounded-full bg-custom-background-80 px-2 capitalize">
|
||||||
{getDateRangeStatus(option?.start_date, option?.end_date)}
|
{getDateRangeStatus(option?.start_date, option?.end_date)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -156,16 +156,16 @@ export const TransferIssuesModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
|||||||
<ExclamationIcon
|
<ExclamationIcon
|
||||||
height={14}
|
height={14}
|
||||||
width={14}
|
width={14}
|
||||||
className="fill-current text-brand-secondary"
|
className="fill-current text-custom-text-200"
|
||||||
/>
|
/>
|
||||||
<span className="text-center text-brand-secondary">
|
<span className="text-center text-custom-text-200">
|
||||||
You don’t have any current cycle. Please create one to transfer the
|
You don’t have any current cycle. Please create one to transfer the
|
||||||
issues.
|
issues.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
<p className="text-center text-brand-secondary">Loading...</p>
|
<p className="text-center text-custom-text-200">Loading...</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,8 +38,8 @@ export const TransferIssues: React.FC<Props> = ({ handleClick }) => {
|
|||||||
: 0;
|
: 0;
|
||||||
return (
|
return (
|
||||||
<div className="-mt-2 mb-4 flex items-center justify-between px-8 pt-6">
|
<div className="-mt-2 mb-4 flex items-center justify-between px-8 pt-6">
|
||||||
<div className="flex items-center gap-2 text-sm text-brand-secondary">
|
<div className="flex items-center gap-2 text-sm text-custom-text-200">
|
||||||
<ExclamationIcon height={14} width={14} className="fill-current text-brand-secondary" />
|
<ExclamationIcon height={14} width={14} className="fill-current text-custom-text-200" />
|
||||||
<span>Completed cycles are not editable.</span>
|
<span>Completed cycles are not editable.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
|||||||
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [openColorPicker, setOpenColorPicker] = useState(false);
|
const [openColorPicker, setOpenColorPicker] = useState(false);
|
||||||
const [activeColor, setActiveColor] = useState<string>("#858e96");
|
const [activeColor, setActiveColor] = useState<string>("rgb(var(--color-text-200))");
|
||||||
|
|
||||||
const [recentEmojis, setRecentEmojis] = useState<string[]>([]);
|
const [recentEmojis, setRecentEmojis] = useState<string[]>([]);
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
|||||||
return (
|
return (
|
||||||
<Popover className="relative z-[1]" ref={ref}>
|
<Popover className="relative z-[1]" ref={ref}>
|
||||||
<Popover.Button
|
<Popover.Button
|
||||||
className="rounded-full bg-brand-surface-1 p-2 outline-none sm:text-sm"
|
className="rounded-full bg-custom-background-90 p-2 outline-none sm:text-sm"
|
||||||
onClick={() => setIsOpen((prev) => !prev)}
|
onClick={() => setIsOpen((prev) => !prev)}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
@ -63,8 +63,8 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
|||||||
leaveFrom="transform opacity-100 scale-100"
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
leaveTo="transform opacity-0 scale-95"
|
leaveTo="transform opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<Popover.Panel className="absolute z-10 mt-2 w-[250px] rounded-[4px] border border-brand-base bg-brand-surface-2 shadow-lg">
|
<Popover.Panel className="absolute z-10 mt-2 w-[250px] rounded-[4px] border border-custom-border-100 bg-custom-background-80 shadow-lg">
|
||||||
<div className="h-[230px] w-[250px] overflow-auto rounded-[4px] border border-brand-base bg-brand-surface-2 p-2 shadow-xl">
|
<div className="h-[230px] w-[250px] overflow-auto rounded-[4px] border border-custom-border-100 bg-custom-background-80 p-2 shadow-xl">
|
||||||
<Tab.Group as="div" className="flex h-full w-full flex-col">
|
<Tab.Group as="div" className="flex h-full w-full flex-col">
|
||||||
<Tab.List className="flex-0 -mx-2 flex justify-around gap-1 p-1">
|
<Tab.List className="flex-0 -mx-2 flex justify-around gap-1 p-1">
|
||||||
{tabOptions.map((tab) => (
|
{tabOptions.map((tab) => (
|
||||||
@ -76,7 +76,7 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
|||||||
setOpenColorPicker(false);
|
setOpenColorPicker(false);
|
||||||
}}
|
}}
|
||||||
className={`-my-1 w-1/2 border-b pb-2 text-center text-sm font-medium outline-none transition-colors ${
|
className={`-my-1 w-1/2 border-b pb-2 text-center text-sm font-medium outline-none transition-colors ${
|
||||||
selected ? "" : "border-transparent text-brand-secondary"
|
selected ? "" : "border-transparent text-custom-text-200"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{tab.title}
|
{tab.title}
|
||||||
@ -89,7 +89,7 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
|||||||
<Tab.Panel>
|
<Tab.Panel>
|
||||||
{recentEmojis.length > 0 && (
|
{recentEmojis.length > 0 && (
|
||||||
<div className="py-2">
|
<div className="py-2">
|
||||||
<h3 className="mb-2 text-xs text-brand-secondary">Recent</h3>
|
<h3 className="mb-2 text-xs text-custom-text-200">Recent</h3>
|
||||||
<div className="grid grid-cols-8 gap-2">
|
<div className="grid grid-cols-8 gap-2">
|
||||||
{recentEmojis.map((emoji) => (
|
{recentEmojis.map((emoji) => (
|
||||||
<button
|
<button
|
||||||
@ -107,7 +107,7 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<hr className="mb-2 h-[1px] w-full border-brand-base" />
|
<hr className="mb-2 h-[1px] w-full border-custom-border-100" />
|
||||||
<div>
|
<div>
|
||||||
<div className="grid grid-cols-8 gap-x-2 gap-y-3">
|
<div className="grid grid-cols-8 gap-x-2 gap-y-3">
|
||||||
{emojis.map((emoji) => (
|
{emojis.map((emoji) => (
|
||||||
@ -173,7 +173,7 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr className="mb-1 h-[1px] w-full border-brand-base" />
|
<hr className="mb-1 h-[1px] w-full border-custom-border-100" />
|
||||||
<div className="mt-1 ml-1 grid grid-cols-8 gap-x-2 gap-y-3">
|
<div className="mt-1 ml-1 grid grid-cols-8 gap-x-2 gap-y-3">
|
||||||
{icons.material_rounded.map((icon, index) => (
|
{icons.material_rounded.map((icon, index) => (
|
||||||
<button
|
<button
|
||||||
|
@ -240,7 +240,7 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
|||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<div className="fixed inset-0 bg-brand-backdrop bg-opacity-50 transition-opacity" />
|
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
|
|
||||||
<div className="fixed inset-0 z-20 overflow-y-auto">
|
<div className="fixed inset-0 z-20 overflow-y-auto">
|
||||||
@ -254,7 +254,7 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
|||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative transform rounded-lg border border-brand-base bg-brand-base px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-100 bg-custom-background-100 px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="text-lg font-medium leading-6">
|
<div className="text-lg font-medium leading-6">
|
||||||
@ -282,9 +282,9 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
|||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-3 gap-3">
|
<div className="grid grid-cols-3 gap-3">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span className="flex h-full items-center rounded-lg bg-brand-surface-2">
|
<span className="flex h-full items-center rounded-lg bg-custom-background-80">
|
||||||
<span className="rounded-lg px-2 text-sm text-brand-secondary">1</span>
|
<span className="rounded-lg px-2 text-sm text-custom-text-200">1</span>
|
||||||
<span className="rounded-r-lg bg-brand-base">
|
<span className="rounded-r-lg bg-custom-background-100">
|
||||||
<Input
|
<Input
|
||||||
id="name"
|
id="name"
|
||||||
name="value1"
|
name="value1"
|
||||||
@ -298,9 +298,9 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span className="flex h-full items-center rounded-lg bg-brand-surface-2">
|
<span className="flex h-full items-center rounded-lg bg-custom-background-80">
|
||||||
<span className="rounded-lg px-2 text-sm text-brand-secondary">2</span>
|
<span className="rounded-lg px-2 text-sm text-custom-text-200">2</span>
|
||||||
<span className="rounded-r-lg bg-brand-base">
|
<span className="rounded-r-lg bg-custom-background-100">
|
||||||
<Input
|
<Input
|
||||||
id="name"
|
id="name"
|
||||||
name="value2"
|
name="value2"
|
||||||
@ -314,9 +314,9 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span className="flex h-full items-center rounded-lg bg-brand-surface-2">
|
<span className="flex h-full items-center rounded-lg bg-custom-background-80">
|
||||||
<span className="rounded-lg px-2 text-sm text-brand-secondary">3</span>
|
<span className="rounded-lg px-2 text-sm text-custom-text-200">3</span>
|
||||||
<span className="rounded-r-lg bg-brand-base">
|
<span className="rounded-r-lg bg-custom-background-100">
|
||||||
<Input
|
<Input
|
||||||
id="name"
|
id="name"
|
||||||
name="value3"
|
name="value3"
|
||||||
@ -330,9 +330,9 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span className="flex h-full items-center rounded-lg bg-brand-surface-2">
|
<span className="flex h-full items-center rounded-lg bg-custom-background-80">
|
||||||
<span className="rounded-lg px-2 text-sm text-brand-secondary">4</span>
|
<span className="rounded-lg px-2 text-sm text-custom-text-200">4</span>
|
||||||
<span className="rounded-r-lg bg-brand-base">
|
<span className="rounded-r-lg bg-custom-background-100">
|
||||||
<Input
|
<Input
|
||||||
id="name"
|
id="name"
|
||||||
name="value4"
|
name="value4"
|
||||||
@ -346,9 +346,9 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span className="flex h-full items-center rounded-lg bg-brand-surface-2">
|
<span className="flex h-full items-center rounded-lg bg-custom-background-80">
|
||||||
<span className="rounded-lg px-2 text-sm text-brand-secondary">5</span>
|
<span className="rounded-lg px-2 text-sm text-custom-text-200">5</span>
|
||||||
<span className="rounded-r-lg bg-brand-base">
|
<span className="rounded-r-lg bg-custom-background-100">
|
||||||
<Input
|
<Input
|
||||||
id="name"
|
id="name"
|
||||||
name="value5"
|
name="value5"
|
||||||
@ -362,9 +362,9 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span className="flex h-full items-center rounded-lg bg-brand-surface-2">
|
<span className="flex h-full items-center rounded-lg bg-custom-background-80">
|
||||||
<span className="rounded-lg px-2 text-sm text-brand-secondary">6</span>
|
<span className="rounded-lg px-2 text-sm text-custom-text-200">6</span>
|
||||||
<span className="rounded-r-lg bg-brand-base">
|
<span className="rounded-r-lg bg-custom-background-100">
|
||||||
<Input
|
<Input
|
||||||
id="name"
|
id="name"
|
||||||
name="value6"
|
name="value6"
|
||||||
|
@ -46,7 +46,7 @@ export const DeleteEstimateModal: React.FC<Props> = ({
|
|||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
<div className="fixed inset-0 bg-brand-backdrop bg-opacity-50 transition-opacity" />
|
<div className="fixed inset-0 bg-custom-backdrop bg-opacity-50 transition-opacity" />
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
|
|
||||||
<div className="fixed inset-0 z-10 overflow-y-auto">
|
<div className="fixed inset-0 z-10 overflow-y-auto">
|
||||||
@ -60,7 +60,7 @@ export const DeleteEstimateModal: React.FC<Props> = ({
|
|||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative transform overflow-hidden rounded-lg border border-brand-base bg-brand-base text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl">
|
<Dialog.Panel className="relative transform overflow-hidden rounded-lg border border-custom-border-100 bg-custom-background-100 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl">
|
||||||
<div className="flex flex-col gap-6 p-6">
|
<div className="flex flex-col gap-6 p-6">
|
||||||
<div className="flex w-full items-center justify-start gap-6">
|
<div className="flex w-full items-center justify-start gap-6">
|
||||||
<span className="place-items-center rounded-full bg-red-500/20 p-4">
|
<span className="place-items-center rounded-full bg-red-500/20 p-4">
|
||||||
@ -74,9 +74,11 @@ export const DeleteEstimateModal: React.FC<Props> = ({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span>
|
<span>
|
||||||
<p className="break-words text-sm leading-7 text-brand-secondary">
|
<p className="break-words text-sm leading-7 text-custom-text-200">
|
||||||
Are you sure you want to delete estimate-{" "}
|
Are you sure you want to delete estimate-{" "}
|
||||||
<span className="break-words font-medium text-brand-base">{data.name}</span>
|
<span className="break-words font-medium text-custom-text-100">
|
||||||
|
{data.name}
|
||||||
|
</span>
|
||||||
{""}? All of the data related to the estiamte will be permanently removed.
|
{""}? All of the data related to the estiamte will be permanently removed.
|
||||||
This action cannot be undone.
|
This action cannot be undone.
|
||||||
</p>
|
</p>
|
||||||
|
@ -72,18 +72,21 @@ export const SingleEstimate: React.FC<Props> = ({
|
|||||||
<h6 className="flex w-[40vw] items-center gap-2 truncate text-sm font-medium">
|
<h6 className="flex w-[40vw] items-center gap-2 truncate text-sm font-medium">
|
||||||
{estimate.name}
|
{estimate.name}
|
||||||
{projectDetails?.estimate && projectDetails?.estimate === estimate.id && (
|
{projectDetails?.estimate && projectDetails?.estimate === estimate.id && (
|
||||||
<span className="rounded bg-green-500/20 px-2 py-0.5 text-xs capitalize text-green-500">
|
<span className="rounded bg-green-500/20 px-2 py-0.5 text-xs text-green-500">
|
||||||
In use
|
In use
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</h6>
|
</h6>
|
||||||
<p className="font-sm w-[40vw] truncate text-[14px] font-normal text-brand-secondary">
|
<p className="font-sm w-[40vw] truncate text-[14px] font-normal text-custom-text-200">
|
||||||
{estimate.description}
|
{estimate.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{projectDetails?.estimate !== estimate.id && estimate.points.length > 0 && (
|
{projectDetails?.estimate !== estimate.id && estimate.points.length > 0 && (
|
||||||
<SecondaryButton onClick={handleUseEstimate} className="py-1">
|
<SecondaryButton
|
||||||
|
onClick={handleUseEstimate}
|
||||||
|
className="!py-1 text-custom-text-200 hover:text-custom-text-100"
|
||||||
|
>
|
||||||
Use
|
Use
|
||||||
</SecondaryButton>
|
</SecondaryButton>
|
||||||
)}
|
)}
|
||||||
@ -114,11 +117,11 @@ export const SingleEstimate: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{estimate.points.length > 0 ? (
|
{estimate.points.length > 0 ? (
|
||||||
<div className="flex text-xs text-brand-secondary">
|
<div className="flex text-xs text-custom-text-200">
|
||||||
Estimate points (
|
Estimate points (
|
||||||
<span className="flex gap-1">
|
<span className="flex gap-1">
|
||||||
{orderArrayBy(estimate.points, "key").map((point, index) => (
|
{orderArrayBy(estimate.points, "key").map((point, index) => (
|
||||||
<h6 key={point.id} className="text-brand-secondary">
|
<h6 key={point.id} className="text-custom-text-200">
|
||||||
{point.value}
|
{point.value}
|
||||||
{index !== estimate.points.length - 1 && ","}{" "}
|
{index !== estimate.points.length - 1 && ","}{" "}
|
||||||
</h6>
|
</h6>
|
||||||
@ -128,7 +131,7 @@ export const SingleEstimate: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-brand-secondary">No estimate points</p>
|
<p className="text-xs text-custom-text-200">No estimate points</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,13 +38,13 @@ export const GanttChartBlocks: FC<{
|
|||||||
style={{ marginLeft: `${block?.position?.marginLeft}px` }}
|
style={{ marginLeft: `${block?.position?.marginLeft}px` }}
|
||||||
>
|
>
|
||||||
<div className="flex-shrink-0 relative w-0 h-0 flex items-center invisible group-hover:visible whitespace-nowrap">
|
<div className="flex-shrink-0 relative w-0 h-0 flex items-center invisible group-hover:visible whitespace-nowrap">
|
||||||
<div className="absolute right-0 mr-[5px] rounded-sm bg-brand-surface-1 px-2 py-0.5 text-xs font-medium">
|
<div className="absolute right-0 mr-[5px] rounded-sm bg-custom-background-90 px-2 py-0.5 text-xs font-medium">
|
||||||
{block?.start_date ? datePreview(block?.start_date) : "-"}
|
{block?.start_date ? datePreview(block?.start_date) : "-"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="rounded shadow-sm bg-brand-base overflow-hidden relative flex items-center h-[34px] border border-brand-base"
|
className="rounded shadow-sm bg-custom-background-100 overflow-hidden relative flex items-center h-[34px] border border-custom-border-100"
|
||||||
style={{
|
style={{
|
||||||
width: `${block?.position?.width}px`,
|
width: `${block?.position?.width}px`,
|
||||||
}}
|
}}
|
||||||
@ -56,7 +56,7 @@ export const GanttChartBlocks: FC<{
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-shrink-0 relative w-0 h-0 flex items-center invisible group-hover:visible whitespace-nowrap">
|
<div className="flex-shrink-0 relative w-0 h-0 flex items-center invisible group-hover:visible whitespace-nowrap">
|
||||||
<div className="absolute left-0 ml-[5px] mr-[5px] rounded-sm bg-brand-surface-1 px-2 py-0.5 text-xs font-medium">
|
<div className="absolute left-0 ml-[5px] mr-[5px] rounded-sm bg-custom-background-90 px-2 py-0.5 text-xs font-medium">
|
||||||
{block?.target_date ? datePreview(block?.target_date) : "-"}
|
{block?.target_date ? datePreview(block?.target_date) : "-"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -68,11 +68,11 @@ export const GanttChartBlocks: FC<{
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* sidebar */}
|
{/* sidebar */}
|
||||||
{/* <div className="fixed top-0 bottom-0 w-[300px] flex-shrink-0 divide-y divide-brand-base border-r border-brand-base overflow-y-auto">
|
{/* <div className="fixed top-0 bottom-0 w-[300px] flex-shrink-0 divide-y divide-custom-border-100 border-r border-custom-border-100 overflow-y-auto">
|
||||||
{blocks &&
|
{blocks &&
|
||||||
blocks.length > 0 &&
|
blocks.length > 0 &&
|
||||||
blocks.map((block: any, _idx: number) => (
|
blocks.map((block: any, _idx: number) => (
|
||||||
<div className="relative h-[40px] bg-brand-base" key={`sidebar-blocks-${_idx}`}>
|
<div className="relative h-[40px] bg-custom-background-100" key={`sidebar-blocks-${_idx}`}>
|
||||||
{sidebarBlockRender(block?.data)}
|
{sidebarBlockRender(block?.data)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
@ -7,18 +7,18 @@ export const BiWeekChartView: FC<any> = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="absolute flex h-full flex-grow divide-x divide-brand-base">
|
<div className="absolute flex h-full flex-grow divide-x divide-custom-border-100">
|
||||||
{renderView &&
|
{renderView &&
|
||||||
renderView.length > 0 &&
|
renderView.length > 0 &&
|
||||||
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
||||||
<div key={`title-${_idxRoot}`} className="relative flex flex-col">
|
<div key={`title-${_idxRoot}`} className="relative flex flex-col">
|
||||||
<div className="relative border-b border-brand-base">
|
<div className="relative border-b border-custom-border-100">
|
||||||
<div className="sticky left-0 inline-flex whitespace-nowrap px-2 py-1 text-sm font-medium capitalize">
|
<div className="sticky left-0 inline-flex whitespace-nowrap px-2 py-1 text-sm font-medium capitalize">
|
||||||
{_itemRoot?.title}
|
{_itemRoot?.title}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex h-full w-full divide-x divide-brand-base">
|
<div className="flex h-full w-full divide-x divide-custom-border-100">
|
||||||
{_itemRoot.children &&
|
{_itemRoot.children &&
|
||||||
_itemRoot.children.length > 0 &&
|
_itemRoot.children.length > 0 &&
|
||||||
_itemRoot.children.map((_item: any, _idx: any) => (
|
_itemRoot.children.map((_item: any, _idx: any) => (
|
||||||
@ -29,7 +29,7 @@ export const BiWeekChartView: FC<any> = () => {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`flex-shrink-0 border-b py-1 text-center text-sm capitalize font-medium ${
|
className={`flex-shrink-0 border-b py-1 text-center text-sm capitalize font-medium ${
|
||||||
_item?.today ? `text-red-500 border-red-500` : `border-brand-base`
|
_item?.today ? `text-red-500 border-red-500` : `border-custom-border-100`
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div>{_item.title}</div>
|
<div>{_item.title}</div>
|
||||||
@ -37,7 +37,7 @@ export const BiWeekChartView: FC<any> = () => {
|
|||||||
<div
|
<div
|
||||||
className={`relative h-full w-full flex-1 flex justify-center ${
|
className={`relative h-full w-full flex-1 flex justify-center ${
|
||||||
["sat", "sun"].includes(_item?.dayData?.shortTitle || "")
|
["sat", "sun"].includes(_item?.dayData?.shortTitle || "")
|
||||||
? `bg-brand-surface-2`
|
? `bg-custom-background-80`
|
||||||
: ``
|
: ``
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
@ -7,18 +7,18 @@ export const DayChartView: FC<any> = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="absolute flex h-full flex-grow divide-x divide-brand-base">
|
<div className="absolute flex h-full flex-grow divide-x divide-custom-border-100">
|
||||||
{renderView &&
|
{renderView &&
|
||||||
renderView.length > 0 &&
|
renderView.length > 0 &&
|
||||||
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
||||||
<div key={`title-${_idxRoot}`} className="relative flex flex-col">
|
<div key={`title-${_idxRoot}`} className="relative flex flex-col">
|
||||||
<div className="relative border-b border-brand-base">
|
<div className="relative border-b border-custom-border-100">
|
||||||
<div className="sticky left-0 inline-flex whitespace-nowrap px-2 py-1 text-sm font-medium capitalize">
|
<div className="sticky left-0 inline-flex whitespace-nowrap px-2 py-1 text-sm font-medium capitalize">
|
||||||
{_itemRoot?.title}
|
{_itemRoot?.title}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex h-full w-full divide-x divide-brand-base">
|
<div className="flex h-full w-full divide-x divide-custom-border-100">
|
||||||
{_itemRoot.children &&
|
{_itemRoot.children &&
|
||||||
_itemRoot.children.length > 0 &&
|
_itemRoot.children.length > 0 &&
|
||||||
_itemRoot.children.map((_item: any, _idx: any) => (
|
_itemRoot.children.map((_item: any, _idx: any) => (
|
||||||
@ -29,7 +29,7 @@ export const DayChartView: FC<any> = () => {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`flex-shrink-0 border-b py-1 text-center text-sm capitalize font-medium ${
|
className={`flex-shrink-0 border-b py-1 text-center text-sm capitalize font-medium ${
|
||||||
_item?.today ? `text-red-500 border-red-500` : `border-brand-base`
|
_item?.today ? `text-red-500 border-red-500` : `border-custom-border-100`
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div>{_item.title}</div>
|
<div>{_item.title}</div>
|
||||||
|
@ -7,18 +7,18 @@ export const HourChartView: FC<any> = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="absolute flex h-full flex-grow divide-x divide-brand-base">
|
<div className="absolute flex h-full flex-grow divide-x divide-custom-border-100">
|
||||||
{renderView &&
|
{renderView &&
|
||||||
renderView.length > 0 &&
|
renderView.length > 0 &&
|
||||||
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
||||||
<div key={`title-${_idxRoot}`} className="relative flex flex-col">
|
<div key={`title-${_idxRoot}`} className="relative flex flex-col">
|
||||||
<div className="relative border-b border-brand-base">
|
<div className="relative border-b border-custom-border-100">
|
||||||
<div className="sticky left-0 inline-flex whitespace-nowrap px-2 py-1 text-sm font-medium capitalize">
|
<div className="sticky left-0 inline-flex whitespace-nowrap px-2 py-1 text-sm font-medium capitalize">
|
||||||
{_itemRoot?.title}
|
{_itemRoot?.title}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex h-full w-full divide-x divide-brand-base">
|
<div className="flex h-full w-full divide-x divide-custom-border-100">
|
||||||
{_itemRoot.children &&
|
{_itemRoot.children &&
|
||||||
_itemRoot.children.length > 0 &&
|
_itemRoot.children.length > 0 &&
|
||||||
_itemRoot.children.map((_item: any, _idx: any) => (
|
_itemRoot.children.map((_item: any, _idx: any) => (
|
||||||
@ -29,7 +29,7 @@ export const HourChartView: FC<any> = () => {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`flex-shrink-0 border-b py-1 text-center text-sm capitalize font-medium ${
|
className={`flex-shrink-0 border-b py-1 text-center text-sm capitalize font-medium ${
|
||||||
_item?.today ? `text-red-500 border-red-500` : `border-brand-base`
|
_item?.today ? `text-red-500 border-red-500` : `border-custom-border-100`
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div>{_item.title}</div>
|
<div>{_item.title}</div>
|
||||||
|
@ -215,17 +215,19 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
fullScreenMode ? `fixed top-0 bottom-0 left-0 right-0 z-[999999] bg-brand-base` : `relative`
|
fullScreenMode
|
||||||
|
? `fixed top-0 bottom-0 left-0 right-0 z-[999999] bg-custom-background-100`
|
||||||
|
: `relative`
|
||||||
} ${
|
} ${
|
||||||
border ? `border border-brand-base` : ``
|
border ? `border border-custom-border-100` : ``
|
||||||
} flex h-full flex-col rounded-sm select-none bg-brand-base shadow`}
|
} flex h-full flex-col rounded-sm select-none bg-custom-background-100 shadow`}
|
||||||
>
|
>
|
||||||
{/* chart title */}
|
{/* chart title */}
|
||||||
{/* <div className="flex w-full flex-shrink-0 flex-wrap items-center gap-5 gap-y-3 whitespace-nowrap p-2 border-b border-brand-base">
|
{/* <div className="flex w-full flex-shrink-0 flex-wrap items-center gap-5 gap-y-3 whitespace-nowrap p-2 border-b border-custom-border-100">
|
||||||
{title && (
|
{title && (
|
||||||
<div className="text-lg font-medium flex gap-2 items-center">
|
<div className="text-lg font-medium flex gap-2 items-center">
|
||||||
<div>{title}</div>
|
<div>{title}</div>
|
||||||
<div className="text-xs rounded-full px-2 py-1 font-bold border border-brand-accent/75 bg-brand-accent/5 text-brand-base">
|
<div className="text-xs rounded-full px-2 py-1 font-bold border border-custom-primary/75 bg-custom-primary/5 text-custom-text-100">
|
||||||
Gantt View Beta
|
Gantt View Beta
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -242,7 +244,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
|||||||
{/* chart header */}
|
{/* chart header */}
|
||||||
<div className="flex w-full flex-shrink-0 flex-wrap items-center gap-5 gap-y-3 whitespace-nowrap p-2">
|
<div className="flex w-full flex-shrink-0 flex-wrap items-center gap-5 gap-y-3 whitespace-nowrap p-2">
|
||||||
{/* <div
|
{/* <div
|
||||||
className="transition-all border border-brand-base w-[30px] h-[30px] flex justify-center items-center cursor-pointer rounded-sm hover:bg-brand-surface-2"
|
className="transition-all border border-custom-border-100 w-[30px] h-[30px] flex justify-center items-center cursor-pointer rounded-sm hover:bg-custom-background-80"
|
||||||
onClick={() => setBlocksSidebarView(() => !blocksSidebarView)}
|
onClick={() => setBlocksSidebarView(() => !blocksSidebarView)}
|
||||||
>
|
>
|
||||||
{blocksSidebarView ? (
|
{blocksSidebarView ? (
|
||||||
@ -255,7 +257,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
|||||||
{title && (
|
{title && (
|
||||||
<div className="text-lg font-medium flex gap-2 items-center">
|
<div className="text-lg font-medium flex gap-2 items-center">
|
||||||
<div>{title}</div>
|
<div>{title}</div>
|
||||||
<div className="text-xs rounded-full px-2 py-1 font-bold border border-brand-accent/75 bg-brand-accent/5 text-brand-base">
|
<div className="text-xs rounded-full px-2 py-1 font-bold border border-custom-primary/75 bg-custom-primary/5 text-custom-text-100">
|
||||||
Gantt View Beta
|
Gantt View Beta
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -277,8 +279,10 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
|||||||
allViews.map((_chatView: any, _idx: any) => (
|
allViews.map((_chatView: any, _idx: any) => (
|
||||||
<div
|
<div
|
||||||
key={_chatView?.key}
|
key={_chatView?.key}
|
||||||
className={`cursor-pointer rounded-sm border border-brand-base p-1 px-2 text-xs ${
|
className={`cursor-pointer rounded-sm border border-custom-border-100 p-1 px-2 text-xs ${
|
||||||
currentView === _chatView?.key ? `bg-brand-surface-2` : `hover:bg-brand-surface-1`
|
currentView === _chatView?.key
|
||||||
|
? `bg-custom-background-80`
|
||||||
|
: `hover:bg-custom-background-90`
|
||||||
}`}
|
}`}
|
||||||
onClick={() => handleChartView(_chatView?.key)}
|
onClick={() => handleChartView(_chatView?.key)}
|
||||||
>
|
>
|
||||||
@ -289,7 +293,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
|||||||
|
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<div
|
<div
|
||||||
className={`cursor-pointer rounded-sm border border-brand-base p-1 px-2 text-xs hover:bg-brand-surface-2`}
|
className={`cursor-pointer rounded-sm border border-custom-border-100 p-1 px-2 text-xs hover:bg-custom-background-80`}
|
||||||
onClick={handleToday}
|
onClick={handleToday}
|
||||||
>
|
>
|
||||||
Today
|
Today
|
||||||
@ -297,7 +301,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="transition-all border border-brand-base w-[30px] h-[30px] flex justify-center items-center cursor-pointer rounded-sm hover:bg-brand-surface-2"
|
className="transition-all border border-custom-border-100 w-[30px] h-[30px] flex justify-center items-center cursor-pointer rounded-sm hover:bg-custom-background-80"
|
||||||
onClick={() => setFullScreenMode(() => !fullScreenMode)}
|
onClick={() => setFullScreenMode(() => !fullScreenMode)}
|
||||||
>
|
>
|
||||||
{fullScreenMode ? (
|
{fullScreenMode ? (
|
||||||
@ -309,7 +313,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* content */}
|
{/* content */}
|
||||||
<div className="relative flex h-full w-full flex-1 overflow-hidden border-t border-brand-base">
|
<div className="relative flex h-full w-full flex-1 overflow-hidden border-t border-custom-border-100">
|
||||||
<div
|
<div
|
||||||
className="relative flex h-full w-full flex-1 flex-col overflow-hidden overflow-x-auto"
|
className="relative flex h-full w-full flex-1 flex-col overflow-hidden overflow-x-auto"
|
||||||
id="scroll-container"
|
id="scroll-container"
|
||||||
|
@ -7,18 +7,18 @@ export const MonthChartView: FC<any> = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="absolute flex h-full flex-grow divide-x divide-brand-base">
|
<div className="absolute flex h-full flex-grow divide-x divide-custom-border-100">
|
||||||
{renderView &&
|
{renderView &&
|
||||||
renderView.length > 0 &&
|
renderView.length > 0 &&
|
||||||
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
||||||
<div key={`title-${_idxRoot}`} className="relative flex flex-col">
|
<div key={`title-${_idxRoot}`} className="relative flex flex-col">
|
||||||
<div className="relative border-b border-brand-base">
|
<div className="relative border-b border-custom-border-100">
|
||||||
<div className="sticky left-0 inline-flex whitespace-nowrap px-2 py-1 text-sm font-medium capitalize">
|
<div className="sticky left-0 inline-flex whitespace-nowrap px-2 py-1 text-sm font-medium capitalize">
|
||||||
{_itemRoot?.title}
|
{_itemRoot?.title}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex h-full w-full divide-x divide-brand-base">
|
<div className="flex h-full w-full divide-x divide-custom-border-100">
|
||||||
{_itemRoot.children &&
|
{_itemRoot.children &&
|
||||||
_itemRoot.children.length > 0 &&
|
_itemRoot.children.length > 0 &&
|
||||||
_itemRoot.children.map((_item: any, _idx: any) => (
|
_itemRoot.children.map((_item: any, _idx: any) => (
|
||||||
@ -29,7 +29,7 @@ export const MonthChartView: FC<any> = () => {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`flex-shrink-0 border-b py-1 text-center text-sm capitalize font-medium ${
|
className={`flex-shrink-0 border-b py-1 text-center text-sm capitalize font-medium ${
|
||||||
_item?.today ? `text-red-500 border-red-500` : `border-brand-base`
|
_item?.today ? `text-red-500 border-red-500` : `border-custom-border-100`
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div>{_item.title}</div>
|
<div>{_item.title}</div>
|
||||||
@ -37,7 +37,7 @@ export const MonthChartView: FC<any> = () => {
|
|||||||
<div
|
<div
|
||||||
className={`relative h-full w-full flex-1 flex justify-center ${
|
className={`relative h-full w-full flex-1 flex justify-center ${
|
||||||
["sat", "sun"].includes(_item?.dayData?.shortTitle || "")
|
["sat", "sun"].includes(_item?.dayData?.shortTitle || "")
|
||||||
? `bg-brand-surface-1`
|
? `bg-custom-background-90`
|
||||||
: ``
|
: ``
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
@ -7,18 +7,18 @@ export const QuarterChartView: FC<any> = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="absolute flex h-full flex-grow divide-x divide-brand-base">
|
<div className="absolute flex h-full flex-grow divide-x divide-custom-border-100">
|
||||||
{renderView &&
|
{renderView &&
|
||||||
renderView.length > 0 &&
|
renderView.length > 0 &&
|
||||||
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
||||||
<div key={`title-${_idxRoot}`} className="relative flex flex-col">
|
<div key={`title-${_idxRoot}`} className="relative flex flex-col">
|
||||||
<div className="relative border-b border-brand-base">
|
<div className="relative border-b border-custom-border-100">
|
||||||
<div className="sticky left-0 inline-flex whitespace-nowrap px-2 py-1 text-sm font-medium capitalize">
|
<div className="sticky left-0 inline-flex whitespace-nowrap px-2 py-1 text-sm font-medium capitalize">
|
||||||
{_itemRoot?.title}
|
{_itemRoot?.title}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex h-full w-full divide-x divide-brand-base">
|
<div className="flex h-full w-full divide-x divide-custom-border-100">
|
||||||
{_itemRoot.children &&
|
{_itemRoot.children &&
|
||||||
_itemRoot.children.length > 0 &&
|
_itemRoot.children.length > 0 &&
|
||||||
_itemRoot.children.map((_item: any, _idx: any) => (
|
_itemRoot.children.map((_item: any, _idx: any) => (
|
||||||
@ -29,7 +29,7 @@ export const QuarterChartView: FC<any> = () => {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`flex-shrink-0 border-b py-1 text-center text-sm capitalize font-medium ${
|
className={`flex-shrink-0 border-b py-1 text-center text-sm capitalize font-medium ${
|
||||||
_item?.today ? `text-red-500 border-red-500` : `border-brand-base`
|
_item?.today ? `text-red-500 border-red-500` : `border-custom-border-100`
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div>{_item.title}</div>
|
<div>{_item.title}</div>
|
||||||
|
@ -7,18 +7,18 @@ export const WeekChartView: FC<any> = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="absolute flex h-full flex-grow divide-x divide-brand-base">
|
<div className="absolute flex h-full flex-grow divide-x divide-custom-border-100">
|
||||||
{renderView &&
|
{renderView &&
|
||||||
renderView.length > 0 &&
|
renderView.length > 0 &&
|
||||||
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
||||||
<div key={`title-${_idxRoot}`} className="relative flex flex-col">
|
<div key={`title-${_idxRoot}`} className="relative flex flex-col">
|
||||||
<div className="relative border-b border-brand-base">
|
<div className="relative border-b border-custom-border-100">
|
||||||
<div className="sticky left-0 inline-flex whitespace-nowrap px-2 py-1 text-sm font-medium capitalize">
|
<div className="sticky left-0 inline-flex whitespace-nowrap px-2 py-1 text-sm font-medium capitalize">
|
||||||
{_itemRoot?.title}
|
{_itemRoot?.title}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex h-full w-full divide-x divide-brand-base">
|
<div className="flex h-full w-full divide-x divide-custom-border-100">
|
||||||
{_itemRoot.children &&
|
{_itemRoot.children &&
|
||||||
_itemRoot.children.length > 0 &&
|
_itemRoot.children.length > 0 &&
|
||||||
_itemRoot.children.map((_item: any, _idx: any) => (
|
_itemRoot.children.map((_item: any, _idx: any) => (
|
||||||
@ -29,7 +29,7 @@ export const WeekChartView: FC<any> = () => {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`flex-shrink-0 border-b py-1 text-center text-sm capitalize font-medium ${
|
className={`flex-shrink-0 border-b py-1 text-center text-sm capitalize font-medium ${
|
||||||
_item?.today ? `text-red-500 border-red-500` : `border-brand-base`
|
_item?.today ? `text-red-500 border-red-500` : `border-custom-border-100`
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div>{_item.title}</div>
|
<div>{_item.title}</div>
|
||||||
@ -37,7 +37,7 @@ export const WeekChartView: FC<any> = () => {
|
|||||||
<div
|
<div
|
||||||
className={`relative h-full w-full flex-1 flex justify-center ${
|
className={`relative h-full w-full flex-1 flex justify-center ${
|
||||||
["sat", "sun"].includes(_item?.dayData?.shortTitle || "")
|
["sat", "sun"].includes(_item?.dayData?.shortTitle || "")
|
||||||
? `bg-brand-surface-2`
|
? `bg-custom-background-80`
|
||||||
: ``
|
: ``
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user