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
|
||||
|
||||
# GPT settings
|
||||
OPENAI_API_KEY=""
|
||||
GPT_ENGINE=""
|
||||
OPENAI_API_BASE="https://api.openai.com/v1" # change if using a custom endpoint
|
||||
OPENAI_API_KEY="sk-" # add your openai key here
|
||||
GPT_ENGINE="gpt-3.5-turbo" # use "gpt-4" if you have access
|
||||
|
||||
# Github
|
||||
GITHUB_CLIENT_SECRET="" # For fetching release notes
|
||||
|
@ -1,2 +1,3 @@
|
||||
web: gunicorn -w 4 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:$PORT --config gunicorn.config.py --max-requests 10000 --max-requests-jitter 1000 --access-logfile -
|
||||
worker: celery -A plane worker -l info
|
||||
beat: celery -A plane beat -l INFO
|
@ -77,6 +77,8 @@ from plane.api.views import (
|
||||
BulkCreateIssueLabelsEndpoint,
|
||||
IssueAttachmentEndpoint,
|
||||
IssueSubscriberViewSet,
|
||||
IssueArchiveViewSet,
|
||||
IssueSubscriberViewSet,
|
||||
## End Issues
|
||||
# States
|
||||
StateViewSet,
|
||||
@ -853,6 +855,36 @@ urlpatterns = [
|
||||
name="project-issue-roadmap",
|
||||
),
|
||||
## IssueProperty Ebd
|
||||
## Issue Archives
|
||||
path(
|
||||
"workspaces/<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
|
||||
path(
|
||||
"workspaces/<str:slug>/file-assets/",
|
||||
|
@ -65,6 +65,7 @@ from .issue import (
|
||||
IssueLinkViewSet,
|
||||
BulkCreateIssueLabelsEndpoint,
|
||||
IssueAttachmentEndpoint,
|
||||
IssueArchiveViewSet,
|
||||
IssueSubscriberViewSet,
|
||||
)
|
||||
|
||||
|
@ -67,7 +67,7 @@ class GPTIntegrationEndpoint(BaseAPIView):
|
||||
|
||||
openai.api_key = settings.OPENAI_API_KEY
|
||||
response = openai.Completion.create(
|
||||
engine=settings.GPT_ENGINE,
|
||||
model=settings.GPT_ENGINE,
|
||||
prompt=final_text,
|
||||
temperature=0.7,
|
||||
max_tokens=1024,
|
||||
|
@ -914,6 +914,197 @@ class IssueAttachmentEndpoint(BaseAPIView):
|
||||
)
|
||||
|
||||
|
||||
class IssueArchiveViewSet(BaseViewSet):
|
||||
permission_classes = [
|
||||
ProjectEntityPermission,
|
||||
]
|
||||
serializer_class = IssueFlatSerializer
|
||||
model = Issue
|
||||
|
||||
def get_queryset(self):
|
||||
return (
|
||||
Issue.objects.annotate(
|
||||
sub_issues_count=Issue.objects.filter(parent=OuterRef("id"))
|
||||
.order_by()
|
||||
.annotate(count=Func(F("id"), function="Count"))
|
||||
.values("count")
|
||||
)
|
||||
.filter(archived_at__isnull=False)
|
||||
.filter(project_id=self.kwargs.get("project_id"))
|
||||
.filter(workspace__slug=self.kwargs.get("slug"))
|
||||
.select_related("project")
|
||||
.select_related("workspace")
|
||||
.select_related("state")
|
||||
.select_related("parent")
|
||||
.prefetch_related("assignees")
|
||||
.prefetch_related("labels")
|
||||
)
|
||||
|
||||
@method_decorator(gzip_page)
|
||||
def list(self, request, slug, project_id):
|
||||
try:
|
||||
filters = issue_filters(request.query_params, "GET")
|
||||
show_sub_issues = request.GET.get("show_sub_issues", "true")
|
||||
|
||||
# Custom ordering for priority and state
|
||||
priority_order = ["urgent", "high", "medium", "low", None]
|
||||
state_order = ["backlog", "unstarted", "started", "completed", "cancelled"]
|
||||
|
||||
order_by_param = request.GET.get("order_by", "-created_at")
|
||||
|
||||
issue_queryset = (
|
||||
self.get_queryset()
|
||||
.filter(**filters)
|
||||
.annotate(cycle_id=F("issue_cycle__id"))
|
||||
.annotate(module_id=F("issue_module__id"))
|
||||
.annotate(
|
||||
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
|
||||
.order_by()
|
||||
.annotate(count=Func(F("id"), function="Count"))
|
||||
.values("count")
|
||||
)
|
||||
.annotate(
|
||||
attachment_count=IssueAttachment.objects.filter(
|
||||
issue=OuterRef("id")
|
||||
)
|
||||
.order_by()
|
||||
.annotate(count=Func(F("id"), function="Count"))
|
||||
.values("count")
|
||||
)
|
||||
)
|
||||
|
||||
# Priority Ordering
|
||||
if order_by_param == "priority" or order_by_param == "-priority":
|
||||
priority_order = (
|
||||
priority_order
|
||||
if order_by_param == "priority"
|
||||
else priority_order[::-1]
|
||||
)
|
||||
issue_queryset = issue_queryset.annotate(
|
||||
priority_order=Case(
|
||||
*[
|
||||
When(priority=p, then=Value(i))
|
||||
for i, p in enumerate(priority_order)
|
||||
],
|
||||
output_field=CharField(),
|
||||
)
|
||||
).order_by("priority_order")
|
||||
|
||||
# State Ordering
|
||||
elif order_by_param in [
|
||||
"state__name",
|
||||
"state__group",
|
||||
"-state__name",
|
||||
"-state__group",
|
||||
]:
|
||||
state_order = (
|
||||
state_order
|
||||
if order_by_param in ["state__name", "state__group"]
|
||||
else state_order[::-1]
|
||||
)
|
||||
issue_queryset = issue_queryset.annotate(
|
||||
state_order=Case(
|
||||
*[
|
||||
When(state__group=state_group, then=Value(i))
|
||||
for i, state_group in enumerate(state_order)
|
||||
],
|
||||
default=Value(len(state_order)),
|
||||
output_field=CharField(),
|
||||
)
|
||||
).order_by("state_order")
|
||||
# assignee and label ordering
|
||||
elif order_by_param in [
|
||||
"labels__name",
|
||||
"-labels__name",
|
||||
"assignees__first_name",
|
||||
"-assignees__first_name",
|
||||
]:
|
||||
issue_queryset = issue_queryset.annotate(
|
||||
max_values=Max(
|
||||
order_by_param[1::]
|
||||
if order_by_param.startswith("-")
|
||||
else order_by_param
|
||||
)
|
||||
).order_by(
|
||||
"-max_values" if order_by_param.startswith("-") else "max_values"
|
||||
)
|
||||
else:
|
||||
issue_queryset = issue_queryset.order_by(order_by_param)
|
||||
|
||||
issue_queryset = (
|
||||
issue_queryset
|
||||
if show_sub_issues == "true"
|
||||
else issue_queryset.filter(parent__isnull=True)
|
||||
)
|
||||
|
||||
issues = IssueLiteSerializer(issue_queryset, many=True).data
|
||||
|
||||
## Grouping the results
|
||||
group_by = request.GET.get("group_by", False)
|
||||
if group_by:
|
||||
return Response(
|
||||
group_results(issues, group_by), status=status.HTTP_200_OK
|
||||
)
|
||||
|
||||
return Response(issues, status=status.HTTP_200_OK)
|
||||
|
||||
except Exception as e:
|
||||
capture_exception(e)
|
||||
return Response(
|
||||
{"error": "Something went wrong please try again later"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
def retrieve(self, request, slug, project_id, pk=None):
|
||||
try:
|
||||
issue = Issue.objects.get(
|
||||
workspace__slug=slug,
|
||||
project_id=project_id,
|
||||
archived_at__isnull=False,
|
||||
pk=pk,
|
||||
)
|
||||
return Response(IssueSerializer(issue).data, status=status.HTTP_200_OK)
|
||||
except Issue.DoesNotExist:
|
||||
return Response(
|
||||
{"error": "Issue Does not exist"}, status=status.HTTP_404_NOT_FOUND
|
||||
)
|
||||
except Exception as e:
|
||||
capture_exception(e)
|
||||
return Response(
|
||||
{"error": "Something went wrong please try again later"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
def unarchive(self, request, slug, project_id, pk=None):
|
||||
try:
|
||||
issue = Issue.objects.get(
|
||||
workspace__slug=slug,
|
||||
project_id=project_id,
|
||||
archived_at__isnull=False,
|
||||
pk=pk,
|
||||
)
|
||||
issue.archived_at = None
|
||||
issue.save()
|
||||
issue_activity.delay(
|
||||
type="issue.activity.updated",
|
||||
requested_data=json.dumps({"archived_in": None}),
|
||||
actor_id=str(request.user.id),
|
||||
issue_id=str(issue.id),
|
||||
project_id=str(project_id),
|
||||
current_instance=None,
|
||||
)
|
||||
|
||||
return Response(IssueSerializer(issue).data, status=status.HTTP_200_OK)
|
||||
except Issue.DoesNotExist:
|
||||
return Response(
|
||||
{"error": "Issue Does not exist"}, status=status.HTTP_404_NOT_FOUND)
|
||||
except Exception as e:
|
||||
capture_exception(e)
|
||||
return Response(
|
||||
{"error": "Something went wrong, please try again later"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
class IssueSubscriberViewSet(BaseViewSet):
|
||||
serializer_class = IssueSubscriberSerializer
|
||||
model = IssueSubscriber
|
||||
|
@ -5,6 +5,7 @@ import requests
|
||||
# Django imports
|
||||
from django.conf import settings
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.utils import timezone
|
||||
|
||||
# Third Party imports
|
||||
from celery import shared_task
|
||||
@ -557,6 +558,24 @@ def track_estimate_points(
|
||||
)
|
||||
|
||||
|
||||
def track_archive_in(
|
||||
requested_data, current_instance, issue_id, project, actor, issue_activities
|
||||
):
|
||||
issue_activities.append(
|
||||
IssueActivity(
|
||||
issue_id=issue_id,
|
||||
project=project,
|
||||
workspace=project.workspace,
|
||||
comment=f"{actor.email} has restored the issue",
|
||||
verb="updated",
|
||||
actor=actor,
|
||||
field="archived_at",
|
||||
old_value="archive",
|
||||
new_value="restore",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def update_issue_activity(
|
||||
requested_data, current_instance, issue_id, project, actor, issue_activities
|
||||
):
|
||||
@ -573,6 +592,7 @@ def update_issue_activity(
|
||||
"blocks_list": track_blocks,
|
||||
"blockers_list": track_blockings,
|
||||
"estimate_point": track_estimate_points,
|
||||
"archived_in": track_archive_in,
|
||||
}
|
||||
|
||||
requested_data = json.loads(requested_data) if requested_data is not None else None
|
||||
@ -950,6 +970,7 @@ def delete_attachment_activity(
|
||||
)
|
||||
|
||||
|
||||
|
||||
# Receive message from room group
|
||||
@shared_task
|
||||
def issue_activity(
|
||||
@ -961,6 +982,11 @@ def issue_activity(
|
||||
actor = User.objects.get(pk=actor_id)
|
||||
project = Project.objects.get(pk=project_id)
|
||||
|
||||
issue = Issue.objects.filter(pk=issue_id).first()
|
||||
if issue is not None:
|
||||
issue.updated_at = timezone.now()
|
||||
issue.save()
|
||||
|
||||
# add the user to issue subscriber
|
||||
try:
|
||||
_ = IssueSubscriber.objects.create(issue_id=issue_id, subscriber=actor)
|
||||
|
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
|
||||
from celery import Celery
|
||||
from plane.settings.redis import redis_instance
|
||||
from celery.schedules import crontab
|
||||
|
||||
# Set the default Django settings module for the 'celery' program.
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "plane.settings.production")
|
||||
@ -13,5 +14,15 @@ app = Celery("plane")
|
||||
# pickle the object when using Windows.
|
||||
app.config_from_object("django.conf:settings", namespace="CELERY")
|
||||
|
||||
app.conf.beat_schedule = {
|
||||
# Executes every day at 12 AM
|
||||
"check-every-day-to-archive-and-close": {
|
||||
"task": "plane.bgtasks.issue_automation_task.archive_and_close_old_issues",
|
||||
"schedule": crontab(hour=0, minute=0),
|
||||
},
|
||||
}
|
||||
|
||||
# Load task modules from all registered Django app configs.
|
||||
app.autodiscover_tasks()
|
||||
|
||||
app.conf.beat_scheduler = 'django_celery_beat.schedulers.DatabaseScheduler'
|
@ -28,6 +28,8 @@ class IssueManager(models.Manager):
|
||||
| models.Q(issue_inbox__status=2)
|
||||
| models.Q(issue_inbox__isnull=True)
|
||||
)
|
||||
.filter(archived_at__isnull=True)
|
||||
.exclude(archived_at__isnull=False)
|
||||
)
|
||||
|
||||
|
||||
@ -81,6 +83,7 @@ class Issue(ProjectBaseModel):
|
||||
)
|
||||
sort_order = models.FloatField(default=65535)
|
||||
completed_at = models.DateTimeField(null=True)
|
||||
archived_at = models.DateField(null=True)
|
||||
|
||||
objects = models.Manager()
|
||||
issue_objects = IssueManager()
|
||||
|
@ -4,6 +4,7 @@ from django.conf import settings
|
||||
from django.template.defaultfilters import slugify
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||
|
||||
# Modeule imports
|
||||
from plane.db.mixins import AuditModel
|
||||
@ -74,6 +75,15 @@ class Project(BaseModel):
|
||||
estimate = models.ForeignKey(
|
||||
"db.Estimate", on_delete=models.SET_NULL, related_name="projects", null=True
|
||||
)
|
||||
archive_in = models.IntegerField(
|
||||
default=0, validators=[MinValueValidator(0), MaxValueValidator(12)]
|
||||
)
|
||||
close_in = models.IntegerField(
|
||||
default=0, validators=[MinValueValidator(0), MaxValueValidator(12)]
|
||||
)
|
||||
default_state = models.ForeignKey(
|
||||
"db.State", on_delete=models.SET_NULL, null=True, related_name="default_state"
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
"""Return name of the project"""
|
||||
|
@ -35,6 +35,7 @@ INSTALLED_APPS = [
|
||||
"rest_framework_simplejwt.token_blacklist",
|
||||
"corsheaders",
|
||||
"taggit",
|
||||
"django_celery_beat",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@ -213,3 +214,4 @@ SIMPLE_JWT = {
|
||||
CELERY_TIMEZONE = TIME_ZONE
|
||||
CELERY_TASK_SERIALIZER = 'json'
|
||||
CELERY_ACCEPT_CONTENT = ['application/json']
|
||||
CELERY_IMPORTS = ("plane.bgtasks.issue_automation_task",)
|
||||
|
@ -246,8 +246,9 @@ PROXY_BASE_URL = os.environ.get("PROXY_BASE_URL", False)
|
||||
ANALYTICS_SECRET_KEY = os.environ.get("ANALYTICS_SECRET_KEY", False)
|
||||
ANALYTICS_BASE_API = os.environ.get("ANALYTICS_BASE_API", False)
|
||||
|
||||
OPENAI_API_BASE = os.environ.get("OPENAI_API_BASE", "https://api.openai.com/v1")
|
||||
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", False)
|
||||
GPT_ENGINE = os.environ.get("GPT_ENGINE", "text-davinci-003")
|
||||
GPT_ENGINE = os.environ.get("GPT_ENGINE", "gpt-3.5-turbo")
|
||||
|
||||
SLACK_BOT_TOKEN = os.environ.get("SLACK_BOT_TOKEN", False)
|
||||
|
||||
|
@ -11,10 +11,9 @@ from sentry_sdk.integrations.django import DjangoIntegration
|
||||
from sentry_sdk.integrations.redis import RedisIntegration
|
||||
|
||||
from .common import * # noqa
|
||||
|
||||
# Database
|
||||
DEBUG = int(os.environ.get(
|
||||
"DEBUG", 1
|
||||
)) == 1
|
||||
DEBUG = int(os.environ.get("DEBUG", 1)) == 1
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.postgresql_psycopg2",
|
||||
@ -56,9 +55,7 @@ STORAGES = {
|
||||
|
||||
|
||||
# Make true if running in a docker environment
|
||||
DOCKERIZED = int(os.environ.get(
|
||||
"DOCKERIZED", 0
|
||||
)) == 1
|
||||
DOCKERIZED = int(os.environ.get("DOCKERIZED", 0)) == 1
|
||||
FILE_SIZE_LIMIT = int(os.environ.get("FILE_SIZE_LIMIT", 5242880))
|
||||
USE_MINIO = int(os.environ.get("USE_MINIO", 0)) == 1
|
||||
|
||||
@ -201,15 +198,19 @@ PROXY_BASE_URL = os.environ.get("PROXY_BASE_URL", False)
|
||||
ANALYTICS_SECRET_KEY = os.environ.get("ANALYTICS_SECRET_KEY", False)
|
||||
ANALYTICS_BASE_API = os.environ.get("ANALYTICS_BASE_API", False)
|
||||
|
||||
|
||||
OPENAI_API_BASE = os.environ.get("OPENAI_API_BASE", "https://api.openai.com/v1")
|
||||
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", False)
|
||||
GPT_ENGINE = os.environ.get("GPT_ENGINE", "text-davinci-003")
|
||||
GPT_ENGINE = os.environ.get("GPT_ENGINE", "gpt-3.5-turbo")
|
||||
|
||||
SLACK_BOT_TOKEN = os.environ.get("SLACK_BOT_TOKEN", False)
|
||||
|
||||
LOGGER_BASE_URL = os.environ.get("LOGGER_BASE_URL", False)
|
||||
|
||||
redis_url = os.environ.get("REDIS_URL")
|
||||
broker_url = f"{redis_url}?ssl_cert_reqs={ssl.CERT_NONE.name}&ssl_ca_certs={certifi.where()}"
|
||||
broker_url = (
|
||||
f"{redis_url}?ssl_cert_reqs={ssl.CERT_NONE.name}&ssl_ca_certs={certifi.where()}"
|
||||
)
|
||||
|
||||
CELERY_RESULT_BACKEND = broker_url
|
||||
CELERY_BROKER_URL = broker_url
|
||||
|
@ -29,3 +29,4 @@ channels==4.0.0
|
||||
openai==0.27.8
|
||||
slack-sdk==3.21.3
|
||||
celery==5.3.1
|
||||
django_celery_beat==2.5.0
|
||||
|
@ -164,8 +164,8 @@ export const EmailCodeForm = ({ handleSignIn }: any) => {
|
||||
type="button"
|
||||
className={`mt-5 flex w-full justify-end text-xs outline-none ${
|
||||
isResendDisabled
|
||||
? "cursor-default text-brand-secondary"
|
||||
: "cursor-pointer text-brand-accent"
|
||||
? "cursor-default text-custom-text-200"
|
||||
: "cursor-pointer text-custom-primary"
|
||||
} `}
|
||||
onClick={() => {
|
||||
setIsCodeResending(true);
|
||||
|
@ -80,7 +80,7 @@ export const EmailPasswordForm: React.FC<Props> = ({ onSubmit }) => {
|
||||
<div className="ml-auto text-sm">
|
||||
{isSignUpPage ? (
|
||||
<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.
|
||||
</a>
|
||||
</Link>
|
||||
@ -88,7 +88,7 @@ export const EmailPasswordForm: React.FC<Props> = ({ onSubmit }) => {
|
||||
<button
|
||||
type="button"
|
||||
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?
|
||||
</button>
|
||||
@ -112,7 +112,7 @@ export const EmailPasswordForm: React.FC<Props> = ({ onSubmit }) => {
|
||||
</SecondaryButton>
|
||||
{!isSignUpPage && (
|
||||
<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.
|
||||
</a>
|
||||
</Link>
|
||||
|
@ -39,7 +39,7 @@ export const GithubLoginButton: FC<GithubLoginButtonProps> = (props) => {
|
||||
<Link
|
||||
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" />
|
||||
<span>Sign In with Github</span>
|
||||
</button>
|
||||
|
@ -97,7 +97,7 @@ export const CreateUpdateAnalyticsModal: React.FC<Props> = ({ isOpen, handleClos
|
||||
leaveFrom="opacity-100"
|
||||
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>
|
||||
|
||||
<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"
|
||||
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)}>
|
||||
<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
|
||||
</Dialog.Title>
|
||||
<div className="mt-5">
|
||||
|
@ -61,7 +61,7 @@ export const CustomAnalytics: React.FC<Props> = ({
|
||||
<AnalyticsSelectBar
|
||||
control={control}
|
||||
setValue={setValue}
|
||||
projects={projects}
|
||||
projects={projects ?? []}
|
||||
params={params}
|
||||
fullScreen={fullScreen}
|
||||
isProjectLevel={isProjectLevel}
|
||||
@ -86,7 +86,7 @@ export const CustomAnalytics: React.FC<Props> = ({
|
||||
</div>
|
||||
) : (
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
@ -104,7 +104,7 @@ export const CustomAnalytics: React.FC<Props> = ({
|
||||
)
|
||||
) : (
|
||||
<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>
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<PrimaryButton
|
||||
|
@ -31,7 +31,7 @@ export const CustomTooltip: React.FC<Props> = ({ datum, analytics, params }) =>
|
||||
}
|
||||
|
||||
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
|
||||
className="h-3 w-3 rounded"
|
||||
style={{
|
||||
@ -39,7 +39,7 @@ export const CustomTooltip: React.FC<Props> = ({ datum, analytics, params }) =>
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
className={`font-medium text-brand-secondary ${
|
||||
className={`font-medium text-custom-text-200 ${
|
||||
params.segment
|
||||
? params.segment === "priority" || params.segment === "state__group"
|
||||
? "capitalize"
|
||||
|
@ -111,7 +111,6 @@ export const AnalyticsGraph: React.FC<Props> = ({
|
||||
: undefined,
|
||||
}}
|
||||
theme={{
|
||||
background: "rgb(var(--color-bg-base))",
|
||||
axis: {},
|
||||
}}
|
||||
/>
|
||||
|
@ -29,7 +29,7 @@ export const AnalyticsSelectBar: React.FC<Props> = ({
|
||||
>
|
||||
{!isProjectLevel && (
|
||||
<div>
|
||||
<h6 className="text-xs text-brand-secondary">Project</h6>
|
||||
<h6 className="text-xs text-custom-text-200">Project</h6>
|
||||
<Controller
|
||||
name="project"
|
||||
control={control}
|
||||
@ -40,7 +40,7 @@ export const AnalyticsSelectBar: React.FC<Props> = ({
|
||||
</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
|
||||
name="y_axis"
|
||||
control={control}
|
||||
@ -50,7 +50,7 @@ export const AnalyticsSelectBar: React.FC<Props> = ({
|
||||
/>
|
||||
</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
|
||||
name="x_axis"
|
||||
control={control}
|
||||
@ -67,7 +67,7 @@ export const AnalyticsSelectBar: React.FC<Props> = ({
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h6 className="text-xs text-brand-secondary">Group</h6>
|
||||
<h6 className="text-xs text-custom-text-200">Group</h6>
|
||||
<Controller
|
||||
name="segment"
|
||||
control={control}
|
||||
|
@ -24,13 +24,13 @@ import { ContrastIcon, LayerDiagonalIcon } from "components/icons";
|
||||
// helpers
|
||||
import { renderShortDate } from "helpers/date-time.helper";
|
||||
import { renderEmoji } from "helpers/emoji.helper";
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
// types
|
||||
import {
|
||||
IAnalyticsParams,
|
||||
IAnalyticsResponse,
|
||||
ICurrentUserResponse,
|
||||
IExportAnalyticsFormData,
|
||||
IProject,
|
||||
IWorkspace,
|
||||
} from "types";
|
||||
// fetch-keys
|
||||
@ -179,23 +179,23 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
||||
};
|
||||
|
||||
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 (
|
||||
<div
|
||||
className={`px-5 py-2.5 flex items-center justify-between space-y-2 ${
|
||||
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-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} />
|
||||
{analytics ? analytics.total : "..."} Issues
|
||||
</div>
|
||||
{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" />
|
||||
{renderShortDate(
|
||||
(cycleId
|
||||
@ -207,7 +207,7 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="h-full overflow-hidden">
|
||||
<div className="h-full w-full overflow-hidden">
|
||||
{fullScreen ? (
|
||||
<>
|
||||
{!isProjectLevel && selectedProjects && selectedProjects.length > 0 && (
|
||||
@ -215,10 +215,11 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
||||
<h4 className="font-medium">Selected Projects</h4>
|
||||
<div className="space-y-6 mt-4 h-full overflow-y-auto">
|
||||
{selectedProjects.map((projectId) => {
|
||||
const project: IProject = projects.find((p) => p.id === projectId);
|
||||
const project = projects?.find((p) => p.id === projectId);
|
||||
|
||||
if (project)
|
||||
return (
|
||||
<div key={project.id}>
|
||||
<div key={project.id} className="w-full">
|
||||
<div className="text-sm flex items-center gap-1">
|
||||
{project.emoji ? (
|
||||
<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)}
|
||||
</span>
|
||||
)}
|
||||
<h5 className="break-words">
|
||||
{project.name}
|
||||
<span className="text-brand-secondary text-xs ml-1">
|
||||
<h5 className="flex items-center gap-1">
|
||||
<p className="break-words">{truncateText(project.name, 20)}</p>
|
||||
<span className="text-custom-text-200 text-xs ml-1">
|
||||
({project.identifier})
|
||||
</span>
|
||||
</h5>
|
||||
</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 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>
|
||||
</div>
|
||||
<span className="text-brand-secondary">{project.total_members}</span>
|
||||
<span className="text-custom-text-200">{project.total_members}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-2 text-xs">
|
||||
<div className="flex items-center gap-2">
|
||||
<ContrastIcon height={16} width={16} />
|
||||
<h6>Total cycles</h6>
|
||||
</div>
|
||||
<span className="text-brand-secondary">{project.total_cycles}</span>
|
||||
<span className="text-custom-text-200">{project.total_cycles}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-2 text-xs">
|
||||
<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>
|
||||
</div>
|
||||
<span className="text-brand-secondary">{project.total_modules}</span>
|
||||
<span className="text-custom-text-200">{project.total_modules}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -280,13 +281,13 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
||||
<h4 className="font-medium break-words">Analytics for {cycleDetails.name}</h4>
|
||||
<div className="space-y-4 mt-4">
|
||||
<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>
|
||||
{cycleDetails.owned_by?.first_name} {cycleDetails.owned_by?.last_name}
|
||||
</span>
|
||||
</div>
|
||||
<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>
|
||||
{cycleDetails.start_date && cycleDetails.start_date !== ""
|
||||
? renderShortDate(cycleDetails.start_date)
|
||||
@ -294,7 +295,7 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
||||
</span>
|
||||
</div>
|
||||
<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>
|
||||
{cycleDetails.end_date && 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>
|
||||
<div className="space-y-4 mt-4">
|
||||
<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>
|
||||
{moduleDetails.lead_detail?.first_name}{" "}
|
||||
{moduleDetails.lead_detail?.last_name}
|
||||
</span>
|
||||
</div>
|
||||
<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>
|
||||
{moduleDetails.start_date && moduleDetails.start_date !== ""
|
||||
? renderShortDate(moduleDetails.start_date)
|
||||
@ -323,7 +324,7 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
||||
</span>
|
||||
</div>
|
||||
<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>
|
||||
{moduleDetails.target_date && moduleDetails.target_date !== ""
|
||||
? renderShortDate(moduleDetails.target_date)
|
||||
@ -357,7 +358,7 @@ export const AnalyticsSidebar: React.FC<Props> = ({
|
||||
</div>
|
||||
<div className="space-y-4 mt-4">
|
||||
<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>
|
||||
{
|
||||
NETWORK_CHOICES[
|
||||
|
@ -37,9 +37,9 @@ export const AnalyticsTable: React.FC<Props> = ({ analytics, barGraphData, param
|
||||
<div className="flow-root">
|
||||
<div className="overflow-x-auto">
|
||||
<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">
|
||||
<thead className="bg-brand-surface-2">
|
||||
<tr className="divide-x divide-brand-base text-sm text-brand-base">
|
||||
<table className="min-w-full divide-y divide-custom-border-100 whitespace-nowrap border-y border-custom-border-100">
|
||||
<thead className="bg-custom-background-80">
|
||||
<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">
|
||||
{ANALYTICS_X_AXIS_VALUES.find((v) => v.value === params.x_axis)?.label}
|
||||
</th>
|
||||
@ -80,11 +80,11 @@ export const AnalyticsTable: React.FC<Props> = ({ analytics, barGraphData, param
|
||||
)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-brand-base">
|
||||
<tbody className="divide-y divide-custom-border-100">
|
||||
{barGraphData.data.map((item, index) => (
|
||||
<tr
|
||||
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
|
||||
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 (
|
||||
<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"
|
||||
} ${isOpen ? "right-0" : "-right-full"} duration-300 transition-all`}
|
||||
>
|
||||
<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"
|
||||
}`}
|
||||
>
|
||||
<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">
|
||||
Analytics for{" "}
|
||||
{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">
|
||||
<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)}
|
||||
>
|
||||
{fullScreen ? (
|
||||
@ -178,7 +178,7 @@ export const AnalyticsProjectModal: React.FC<Props> = ({ isOpen, onClose }) => {
|
||||
</button>
|
||||
<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}
|
||||
>
|
||||
<XMarkIcon className="h-4 w-4" />
|
||||
@ -186,13 +186,13 @@ export const AnalyticsProjectModal: React.FC<Props> = ({ isOpen, onClose }) => {
|
||||
</div>
|
||||
</div>
|
||||
<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) => (
|
||||
<Tab
|
||||
key={tab}
|
||||
className={({ selected }) =>
|
||||
`rounded-3xl border border-brand-base px-4 py-2 text-xs hover:bg-brand-surface-2 ${
|
||||
selected ? "bg-brand-surface-2" : ""
|
||||
`rounded-3xl border border-custom-border-100 px-4 py-2 text-xs hover:bg-custom-background-80 ${
|
||||
selected ? "bg-custom-background-80" : ""
|
||||
}`
|
||||
}
|
||||
onClick={() => trackAnalyticsEvent(tab)}
|
||||
|
@ -10,10 +10,10 @@ type Props = {
|
||||
};
|
||||
|
||||
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>
|
||||
<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>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
@ -31,13 +31,13 @@ export const AnalyticsDemand: React.FC<Props> = ({ defaultAnalytics }) => (
|
||||
}}
|
||||
/>
|
||||
<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}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-brand-secondary">{percentage}%</p>
|
||||
<p className="text-custom-text-200">{percentage}%</p>
|
||||
</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
|
||||
className="absolute top-0 left-0 h-1 rounded duration-300"
|
||||
style={{
|
||||
@ -50,8 +50,8 @@ export const AnalyticsDemand: React.FC<Props> = ({ defaultAnalytics }) => (
|
||||
);
|
||||
})}
|
||||
</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">
|
||||
<p className="flex items-center gap-1 text-brand-secondary">
|
||||
<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-custom-text-200">
|
||||
<PlayIcon className="h-4 w-4 -rotate-90" aria-hidden="true" />
|
||||
<span>Estimate Demand:</span>
|
||||
</p>
|
||||
|
@ -10,7 +10,7 @@ type Props = {
|
||||
};
|
||||
|
||||
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>
|
||||
{users.length > 0 ? (
|
||||
<div className="mt-3 space-y-3">
|
||||
@ -33,7 +33,7 @@ export const AnalyticsLeaderboard: React.FC<Props> = ({ users, title }) => (
|
||||
{user.firstName !== "" ? user.firstName[0] : "?"}
|
||||
</div>
|
||||
)}
|
||||
<span className="break-words text-brand-secondary">
|
||||
<span className="break-words text-custom-text-200">
|
||||
{user.firstName !== "" ? `${user.firstName} ${user.lastName}` : "No assignee"}
|
||||
</span>
|
||||
</div>
|
||||
@ -42,7 +42,7 @@ export const AnalyticsLeaderboard: React.FC<Props> = ({ users, title }) => (
|
||||
))}
|
||||
</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>
|
||||
);
|
||||
|
@ -88,7 +88,7 @@ export const ScopeAndDemand: React.FC<Props> = ({ fullScreen = true }) => {
|
||||
)
|
||||
) : (
|
||||
<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>
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<PrimaryButton onClick={() => mutateDefaultAnalytics()}>Refresh</PrimaryButton>
|
||||
|
@ -8,9 +8,9 @@ type Props = {
|
||||
};
|
||||
|
||||
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>
|
||||
<div className="divide-y divide-brand-base">
|
||||
<div className="divide-y divide-custom-border-100">
|
||||
<div>
|
||||
<h6 className="px-3 text-base font-medium">Pending issues</h6>
|
||||
{defaultAnalytics.pending_issue_user.length > 0 ? (
|
||||
@ -27,8 +27,8 @@ export const AnalyticsScope: React.FC<Props> = ({ defaultAnalytics }) => (
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="rounded-md border border-brand-base bg-brand-surface-2 p-2 text-xs">
|
||||
<span className="font-medium text-brand-secondary">
|
||||
<div className="rounded-md border border-custom-border-100 bg-custom-background-80 p-2 text-xs">
|
||||
<span className="font-medium text-custom-text-200">
|
||||
{assignee
|
||||
? assignee.assignees__first_name + " " + assignee.assignees__last_name
|
||||
: "No assignee"}
|
||||
@ -69,12 +69,11 @@ export const AnalyticsScope: React.FC<Props> = ({ defaultAnalytics }) => (
|
||||
}}
|
||||
margin={{ top: 20 }}
|
||||
theme={{
|
||||
background: "rgb(var(--color-bg-base))",
|
||||
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.
|
||||
</div>
|
||||
)}
|
||||
|
@ -15,14 +15,14 @@ export const AnalyticsYearWiseIssues: React.FC<Props> = ({ defaultAnalytics }) =
|
||||
const quarterMonthsList = [startMonth, startMonth + 1, startMonth + 2];
|
||||
|
||||
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>
|
||||
{defaultAnalytics.issue_completed_month_wise.length > 0 ? (
|
||||
<LineGraph
|
||||
data={[
|
||||
{
|
||||
id: "issues_closed",
|
||||
color: "rgb(var(--color-accent))",
|
||||
color: "rgb(var(--color-primary-100))",
|
||||
data: MONTHS_LIST.map((month) => ({
|
||||
x: month.label.substring(0, 3),
|
||||
y:
|
||||
@ -43,19 +43,19 @@ export const AnalyticsYearWiseIssues: React.FC<Props> = ({ defaultAnalytics }) =
|
||||
margin={{ top: 20 }}
|
||||
enableSlices="x"
|
||||
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}
|
||||
<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}
|
||||
</div>
|
||||
)}
|
||||
theme={{
|
||||
background: "rgb(var(--color-bg-base))",
|
||||
background: "rgb(var(--color-background-100))",
|
||||
}}
|
||||
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>
|
||||
);
|
||||
|
@ -15,7 +15,7 @@ export const SelectProject: React.FC<Props> = ({ value, onChange, projects }) =>
|
||||
query: project.name + project.identifier,
|
||||
content: (
|
||||
<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}
|
||||
</div>
|
||||
),
|
||||
|
@ -23,7 +23,7 @@ export const SelectSegment: React.FC<Props> = ({ value, onChange, params }) => {
|
||||
label={
|
||||
<span>
|
||||
{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>
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ export const NotAuthorizedView: React.FC<Props> = ({ actionButton, type }) => {
|
||||
|
||||
return (
|
||||
<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">
|
||||
<Image
|
||||
src={type === "project" ? ProjectNotAuthorizedImg : WorkspaceNotAuthorizedImg}
|
||||
@ -31,16 +31,16 @@ export const NotAuthorizedView: React.FC<Props> = ({ actionButton, type }) => {
|
||||
alt="ProjectSettingImg"
|
||||
/>
|
||||
</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
|
||||
</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 ? (
|
||||
<p>
|
||||
You have signed in as {user.email}. <br />
|
||||
<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>{" "}
|
||||
with different account that has access to this page.
|
||||
</p>
|
||||
@ -48,7 +48,7 @@ export const NotAuthorizedView: React.FC<Props> = ({ actionButton, type }) => {
|
||||
<p>
|
||||
You need to{" "}
|
||||
<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>{" "}
|
||||
with an account that has access to this page.
|
||||
</p>
|
||||
|
@ -41,13 +41,15 @@ export const JoinProject: React.FC = () => {
|
||||
};
|
||||
|
||||
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">
|
||||
<Image src={JoinProjectImg} height="176" width="288" alt="JoinProject" />
|
||||
</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">
|
||||
You are not a member of this project, but you can join this project by clicking the button
|
||||
below.
|
||||
|
@ -11,7 +11,7 @@ export const NotAWorkspaceMember = () => (
|
||||
<div className="space-y-8 text-center">
|
||||
<div className="space-y-2">
|
||||
<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
|
||||
invitation or check your pending invitations.
|
||||
</p>
|
||||
|
@ -17,12 +17,12 @@ const Breadcrumbs = ({ children }: BreadcrumbsProps) => {
|
||||
<div className="flex items-center">
|
||||
<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()}
|
||||
>
|
||||
<Icon
|
||||
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>
|
||||
{children}
|
||||
@ -41,7 +41,7 @@ const BreadcrumbItem: React.FC<BreadcrumbItemProps> = ({ title, link, icon }) =>
|
||||
<>
|
||||
{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" : ""}`}>
|
||||
{icon ?? null}
|
||||
{title}
|
||||
|
@ -34,8 +34,8 @@ export const ChangeInterfaceTheme: React.FC<Props> = ({ setIsPaletteOpen }) => {
|
||||
}}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<SettingIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<SettingIcon className="h-4 w-4 text-custom-text-200" />
|
||||
{theme.label}
|
||||
</div>
|
||||
</Command.Item>
|
||||
|
@ -408,7 +408,7 @@ export const CommandPalette: React.FC = () => {
|
||||
leaveFrom="opacity-100"
|
||||
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>
|
||||
|
||||
<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"
|
||||
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
|
||||
filter={(value, search) => {
|
||||
if (value.toLowerCase().includes(search.toLowerCase())) return 1;
|
||||
@ -444,7 +444,7 @@ export const CommandPalette: React.FC = () => {
|
||||
>
|
||||
{issueId && issueDetails && (
|
||||
<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?.name}
|
||||
</p>
|
||||
@ -452,11 +452,11 @@ export const CommandPalette: React.FC = () => {
|
||||
)}
|
||||
<div className="relative">
|
||||
<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"
|
||||
/>
|
||||
<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}
|
||||
value={searchTerm}
|
||||
onValueChange={(e) => {
|
||||
@ -470,7 +470,7 @@ export const CommandPalette: React.FC = () => {
|
||||
resultsCount === 0 &&
|
||||
searchTerm !== "" &&
|
||||
debouncedSearchTerm !== "" && (
|
||||
<div className="my-4 text-center text-brand-secondary">
|
||||
<div className="my-4 text-center text-custom-text-200">
|
||||
No results found.
|
||||
</div>
|
||||
)}
|
||||
@ -533,9 +533,9 @@ export const CommandPalette: React.FC = () => {
|
||||
value={value}
|
||||
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
|
||||
className="h-4 w-4 text-brand-secondary"
|
||||
className="h-4 w-4 text-custom-text-200"
|
||||
color="#6b7280"
|
||||
/>
|
||||
<p className="block flex-1 truncate">{item.name}</p>
|
||||
@ -562,8 +562,8 @@ export const CommandPalette: React.FC = () => {
|
||||
}}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<Squares2X2Icon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<Squares2X2Icon className="h-4 w-4 text-custom-text-200" />
|
||||
Change state...
|
||||
</div>
|
||||
</Command.Item>
|
||||
@ -575,8 +575,8 @@ export const CommandPalette: React.FC = () => {
|
||||
}}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<ChartBarIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<ChartBarIcon className="h-4 w-4 text-custom-text-200" />
|
||||
Change priority...
|
||||
</div>
|
||||
</Command.Item>
|
||||
@ -588,8 +588,8 @@ export const CommandPalette: React.FC = () => {
|
||||
}}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<UsersIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<UsersIcon className="h-4 w-4 text-custom-text-200" />
|
||||
Assign to...
|
||||
</div>
|
||||
</Command.Item>
|
||||
@ -600,15 +600,15 @@ export const CommandPalette: React.FC = () => {
|
||||
}}
|
||||
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) ? (
|
||||
<>
|
||||
<UserMinusIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<UserMinusIcon className="h-4 w-4 text-custom-text-200" />
|
||||
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
|
||||
</>
|
||||
)}
|
||||
@ -616,8 +616,8 @@ export const CommandPalette: React.FC = () => {
|
||||
</Command.Item>
|
||||
|
||||
<Command.Item onSelect={deleteIssue} className="focus:outline-none">
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<TrashIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<TrashIcon className="h-4 w-4 text-custom-text-200" />
|
||||
Delete issue
|
||||
</div>
|
||||
</Command.Item>
|
||||
@ -628,8 +628,8 @@ export const CommandPalette: React.FC = () => {
|
||||
}}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<LinkIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<LinkIcon className="h-4 w-4 text-custom-text-200" />
|
||||
Copy issue URL to clipboard
|
||||
</div>
|
||||
</Command.Item>
|
||||
@ -638,9 +638,9 @@ export const CommandPalette: React.FC = () => {
|
||||
<Command.Group heading="Issue">
|
||||
<Command.Item
|
||||
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" />
|
||||
Create new issue
|
||||
</div>
|
||||
@ -654,7 +654,7 @@ export const CommandPalette: React.FC = () => {
|
||||
onSelect={createNewProject}
|
||||
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" />
|
||||
Create new project
|
||||
</div>
|
||||
@ -670,7 +670,7 @@ export const CommandPalette: React.FC = () => {
|
||||
onSelect={createNewCycle}
|
||||
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" />
|
||||
Create new cycle
|
||||
</div>
|
||||
@ -683,7 +683,7 @@ export const CommandPalette: React.FC = () => {
|
||||
onSelect={createNewModule}
|
||||
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" />
|
||||
Create new module
|
||||
</div>
|
||||
@ -693,7 +693,7 @@ export const CommandPalette: React.FC = () => {
|
||||
|
||||
<Command.Group heading="View">
|
||||
<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" />
|
||||
Create new view
|
||||
</div>
|
||||
@ -703,7 +703,7 @@ export const CommandPalette: React.FC = () => {
|
||||
|
||||
<Command.Group heading="Page">
|
||||
<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" />
|
||||
Create new page
|
||||
</div>
|
||||
@ -721,7 +721,7 @@ export const CommandPalette: React.FC = () => {
|
||||
}
|
||||
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" />
|
||||
Open inbox
|
||||
</div>
|
||||
@ -740,7 +740,7 @@ export const CommandPalette: React.FC = () => {
|
||||
}}
|
||||
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" />
|
||||
Search settings...
|
||||
</div>
|
||||
@ -751,8 +751,8 @@ export const CommandPalette: React.FC = () => {
|
||||
onSelect={createNewWorkspace}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<FolderPlusIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<FolderPlusIcon className="h-4 w-4 text-custom-text-200" />
|
||||
Create new workspace
|
||||
</div>
|
||||
</Command.Item>
|
||||
@ -764,8 +764,8 @@ export const CommandPalette: React.FC = () => {
|
||||
}}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<SettingIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<SettingIcon className="h-4 w-4 text-custom-text-200" />
|
||||
Change interface theme...
|
||||
</div>
|
||||
</Command.Item>
|
||||
@ -781,8 +781,8 @@ export const CommandPalette: React.FC = () => {
|
||||
}}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<RocketLaunchIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<RocketLaunchIcon className="h-4 w-4 text-custom-text-200" />
|
||||
Open keyboard shortcuts
|
||||
</div>
|
||||
</Command.Item>
|
||||
@ -793,8 +793,8 @@ export const CommandPalette: React.FC = () => {
|
||||
}}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<DocumentIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<DocumentIcon className="h-4 w-4 text-custom-text-200" />
|
||||
Open Plane documentation
|
||||
</div>
|
||||
</Command.Item>
|
||||
@ -805,7 +805,7 @@ export const CommandPalette: React.FC = () => {
|
||||
}}
|
||||
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" />
|
||||
Join our Discord
|
||||
</div>
|
||||
@ -820,7 +820,7 @@ export const CommandPalette: React.FC = () => {
|
||||
}}
|
||||
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" />
|
||||
Report a bug
|
||||
</div>
|
||||
@ -832,8 +832,8 @@ export const CommandPalette: React.FC = () => {
|
||||
}}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<ChatBubbleOvalLeftEllipsisIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<ChatBubbleOvalLeftEllipsisIcon className="h-4 w-4 text-custom-text-200" />
|
||||
Chat with us
|
||||
</div>
|
||||
</Command.Item>
|
||||
@ -847,8 +847,8 @@ export const CommandPalette: React.FC = () => {
|
||||
onSelect={() => redirect(`/${workspaceSlug}/settings`)}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<SettingIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<SettingIcon className="h-4 w-4 text-custom-text-200" />
|
||||
General
|
||||
</div>
|
||||
</Command.Item>
|
||||
@ -856,8 +856,8 @@ export const CommandPalette: React.FC = () => {
|
||||
onSelect={() => redirect(`/${workspaceSlug}/settings/members`)}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<SettingIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<SettingIcon className="h-4 w-4 text-custom-text-200" />
|
||||
Members
|
||||
</div>
|
||||
</Command.Item>
|
||||
@ -865,8 +865,8 @@ export const CommandPalette: React.FC = () => {
|
||||
onSelect={() => redirect(`/${workspaceSlug}/settings/billing`)}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<SettingIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<SettingIcon className="h-4 w-4 text-custom-text-200" />
|
||||
Billing and Plans
|
||||
</div>
|
||||
</Command.Item>
|
||||
@ -874,8 +874,8 @@ export const CommandPalette: React.FC = () => {
|
||||
onSelect={() => redirect(`/${workspaceSlug}/settings/integrations`)}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<SettingIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<SettingIcon className="h-4 w-4 text-custom-text-200" />
|
||||
Integrations
|
||||
</div>
|
||||
</Command.Item>
|
||||
@ -883,8 +883,8 @@ export const CommandPalette: React.FC = () => {
|
||||
onSelect={() => redirect(`/${workspaceSlug}/settings/import-export`)}
|
||||
className="focus:outline-none"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-brand-secondary">
|
||||
<SettingIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
<SettingIcon className="h-4 w-4 text-custom-text-200" />
|
||||
Import/Export
|
||||
</div>
|
||||
</Command.Item>
|
||||
|
@ -85,29 +85,29 @@ export const ShortcutsModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
|
||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<Dialog.Panel className="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">
|
||||
<div className="bg-brand-surface-2 p-5">
|
||||
<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-custom-background-80 p-5">
|
||||
<div className="sm:flex sm:items-start">
|
||||
<div className="flex w-full flex-col gap-y-4 text-center sm:text-left">
|
||||
<Dialog.Title
|
||||
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>
|
||||
<button type="button" onClick={() => setIsOpen(false)}>
|
||||
<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"
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
</Dialog.Title>
|
||||
<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">
|
||||
<MagnifyingGlassIcon className="h-3.5 w-3.5 text-brand-secondary" />
|
||||
<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-custom-text-200" />
|
||||
<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"
|
||||
name="search"
|
||||
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 className="flex flex-col gap-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-sm text-brand-secondary">
|
||||
<p className="text-sm text-custom-text-200">
|
||||
{shortcut.description}
|
||||
</p>
|
||||
<div className="flex items-center gap-x-2.5">
|
||||
{shortcut.keys.split(",").map((key, index) => (
|
||||
<span key={index} className="flex items-center gap-1">
|
||||
{key === "Ctrl" ? (
|
||||
<span className="flex h-full items-center rounded-sm border border-brand-base bg-brand-surface-1 p-1.5">
|
||||
<CommandIcon className="h-4 w-4 fill-current text-brand-secondary" />
|
||||
<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-custom-text-200" />
|
||||
</span>
|
||||
) : key === "Ctrl" ? (
|
||||
<kbd className="rounded-sm border border-brand-base bg-brand-surface-1 p-1.5 text-sm font-medium text-brand-secondary">
|
||||
<CommandIcon className="h-4 w-4 fill-current 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-custom-text-200" />
|
||||
</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}
|
||||
</kbd>
|
||||
)}
|
||||
@ -151,7 +151,7 @@ export const ShortcutsModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
|
||||
))
|
||||
) : (
|
||||
<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{" "}
|
||||
<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">
|
||||
{shortcuts.map(({ keys, description }, index) => (
|
||||
<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">
|
||||
{keys.split(",").map((key, index) => (
|
||||
<span key={index} className="flex items-center gap-1">
|
||||
{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">
|
||||
<CommandIcon className="h-4 w-4 fill-current 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-custom-text-200" />
|
||||
</span>
|
||||
) : key === "Ctrl" ? (
|
||||
<kbd className="rounded-sm border border-brand-base bg-brand-surface-1 p-1.5 text-sm font-medium text-brand-secondary">
|
||||
<CommandIcon className="h-4 w-4 fill-current 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-custom-text-200" />
|
||||
</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}
|
||||
</kbd>
|
||||
)}
|
||||
|
@ -85,7 +85,7 @@ export const AllBoards: React.FC<Props> = ({
|
||||
return (
|
||||
<div
|
||||
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">
|
||||
{currentState &&
|
||||
@ -96,7 +96,7 @@ export const AllBoards: React.FC<Props> = ({
|
||||
: addSpaceIfCamelCase(singleGroup)}
|
||||
</h4>
|
||||
</div>
|
||||
<span className="text-xs text-brand-secondary">0</span>
|
||||
<span className="text-xs text-custom-text-200">0</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
@ -113,7 +113,7 @@ export const BoardHeader: React.FC<Props> = ({
|
||||
return (
|
||||
<div
|
||||
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"}`}>
|
||||
@ -134,7 +134,7 @@ export const BoardHeader: React.FC<Props> = ({
|
||||
<span
|
||||
className={`${
|
||||
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}
|
||||
</span>
|
||||
@ -144,7 +144,7 @@ export const BoardHeader: React.FC<Props> = ({
|
||||
<div className={`flex items-center ${!isCollapsed ? "flex-col pb-2" : ""}`}>
|
||||
<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={() => {
|
||||
setIsCollapsed((prevData) => !prevData);
|
||||
}}
|
||||
@ -158,7 +158,7 @@ export const BoardHeader: React.FC<Props> = ({
|
||||
{!isCompleted && selectedGroup !== "created_by" && (
|
||||
<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}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
|
@ -77,7 +77,9 @@ export const SingleBoard: React.FC<Props> = ({
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
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"}`}
|
||||
ref={provided.innerRef}
|
||||
{...provided.droppableProps}
|
||||
@ -87,12 +89,12 @@ export const SingleBoard: React.FC<Props> = ({
|
||||
<div
|
||||
className={`absolute ${
|
||||
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
|
||||
className={`absolute ${
|
||||
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{" "}
|
||||
{replaceUnderscoreIfSnakeCase(
|
||||
@ -150,7 +152,7 @@ export const SingleBoard: React.FC<Props> = ({
|
||||
{type === "issue" ? (
|
||||
<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}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
@ -162,7 +164,7 @@ export const SingleBoard: React.FC<Props> = ({
|
||||
customButton={
|
||||
<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" />
|
||||
Add Issue
|
||||
|
@ -43,7 +43,7 @@ import {
|
||||
import { LayerDiagonalIcon } from "components/icons";
|
||||
// helpers
|
||||
import { handleIssuesMutation } from "constants/issue";
|
||||
import { copyTextToClipboard, truncateText } from "helpers/string.helper";
|
||||
import { copyTextToClipboard } from "helpers/string.helper";
|
||||
// types
|
||||
import {
|
||||
ICurrentUserResponse,
|
||||
@ -265,8 +265,8 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
||||
</a>
|
||||
</ContextMenu>
|
||||
<div
|
||||
className={`mb-3 rounded bg-brand-base shadow ${
|
||||
snapshot.isDragging ? "border-2 border-brand-accent shadow-lg" : ""
|
||||
className={`mb-3 rounded bg-custom-background-90 shadow ${
|
||||
snapshot.isDragging ? "border-2 border-custom-primary shadow-lg" : ""
|
||||
}`}
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
@ -290,7 +290,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
||||
<CustomMenu
|
||||
customButton={
|
||||
<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)}
|
||||
>
|
||||
<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}`}>
|
||||
<a>
|
||||
{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}
|
||||
</div>
|
||||
)}
|
||||
<h5 className="text-sm group-hover:text-brand-accent break-words line-clamp-3">
|
||||
{issue.name}
|
||||
</h5>
|
||||
<h5 className="text-sm break-words line-clamp-3">{issue.name}</h5>
|
||||
</a>
|
||||
</Link>
|
||||
<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 && (
|
||||
<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}`}>
|
||||
<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" />
|
||||
{issue.sub_issues_count}
|
||||
</div>
|
||||
@ -404,9 +402,9 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
{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}`}>
|
||||
<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" />
|
||||
{issue.link_count}
|
||||
</div>
|
||||
@ -414,9 +412,9 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
{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}`}>
|
||||
<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" />
|
||||
{issue.attachment_count}
|
||||
</div>
|
||||
|
@ -62,7 +62,7 @@ export const CalendarHeader: React.FC<Props> = ({
|
||||
{({ open }) => (
|
||||
<>
|
||||
<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, "yyyy")}</span>
|
||||
</div>
|
||||
@ -77,30 +77,30 @@ export const CalendarHeader: React.FC<Props> = ({
|
||||
leaveFrom="opacity-100 translate-y-0"
|
||||
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">
|
||||
{YEARS_LIST.map((year) => (
|
||||
<button
|
||||
onClick={() => updateDate(updateDateWithYear(year.label, currentDate))}
|
||||
className={` ${
|
||||
isSameYear(year.value, currentDate)
|
||||
? "text-sm font-medium text-brand-base"
|
||||
: "text-xs text-brand-secondary "
|
||||
} hover:text-sm hover:font-medium hover:text-brand-base`}
|
||||
? "text-sm font-medium text-custom-text-100"
|
||||
: "text-xs text-custom-text-200 "
|
||||
} hover:text-sm hover:font-medium hover:text-custom-text-100`}
|
||||
>
|
||||
{year.label}
|
||||
</button>
|
||||
))}
|
||||
</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) => (
|
||||
<button
|
||||
onClick={() =>
|
||||
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)
|
||||
? "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">
|
||||
<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={() => {
|
||||
if (isMonthlyView) {
|
||||
updateDate(new Date());
|
||||
@ -170,7 +170,7 @@ export const CalendarHeader: React.FC<Props> = ({
|
||||
|
||||
<CustomMenu
|
||||
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"}
|
||||
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
||||
</div>
|
||||
@ -181,7 +181,7 @@ export const CalendarHeader: React.FC<Props> = ({
|
||||
setIsMonthlyView(true);
|
||||
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">
|
||||
<span className="flex items-center gap-2">Monthly View</span>
|
||||
@ -198,7 +198,7 @@ export const CalendarHeader: React.FC<Props> = ({
|
||||
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">
|
||||
<span className="flex items-center gap-2">Weekly View</span>
|
||||
@ -207,7 +207,7 @@ export const CalendarHeader: React.FC<Props> = ({
|
||||
/>
|
||||
</div>
|
||||
</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>
|
||||
<ToggleSwitch value={showWeekEnds} onChange={() => setShowWeekEnds(!showWeekEnds)} />
|
||||
</div>
|
||||
|
@ -172,7 +172,7 @@ export const CalendarView: React.FC<Props> = ({
|
||||
return calendarIssues ? (
|
||||
<div className="h-full overflow-y-auto">
|
||||
<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
|
||||
isMonthlyView={isMonthlyView}
|
||||
setIsMonthlyView={setIsMonthlyView}
|
||||
@ -191,7 +191,7 @@ export const CalendarView: React.FC<Props> = ({
|
||||
{weeks.map((date, index) => (
|
||||
<div
|
||||
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
|
||||
? showWeekEnds
|
||||
? (index + 1) % 7 === 0
|
||||
|
@ -49,7 +49,7 @@ export const SingleCalendarDate: React.FC<Props> = ({
|
||||
key={index}
|
||||
ref={provided.innerRef}
|
||||
{...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"
|
||||
} ${
|
||||
showWeekEnds
|
||||
@ -83,7 +83,7 @@ export const SingleCalendarDate: React.FC<Props> = ({
|
||||
{totalIssues > 4 && (
|
||||
<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)}
|
||||
>
|
||||
{showAllIssues ? "Hide" : totalIssues - 4 + " more"}
|
||||
@ -91,13 +91,13 @@ export const SingleCalendarDate: React.FC<Props> = ({
|
||||
)}
|
||||
|
||||
<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
|
||||
className="flex items-center justify-center gap-1 text-center"
|
||||
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
|
||||
</button>
|
||||
</div>
|
||||
|
@ -163,8 +163,8 @@ export const SingleCalendarIssue: React.FC<Props> = ({
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
className={`w-full relative cursor-pointer rounded border border-brand-base px-1.5 py-1.5 text-xs duration-300 hover:cursor-move hover:bg-brand-surface-2 ${
|
||||
snapshot.isDragging ? "bg-brand-surface-2 shadow-lg" : ""
|
||||
className={`w-full relative cursor-pointer rounded border border-custom-border-100 px-1.5 py-1.5 text-xs duration-300 hover:cursor-move hover:bg-custom-background-80 ${
|
||||
snapshot.isDragging ? "bg-custom-background-80 shadow-lg" : ""
|
||||
}`}
|
||||
>
|
||||
<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"
|
||||
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}
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
<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>
|
||||
</a>
|
||||
</Link>
|
||||
@ -267,9 +267,9 @@ export const SingleCalendarIssue: React.FC<Props> = ({
|
||||
/>
|
||||
)}
|
||||
{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}`}>
|
||||
<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" />
|
||||
{issue.sub_issues_count}
|
||||
</div>
|
||||
@ -277,9 +277,9 @@ export const SingleCalendarIssue: React.FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
{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}`}>
|
||||
<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" />
|
||||
{issue.link_count}
|
||||
</div>
|
||||
@ -287,9 +287,9 @@ export const SingleCalendarIssue: React.FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
{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}`}>
|
||||
<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" />
|
||||
{issue.attachment_count}
|
||||
</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: {
|
||||
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: {
|
||||
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: {
|
||||
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: {
|
||||
message: "set the name to",
|
||||
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: {
|
||||
message: "updated the description.",
|
||||
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: {
|
||||
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: {
|
||||
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: {
|
||||
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: {
|
||||
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: {
|
||||
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: {
|
||||
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: {
|
||||
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;
|
||||
value = (
|
||||
<span className="text-brand-secondary">
|
||||
<span className="text-custom-text-200">
|
||||
created{" "}
|
||||
<Link href={`/${workspace_detail.slug}/projects/${project}/issues/${issue}`}>
|
||||
<a className="inline-flex items-center hover:underline">
|
||||
@ -221,9 +221,9 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
||||
</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
|
||||
className="h-3.5 w-3.5 text-brand-secondary"
|
||||
className="h-3.5 w-3.5 text-custom-text-200"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
@ -234,7 +234,7 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
||||
{activity.actor_detail.first_name}
|
||||
{activity.actor_detail.is_bot ? "Bot" : " " + activity.actor_detail.last_name}
|
||||
</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)}
|
||||
</p>
|
||||
</div>
|
||||
@ -247,7 +247,7 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
||||
}
|
||||
editable={false}
|
||||
noBorder
|
||||
customClassName="text-xs border border-brand-base bg-brand-base"
|
||||
customClassName="text-xs border border-custom-border-100 bg-custom-background-100"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -262,7 +262,7 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
||||
<div className="relative pb-1">
|
||||
{activities.length > 1 && activityIdx !== activities.length - 1 ? (
|
||||
<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"
|
||||
/>
|
||||
) : null}
|
||||
@ -271,7 +271,7 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
||||
<div>
|
||||
<div className="relative px-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 ? (
|
||||
activityDetails[activity.field as keyof typeof activityDetails]?.icon
|
||||
) : activity.actor_detail.avatar &&
|
||||
@ -295,7 +295,7 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
{activity.actor_detail.first_name}
|
||||
{activity.actor_detail.is_bot
|
||||
@ -303,7 +303,7 @@ export const Feeds: React.FC<any> = ({ activities }) => (
|
||||
: " " + activity.actor_detail.last_name}
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -96,7 +96,7 @@ export const DueDateFilterModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
||||
leaveFrom="opacity-100"
|
||||
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>
|
||||
<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">
|
||||
@ -109,7 +109,7 @@ export const DueDateFilterModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<Dialog.Panel className="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)}>
|
||||
<div className="flex w-full justify-between">
|
||||
<Controller
|
||||
@ -157,9 +157,9 @@ export const DueDateFilterModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
||||
</div>
|
||||
{watch("filterType") === "range" && (
|
||||
<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 className="text-brand-secondary ml-1">Before:</span>
|
||||
<span className="text-custom-text-200 ml-1">Before:</span>
|
||||
{!isInvalid && <span>{renderShortDateWithYearFormat(watch("date2"))}</span>}
|
||||
</h6>
|
||||
)}
|
||||
|
@ -58,9 +58,9 @@ export const FilterList: React.FC<any> = ({ filters, setFilters }) => {
|
||||
return (
|
||||
<div
|
||||
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)}:
|
||||
</span>
|
||||
{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"
|
||||
: priority === "low"
|
||||
? "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>
|
||||
@ -171,7 +171,7 @@ export const FilterList: React.FC<any> = ({ filters, setFilters }) => {
|
||||
return (
|
||||
<div
|
||||
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} />
|
||||
<span>{member?.first_name}</span>
|
||||
@ -212,7 +212,7 @@ export const FilterList: React.FC<any> = ({ filters, setFilters }) => {
|
||||
return (
|
||||
<div
|
||||
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} />
|
||||
<span>{member?.first_name}</span>
|
||||
@ -310,7 +310,7 @@ export const FilterList: React.FC<any> = ({ filters, setFilters }) => {
|
||||
return (
|
||||
<div
|
||||
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" />
|
||||
<span className="capitalize">
|
||||
@ -381,7 +381,7 @@ export const FilterList: React.FC<any> = ({ filters, setFilters }) => {
|
||||
target_date: null,
|
||||
})
|
||||
}
|
||||
className="flex items-center gap-x-1 rounded-full border border-brand-base bg-brand-surface-2 px-3 py-1.5 text-xs"
|
||||
className="flex items-center gap-x-1 rounded-full border border-custom-border-100 bg-custom-background-80 px-3 py-1.5 text-xs"
|
||||
>
|
||||
<span>Clear all filters</span>
|
||||
<XMarkIcon className="h-3 w-3" />
|
||||
|
@ -23,10 +23,33 @@ import {
|
||||
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
|
||||
import { checkIfArraysHaveSameElements } from "helpers/array.helper";
|
||||
// types
|
||||
import { Properties } from "types";
|
||||
import { Properties, TIssueViewOptions } from "types";
|
||||
// constants
|
||||
import { GROUP_BY_OPTIONS, ORDER_BY_OPTIONS, FILTER_ISSUE_OPTIONS } from "constants/issue";
|
||||
|
||||
const issueViewOptions: { type: TIssueViewOptions; icon: any }[] = [
|
||||
{
|
||||
type: "list",
|
||||
icon: <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 = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, viewId } = router.query;
|
||||
@ -56,53 +79,20 @@ export const IssuesFilterView: React.FC = () => {
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-x-1">
|
||||
{issueViewOptions.map((option) => (
|
||||
<button
|
||||
key={option.type}
|
||||
type="button"
|
||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-brand-surface-2 ${
|
||||
issueView === "list" ? "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 === 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" />
|
||||
</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>
|
||||
{option.icon}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<SelectFilters
|
||||
filters={filters}
|
||||
@ -146,8 +136,10 @@ export const IssuesFilterView: React.FC = () => {
|
||||
{({ open }) => (
|
||||
<>
|
||||
<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 ${
|
||||
open ? "bg-brand-surface-1 text-brand-base" : "text-brand-secondary"
|
||||
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-custom-sidebar-background-90 text-custom-sidebar-text-100"
|
||||
: "text-custom-sidebar-text-200"
|
||||
}`}
|
||||
>
|
||||
View
|
||||
@ -163,13 +155,13 @@ export const IssuesFilterView: React.FC = () => {
|
||||
leaveFrom="opacity-100 translate-y-0"
|
||||
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">
|
||||
<div className="relative divide-y-2 divide-brand-base">
|
||||
<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-custom-border-100">
|
||||
<div className="space-y-4 pb-3 text-xs">
|
||||
{issueView !== "calendar" && issueView !== "spreadsheet" && (
|
||||
<>
|
||||
<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
|
||||
label={
|
||||
GROUP_BY_OPTIONS.find((option) => option.key === groupByProperty)
|
||||
@ -190,7 +182,7 @@ export const IssuesFilterView: React.FC = () => {
|
||||
</CustomMenu>
|
||||
</div>
|
||||
<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
|
||||
label={
|
||||
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">
|
||||
<h4 className="text-brand-secondary">Issue type</h4>
|
||||
<h4 className="text-custom-text-200">Issue type</h4>
|
||||
<CustomMenu
|
||||
label={
|
||||
FILTER_ISSUE_OPTIONS.find((option) => option.key === filters.type)
|
||||
@ -241,7 +233,7 @@ export const IssuesFilterView: React.FC = () => {
|
||||
{issueView !== "calendar" && issueView !== "spreadsheet" && (
|
||||
<>
|
||||
<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
|
||||
value={showEmptyGroups}
|
||||
onChange={() => setShowEmptyGroups(!showEmptyGroups)}
|
||||
@ -253,7 +245,7 @@ export const IssuesFilterView: React.FC = () => {
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="font-medium text-brand-accent"
|
||||
className="font-medium text-custom-primary"
|
||||
onClick={() => setNewFilterDefaultView()}
|
||||
>
|
||||
Set as default
|
||||
@ -264,7 +256,7 @@ export const IssuesFilterView: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<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">
|
||||
{Object.keys(properties).map((key) => {
|
||||
if (key === "estimate" && !isEstimateActive) return null;
|
||||
@ -289,8 +281,8 @@ export const IssuesFilterView: React.FC = () => {
|
||||
type="button"
|
||||
className={`rounded border px-2 py-1 text-xs capitalize ${
|
||||
properties[key as keyof Properties]
|
||||
? "border-brand-accent bg-brand-accent text-white"
|
||||
: "border-brand-base"
|
||||
? "border-custom-primary bg-custom-primary text-white"
|
||||
: "border-custom-border-100"
|
||||
}`}
|
||||
onClick={() => setProperties(key as keyof Properties)}
|
||||
>
|
||||
|
@ -62,7 +62,7 @@ export const ImagePickerPopover: React.FC<Props> = ({ label, value, onChange })
|
||||
return (
|
||||
<Popover className="relative z-[2]" ref={ref}>
|
||||
<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)}
|
||||
>
|
||||
{label}
|
||||
@ -76,16 +76,16 @@ export const ImagePickerPopover: React.FC<Props> = ({ label, value, onChange })
|
||||
leaveFrom="transform opacity-100 scale-100"
|
||||
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">
|
||||
<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]">
|
||||
<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-custom-border-100 bg-custom-background-80 p-5 shadow-2xl sm:max-w-2xl md:w-96 lg:w-[40rem]">
|
||||
<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) => (
|
||||
<Tab
|
||||
key={tab.key}
|
||||
className={({ selected }) =>
|
||||
`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 "./modals";
|
||||
export * from "./spreadsheet-view";
|
||||
export * from "./theme";
|
||||
export * from "./sidebar";
|
||||
export * from "./issues-view";
|
||||
export * from "./image-picker-popover";
|
||||
export * from "./feeds";
|
||||
export * from "./theme-switch";
|
||||
export * from "./custom-theme-selector";
|
||||
export * from "./color-picker-input";
|
||||
|
@ -29,19 +29,13 @@ import {
|
||||
} from "components/core";
|
||||
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
||||
import { CreateUpdateViewModal } from "components/views";
|
||||
import { CycleIssuesGanttChartView, TransferIssues, TransferIssuesModal } from "components/cycles";
|
||||
import { IssueGanttChartView } from "components/issues/gantt-chart";
|
||||
import { TransferIssues, TransferIssuesModal } from "components/cycles";
|
||||
// ui
|
||||
import { EmptySpace, EmptySpaceItem, EmptyState, PrimaryButton, Spinner } from "components/ui";
|
||||
import { EmptyState, PrimaryButton, Spinner } from "components/ui";
|
||||
// icons
|
||||
import {
|
||||
ListBulletIcon,
|
||||
PlusIcon,
|
||||
RectangleStackIcon,
|
||||
TrashIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { PlusIcon, TrashIcon } from "@heroicons/react/24/outline";
|
||||
// images
|
||||
import emptyIssue from "public/empty-state/empty-issue.svg";
|
||||
import emptyIssue from "public/empty-state/issue.svg";
|
||||
// helpers
|
||||
import { getStatesList } from "helpers/state.helper";
|
||||
import { orderArrayBy } from "helpers/array.helper";
|
||||
@ -56,7 +50,6 @@ import {
|
||||
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
||||
STATES_LIST,
|
||||
} from "constants/fetch-keys";
|
||||
import { ModuleIssuesGanttChartView } from "components/modules";
|
||||
|
||||
type Props = {
|
||||
type?: "issue" | "cycle" | "module";
|
||||
@ -107,7 +100,7 @@ export const IssuesView: React.FC<Props> = ({
|
||||
groupByProperty: selectedGroup,
|
||||
orderBy,
|
||||
filters,
|
||||
isNotEmpty,
|
||||
isEmpty,
|
||||
setFilters,
|
||||
params,
|
||||
} = useIssuesView();
|
||||
@ -495,7 +488,7 @@ export const IssuesView: React.FC<Props> = ({
|
||||
{viewId ? "Update" : "Save"} view
|
||||
</PrimaryButton>
|
||||
</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
|
||||
className={`${
|
||||
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" : ""
|
||||
} transition duration-300`}
|
||||
ref={provided.innerRef}
|
||||
@ -517,7 +510,7 @@ export const IssuesView: React.FC<Props> = ({
|
||||
)}
|
||||
</StrictModeDroppable>
|
||||
{groupedByIssues ? (
|
||||
isNotEmpty ? (
|
||||
!isEmpty || issueView === "kanban" || issueView === "calendar" ? (
|
||||
<>
|
||||
{isCompleted && <TransferIssues handleClick={() => setTransferIssuesModal(true)} />}
|
||||
{issueView === "list" ? (
|
||||
@ -584,46 +577,20 @@ export const IssuesView: React.FC<Props> = ({
|
||||
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">
|
||||
<EmptySpace
|
||||
title="You don't have any issue yet."
|
||||
<EmptyState
|
||||
title="Project issues will appear here"
|
||||
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}
|
||||
>
|
||||
<EmptySpaceItem
|
||||
title="Create a new issue"
|
||||
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={() => {
|
||||
image={emptyIssue}
|
||||
buttonText="New Issue"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "c",
|
||||
});
|
||||
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">
|
||||
|
@ -218,7 +218,7 @@ export const SingleListIssue: React.FC<Props> = ({
|
||||
</a>
|
||||
</ContextMenu>
|
||||
<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) => {
|
||||
e.preventDefault();
|
||||
setContextMenu(true);
|
||||
@ -233,13 +233,13 @@ export const SingleListIssue: React.FC<Props> = ({
|
||||
tooltipHeading="Issue 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}
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
<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)}
|
||||
</span>
|
||||
</Tooltip>
|
||||
@ -302,9 +302,9 @@ export const SingleListIssue: React.FC<Props> = ({
|
||||
/>
|
||||
)}
|
||||
{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}`}>
|
||||
<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" />
|
||||
{issue.sub_issues_count}
|
||||
</div>
|
||||
@ -312,9 +312,9 @@ export const SingleListIssue: React.FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
{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}`}>
|
||||
<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" />
|
||||
{issue.link_count}
|
||||
</div>
|
||||
@ -322,9 +322,9 @@ export const SingleListIssue: React.FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
{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}`}>
|
||||
<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" />
|
||||
{issue.attachment_count}
|
||||
</div>
|
||||
|
@ -141,20 +141,20 @@ export const SingleList: React.FC<Props> = ({
|
||||
<Disclosure as="div" defaultOpen>
|
||||
{({ open }) => (
|
||||
<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>
|
||||
<div className="flex items-center gap-x-3">
|
||||
{selectedGroup !== null && (
|
||||
<div className="flex items-center">{getGroupIcon()}</div>
|
||||
)}
|
||||
{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()}
|
||||
</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}
|
||||
</span>
|
||||
</div>
|
||||
@ -162,7 +162,7 @@ export const SingleList: React.FC<Props> = ({
|
||||
{type === "issue" ? (
|
||||
<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}
|
||||
>
|
||||
<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.
|
||||
</p>
|
||||
)
|
||||
|
@ -173,7 +173,7 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
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>
|
||||
<Combobox
|
||||
onChange={(val: string) => {
|
||||
@ -188,12 +188,12 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
|
||||
>
|
||||
<div className="relative m-1">
|
||||
<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"
|
||||
/>
|
||||
<input
|
||||
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..."
|
||||
onChange={(event) => setQuery(event.target.value)}
|
||||
/>
|
||||
@ -201,16 +201,16 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
|
||||
|
||||
<Combobox.Options
|
||||
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 ? (
|
||||
<li className="p-2">
|
||||
{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
|
||||
</h2>
|
||||
)}
|
||||
<ul className="text-sm text-brand-secondary">
|
||||
<ul className="text-sm text-custom-text-200">
|
||||
{filteredIssues.map((issue) => (
|
||||
<Combobox.Option
|
||||
key={issue.id}
|
||||
@ -218,7 +218,7 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
|
||||
value={issue.id}
|
||||
className={({ active, selected }) =>
|
||||
`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">
|
||||
<LayerDiagonalIcon height="56" width="56" />
|
||||
<h3 className="text-brand-secondary">
|
||||
<h3 className="text-custom-text-200">
|
||||
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>
|
||||
</div>
|
||||
)}
|
||||
|
@ -141,7 +141,7 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
||||
leaveFrom="opacity-100"
|
||||
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>
|
||||
|
||||
<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"
|
||||
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
|
||||
as="div"
|
||||
onChange={(val: ISearchIssueResponse) => {
|
||||
@ -165,24 +165,24 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
||||
>
|
||||
<div className="relative m-1">
|
||||
<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"
|
||||
/>
|
||||
<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..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
/>
|
||||
</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 ? (
|
||||
<div className="flex items-center gap-2 flex-wrap mt-1">
|
||||
{selectedIssues.map((issue) => (
|
||||
<div
|
||||
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}
|
||||
<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>
|
||||
</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
|
||||
</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">
|
||||
{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{" "}
|
||||
<span className="text-brand-base">
|
||||
<span className="text-custom-text-100">
|
||||
{'"'}
|
||||
{debouncedSearchTerm}
|
||||
{'"'}
|
||||
@ -225,9 +225,9 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
||||
debouncedSearchTerm !== "" && (
|
||||
<div className="flex flex-col items-center justify-center gap-4 px-3 py-8 text-center">
|
||||
<LayerDiagonalIcon height="52" width="52" />
|
||||
<h3 className="text-brand-secondary">
|
||||
<h3 className="text-custom-text-200">
|
||||
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
|
||||
</pre>
|
||||
.
|
||||
@ -243,7 +243,9 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
||||
<Loader.Item height="40px" />
|
||||
</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) => {
|
||||
const selected = selectedIssues.some((i) => i.id === issue.id);
|
||||
|
||||
@ -254,9 +256,9 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
||||
htmlFor={`issue-${issue.id}`}
|
||||
value={issue}
|
||||
className={({ active }) =>
|
||||
`flex w-full cursor-pointer select-none items-center gap-2 rounded-md px-3 py-2 text-brand-secondary ${
|
||||
active ? "bg-brand-surface-2 text-brand-base" : ""
|
||||
} ${selected ? "text-brand-base" : ""}`
|
||||
`flex w-full cursor-pointer select-none items-center gap-2 rounded-md px-3 py-2 text-custom-text-200 ${
|
||||
active ? "bg-custom-background-80 text-custom-text-100" : ""
|
||||
} ${selected ? "text-custom-text-100" : ""}`
|
||||
}
|
||||
>
|
||||
<input type="checkbox" checked={selected} readOnly />
|
||||
|
@ -143,7 +143,7 @@ export const GptAssistantModal: React.FC<Props> = ({
|
||||
|
||||
return (
|
||||
<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"
|
||||
}`}
|
||||
>
|
||||
|
@ -104,7 +104,7 @@ export const ImageUploadModal: React.FC<Props> = ({
|
||||
leaveFrom="opacity-100"
|
||||
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>
|
||||
|
||||
<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"
|
||||
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">
|
||||
<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
|
||||
</Dialog.Title>
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<div
|
||||
{...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
|
||||
? "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
|
||||
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
|
||||
</button>
|
||||
@ -151,8 +154,8 @@ export const ImageUploadModal: React.FC<Props> = ({
|
||||
</>
|
||||
) : (
|
||||
<div>
|
||||
<UserCircleIcon className="mx-auto h-16 w-16 text-brand-secondary" />
|
||||
<span className="mt-2 block text-sm font-medium 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-custom-text-200">
|
||||
{isDragActive
|
||||
? "Drop image here to upload"
|
||||
: "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"
|
||||
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)}>
|
||||
<div>
|
||||
<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
|
||||
</Dialog.Title>
|
||||
<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">
|
||||
<Link href={link.url}>
|
||||
<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"
|
||||
>
|
||||
<ArrowTopRightOnSquareIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<ArrowTopRightOnSquareIcon className="h-4 w-4 text-custom-text-200" />
|
||||
</a>
|
||||
</Link>
|
||||
<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)}
|
||||
>
|
||||
<TrashIcon className="h-4 w-4" />
|
||||
@ -48,13 +48,16 @@ export const LinksList: React.FC<Props> = ({ links, handleDeleteLink, userAuth }
|
||||
</div>
|
||||
)}
|
||||
<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">
|
||||
<LinkIcon className="h-3.5 w-3.5" />
|
||||
</div>
|
||||
<div>
|
||||
<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)}
|
||||
<br />
|
||||
by{" "}
|
||||
|
@ -119,9 +119,9 @@ const ProgressChart: React.FC<Props> = ({ distribution, startDate, endDate, tota
|
||||
gridXValues={chartData.map((item, index) => (index % 2 === 0 ? item.currentDate : ""))}
|
||||
enableSlices="x"
|
||||
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}
|
||||
<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}
|
||||
</div>
|
||||
)}
|
||||
|
@ -80,16 +80,16 @@ export const SidebarProgressStats: React.FC<Props> = ({
|
||||
<Tab.List
|
||||
as="div"
|
||||
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
|
||||
${module ? "text-xs" : "text-sm"} `}
|
||||
>
|
||||
<Tab
|
||||
className={({ selected }) =>
|
||||
`w-full ${
|
||||
roundedTab ? "rounded-3xl border border-brand-base" : "rounded"
|
||||
} px-3 py-1 text-brand-base ${
|
||||
selected ? " bg-brand-accent text-white" : " hover:bg-brand-surface-2"
|
||||
roundedTab ? "rounded-3xl border border-custom-border-100" : "rounded"
|
||||
} px-3 py-1 text-custom-text-100 ${
|
||||
selected ? " bg-custom-primary text-white" : " hover:bg-custom-background-80"
|
||||
}`
|
||||
}
|
||||
>
|
||||
@ -98,9 +98,9 @@ export const SidebarProgressStats: React.FC<Props> = ({
|
||||
<Tab
|
||||
className={({ selected }) =>
|
||||
`w-full ${
|
||||
roundedTab ? "rounded-3xl border border-brand-base" : "rounded"
|
||||
} px-3 py-1 text-brand-base ${
|
||||
selected ? " bg-brand-accent text-white" : " hover:bg-brand-surface-2"
|
||||
roundedTab ? "rounded-3xl border border-custom-border-100" : "rounded"
|
||||
} px-3 py-1 text-custom-text-100 ${
|
||||
selected ? " bg-custom-primary text-white" : " hover:bg-custom-background-80"
|
||||
}`
|
||||
}
|
||||
>
|
||||
@ -109,16 +109,16 @@ export const SidebarProgressStats: React.FC<Props> = ({
|
||||
<Tab
|
||||
className={({ selected }) =>
|
||||
`w-full ${
|
||||
roundedTab ? "rounded-3xl border border-brand-base" : "rounded"
|
||||
} px-3 py-1 text-brand-base ${
|
||||
selected ? " bg-brand-accent text-white" : " hover:bg-brand-surface-2"
|
||||
roundedTab ? "rounded-3xl border border-custom-border-100" : "rounded"
|
||||
} px-3 py-1 text-custom-text-100 ${
|
||||
selected ? " bg-custom-primary text-white" : " hover:bg-custom-background-80"
|
||||
}`
|
||||
}
|
||||
>
|
||||
States
|
||||
</Tab>
|
||||
</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">
|
||||
{distribution.assignees.map((assignee, index) => {
|
||||
if (assignee.assignee_id)
|
||||
@ -159,7 +159,7 @@ export const SidebarProgressStats: React.FC<Props> = ({
|
||||
key={`unassigned-${index}`}
|
||||
title={
|
||||
<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
|
||||
src="/user.png"
|
||||
height="100%"
|
||||
|
@ -19,8 +19,8 @@ export const SingleProgressStats: React.FC<TSingleProgressStatsProps> = ({
|
||||
}) => (
|
||||
<div
|
||||
className={`flex w-full items-center gap-4 justify-between rounded-sm p-1 text-xs ${
|
||||
onClick ? "cursor-pointer hover:bg-brand-surface-1" : ""
|
||||
} ${selected ? "bg-brand-surface-1" : ""}`}
|
||||
onClick ? "cursor-pointer hover:bg-custom-background-90" : ""
|
||||
} ${selected ? "bg-custom-background-90" : ""}`}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="w-1/2">{title}</div>
|
||||
|
@ -179,12 +179,12 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
|
||||
return (
|
||||
<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 }}
|
||||
>
|
||||
<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="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 && (
|
||||
<span className="flex items-center justify-center opacity-100 group-hover:opacity-0">
|
||||
{issue.project_detail?.identifier}-{issue.sequence_id}
|
||||
@ -198,11 +198,11 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
onInteraction={(nextOpenState) => setIsOpen(nextOpenState)}
|
||||
content={
|
||||
<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
|
||||
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={() => {
|
||||
handleEditIssue(issue);
|
||||
setIsOpen(false);
|
||||
@ -216,7 +216,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
|
||||
<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={() => {
|
||||
handleDeleteIssue(issue);
|
||||
setIsOpen(false);
|
||||
@ -230,7 +230,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
|
||||
<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={() => {
|
||||
handleCopyText();
|
||||
setIsOpen(false);
|
||||
@ -245,7 +245,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
}
|
||||
placement="bottom-start"
|
||||
>
|
||||
<EllipsisHorizontalIcon className="h-5 w-5 text-brand-secondary" />
|
||||
<EllipsisHorizontalIcon className="h-5 w-5 text-custom-text-200" />
|
||||
</Popover2>
|
||||
</div>
|
||||
)}
|
||||
@ -254,7 +254,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
{issue.sub_issues_count > 0 && (
|
||||
<div className="h-6 w-6 flex justify-center items-center">
|
||||
<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)}
|
||||
>
|
||||
<Icon iconName="chevron_right" className={`${expanded ? "rotate-90" : ""}`} />
|
||||
@ -264,13 +264,13 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
</div>
|
||||
|
||||
<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}
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
{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
|
||||
issue={issue}
|
||||
partialUpdateIssue={partialUpdateIssue}
|
||||
@ -284,7 +284,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
{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
|
||||
issue={issue}
|
||||
partialUpdateIssue={partialUpdateIssue}
|
||||
@ -297,7 +297,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
{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
|
||||
issue={issue}
|
||||
partialUpdateIssue={partialUpdateIssue}
|
||||
@ -310,7 +310,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
{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
|
||||
issue={issue}
|
||||
partialUpdateIssue={partialUpdateIssue}
|
||||
@ -324,7 +324,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
)}
|
||||
|
||||
{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
|
||||
issue={issue}
|
||||
partialUpdateIssue={partialUpdateIssue}
|
||||
@ -336,7 +336,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
{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
|
||||
issue={issue}
|
||||
partialUpdateIssue={partialUpdateIssue}
|
||||
|
@ -39,13 +39,15 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
||||
if (col.isActive) {
|
||||
return (
|
||||
<div
|
||||
className={`bg-brand-surface-1 w-full ${
|
||||
col.propertyName === "title" ? "sticky left-0 z-20 bg-brand-surface-1 pl-24" : ""
|
||||
className={`bg-custom-background-90 w-full ${
|
||||
col.propertyName === "title"
|
||||
? "sticky left-0 z-20 bg-custom-background-90 pl-24"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{col.propertyName === "title" ? (
|
||||
<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}
|
||||
</div>
|
||||
@ -54,22 +56,22 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
||||
className="!w-full"
|
||||
customButton={
|
||||
<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 ${
|
||||
activeSortingProperty === col.propertyName ? "bg-brand-surface-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-custom-background-80" : ""
|
||||
}`}
|
||||
>
|
||||
{activeSortingProperty === col.propertyName && (
|
||||
<div className="absolute top-1 right-1.5">
|
||||
<Icon
|
||||
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>
|
||||
)}
|
||||
|
||||
{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" : ""
|
||||
}`}
|
||||
aria-hidden="true"
|
||||
@ -77,7 +79,7 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
||||
width="14"
|
||||
/>
|
||||
) : 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
|
||||
</span>
|
||||
) : (
|
||||
@ -94,7 +96,7 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
||||
<CustomMenu.MenuItem
|
||||
className={`${
|
||||
selectedMenuItem === `${col.ascendingOrder}_${col.propertyName}`
|
||||
? "bg-brand-surface-2"
|
||||
? "bg-custom-background-80"
|
||||
: ""
|
||||
}`}
|
||||
key={col.propertyName}
|
||||
@ -105,8 +107,8 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
||||
<div
|
||||
className={`group flex gap-1.5 px-1 items-center justify-between ${
|
||||
selectedMenuItem === `${col.ascendingOrder}_${col.propertyName}`
|
||||
? "text-brand-base"
|
||||
: "text-brand-secondary hover:text-brand-base"
|
||||
? "text-custom-text-100"
|
||||
: "text-custom-text-200 hover:text-custom-text-100"
|
||||
}`}
|
||||
>
|
||||
<div className="flex gap-2 items-center">
|
||||
@ -166,7 +168,7 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
||||
<CustomMenu.MenuItem
|
||||
className={`mt-0.5 ${
|
||||
selectedMenuItem === `${col.descendingOrder}_${col.propertyName}`
|
||||
? "bg-brand-surface-2"
|
||||
? "bg-custom-background-80"
|
||||
: ""
|
||||
}`}
|
||||
key={col.property}
|
||||
@ -177,8 +179,8 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
||||
<div
|
||||
className={`group flex gap-1.5 px-1 items-center justify-between ${
|
||||
selectedMenuItem === `${col.descendingOrder}_${col.propertyName}`
|
||||
? "text-brand-base"
|
||||
: "text-brand-secondary hover:text-brand-base"
|
||||
? "text-custom-text-100"
|
||||
: "text-custom-text-200 hover:text-custom-text-100"
|
||||
}`}
|
||||
>
|
||||
<div className="flex gap-2 items-center">
|
||||
@ -249,7 +251,7 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
|
||||
<CustomMenu.MenuItem
|
||||
className={`mt-0.5${
|
||||
selectedMenuItem === `-created_at_${col.propertyName}`
|
||||
? "bg-brand-surface-2"
|
||||
? "bg-custom-background-80"
|
||||
: ""
|
||||
}`}
|
||||
key={col.property}
|
||||
|
@ -61,12 +61,12 @@ export const SpreadsheetView: React.FC<Props> = ({
|
||||
.join(" ");
|
||||
|
||||
return (
|
||||
<div className="h-full rounded-lg text-brand-secondary overflow-x-auto whitespace-nowrap bg-brand-base">
|
||||
<div className="sticky z-[2] top-0 border-b border-brand-base bg-brand-surface-1 w-full min-w-max">
|
||||
<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-custom-border-100 bg-custom-background-90 w-full min-w-max">
|
||||
<SpreadsheetColumns columnData={columnData} gridTemplateColumns={gridTemplateColumns} />
|
||||
</div>
|
||||
{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
|
||||
key={`${issue.id}_${index}`}
|
||||
@ -84,12 +84,12 @@ export const SpreadsheetView: React.FC<Props> = ({
|
||||
/>
|
||||
))}
|
||||
<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 }}
|
||||
>
|
||||
{type === "issue" ? (
|
||||
<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={() => {
|
||||
const e = new KeyboardEvent("keydown", { key: "c" });
|
||||
document.dispatchEvent(e);
|
||||
@ -104,7 +104,7 @@ export const SpreadsheetView: React.FC<Props> = ({
|
||||
className="sticky left-0 z-[1]"
|
||||
customButton={
|
||||
<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"
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
|
@ -16,9 +16,11 @@ import { Popover, Transition } from "@headlessui/react";
|
||||
import { Input } from "components/ui";
|
||||
// icons
|
||||
import { ColorPickerIcon } from "components/icons";
|
||||
// types
|
||||
import { ICustomTheme } from "types";
|
||||
|
||||
type Props = {
|
||||
name: string;
|
||||
name: keyof ICustomTheme;
|
||||
watch: UseFormWatch<any>;
|
||||
setValue: UseFormSetValue<any>;
|
||||
error: FieldError | Merge<FieldError, FieldErrorsImpl<any>> | undefined;
|
||||
@ -31,31 +33,25 @@ export const ColorPickerInput: React.FC<Props> = ({ name, watch, setValue, error
|
||||
setValue(name, hex);
|
||||
};
|
||||
|
||||
const getColorText = (colorName: string) => {
|
||||
const getColorText = (colorName: keyof ICustomTheme) => {
|
||||
switch (colorName) {
|
||||
case "accent":
|
||||
return "Accent";
|
||||
case "bgBase":
|
||||
case "background":
|
||||
return "Background";
|
||||
case "bgSurface1":
|
||||
return "Background surface 1";
|
||||
case "bgSurface2":
|
||||
return "Background surface 2";
|
||||
case "border":
|
||||
return "Border";
|
||||
case "sidebar":
|
||||
return "Sidebar";
|
||||
case "textBase":
|
||||
return "Text primary";
|
||||
case "textSecondary":
|
||||
return "Text secondary";
|
||||
case "text":
|
||||
return "Text";
|
||||
case "primary":
|
||||
return "Primary(Theme)";
|
||||
case "sidebarBackground":
|
||||
return "Sidebar Background";
|
||||
case "sidebarText":
|
||||
return "Sidebar Text";
|
||||
default:
|
||||
return "Color";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative ">
|
||||
<div className="relative">
|
||||
<Input
|
||||
id={name}
|
||||
name={name}
|
||||
@ -80,12 +76,12 @@ export const ColorPickerInput: React.FC<Props> = ({ name, watch, setValue, error
|
||||
<Popover.Button
|
||||
type="button"
|
||||
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) !== "" ? (
|
||||
<span
|
||||
className="h-4 w-4 rounded border border-brand-base"
|
||||
className="h-4 w-4 rounded border border-custom-border-100"
|
||||
style={{
|
||||
backgroundColor: `${watch(name)}`,
|
||||
}}
|
||||
@ -94,7 +90,7 @@ export const ColorPickerInput: React.FC<Props> = ({ name, watch, setValue, error
|
||||
<ColorPickerIcon
|
||||
height={14}
|
||||
width={14}
|
||||
className="fill-current text-brand-base"
|
||||
className="fill-current text-custom-text-100"
|
||||
/>
|
||||
)}
|
||||
</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";
|
||||
// ui
|
||||
import { CustomSelect } from "components/ui";
|
||||
// helper
|
||||
import { applyTheme } from "helpers/theme.helper";
|
||||
// types
|
||||
import { ICustomTheme, IUser } from "types";
|
||||
|
||||
@ -79,19 +77,14 @@ export const ThemeSwitch: React.FC<Props> = ({
|
||||
if (!customThemeSelectorOptions) setCustomThemeSelectorOptions(true);
|
||||
} else {
|
||||
if (customThemeSelectorOptions) setCustomThemeSelectorOptions(false);
|
||||
const cssVars = [
|
||||
"--color-bg-base",
|
||||
"--color-bg-surface-1",
|
||||
"--color-bg-surface-2",
|
||||
|
||||
"--color-border",
|
||||
"--color-bg-sidebar",
|
||||
"--color-accent",
|
||||
|
||||
"--color-text-base",
|
||||
"--color-text-secondary",
|
||||
];
|
||||
cssVars.forEach((cssVar) => document.documentElement.style.removeProperty(cssVar));
|
||||
for (let i = 10; i <= 900; i >= 100 ? (i += 100) : (i += 10)) {
|
||||
document.documentElement.style.removeProperty(`--color-background-${i}`);
|
||||
document.documentElement.style.removeProperty(`--color-text-${i}`);
|
||||
document.documentElement.style.removeProperty(`--color-primary-${i}`);
|
||||
document.documentElement.style.removeProperty(`--color-sidebar-background-${i}`);
|
||||
document.documentElement.style.removeProperty(`--color-sidebar-text-${i}`);
|
||||
}
|
||||
}
|
||||
setTheme(value);
|
||||
document.documentElement.style.setProperty("color-scheme", type);
|
@ -110,8 +110,8 @@ export const ActiveCycleDetails: React.FC = () => {
|
||||
|
||||
if (!cycle)
|
||||
return (
|
||||
<div className="flex w-full items-center justify-start rounded-[10px] bg-brand-surface-2 px-6 py-4">
|
||||
<h3 className="text-base font-medium text-brand-base ">No active cycle is present.</h3>
|
||||
<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-custom-text-100 ">No active cycle is present.</h3>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -209,8 +209,8 @@ export const ActiveCycleDetails: React.FC = () => {
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="grid-row-2 grid rounded-[10px] shadow divide-y bg-brand-base border border-brand-base">
|
||||
<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-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-custom-border-100 lg:divide-y-0 lg:divide-x lg:grid-cols-3">
|
||||
<div className="flex flex-col text-xs">
|
||||
<div className="h-full w-full">
|
||||
<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"
|
||||
? "#3F76FF"
|
||||
: cycleStatus === "draft"
|
||||
? "#858E96"
|
||||
? "rgb(var(--color-text-200))"
|
||||
: ""
|
||||
}`}
|
||||
/>
|
||||
@ -300,18 +300,18 @@ export const ActiveCycleDetails: React.FC = () => {
|
||||
handleAddToFavorites();
|
||||
}}
|
||||
>
|
||||
<StarIcon className="h-4 w-4 " color="#858E96" />
|
||||
<StarIcon className="h-4 w-4 " color="rgb(var(--color-text-200))" />
|
||||
</button>
|
||||
)}
|
||||
</span>
|
||||
</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">
|
||||
<CalendarDaysIcon className="h-4 w-4" />
|
||||
<span>{renderShortDateWithYearFormat(startDate)}</span>
|
||||
</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">
|
||||
<TargetIcon className="h-4 w-4" />
|
||||
<span>{renderShortDateWithYearFormat(endDate)}</span>
|
||||
@ -319,7 +319,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<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 !== "" ? (
|
||||
<img
|
||||
src={cycle.owned_by.avatar}
|
||||
@ -329,21 +329,21 @@ export const ActiveCycleDetails: React.FC = () => {
|
||||
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)}
|
||||
</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>
|
||||
|
||||
{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} />
|
||||
</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">
|
||||
<LayerDiagonalIcon className="h-4 w-4 flex-shrink-0" />
|
||||
{cycle.total_issues} issues
|
||||
@ -355,16 +355,16 @@ export const ActiveCycleDetails: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<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
|
||||
</a>
|
||||
</Link>
|
||||
</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="flex h-60 flex-col border-brand-base">
|
||||
<div className="flex h-full w-full flex-col text-brand-secondary p-4">
|
||||
<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-custom-border-100">
|
||||
<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">
|
||||
<span>Progress</span>
|
||||
<LinearProgressIndicator data={progressIndicatorData} />
|
||||
@ -391,22 +391,22 @@ export const ActiveCycleDetails: React.FC = () => {
|
||||
</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} />
|
||||
</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>
|
||||
<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">
|
||||
{issues ? (
|
||||
issues.length > 0 ? (
|
||||
issues.map((issue) => (
|
||||
<div
|
||||
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>
|
||||
@ -414,7 +414,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
||||
tooltipHeading="Issue 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}
|
||||
</span>
|
||||
</Tooltip>
|
||||
@ -424,7 +424,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
||||
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, 30)}
|
||||
</span>
|
||||
</Tooltip>
|
||||
@ -444,7 +444,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
||||
{issue.label_details.map((label) => (
|
||||
<span
|
||||
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
|
||||
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.length > 0 &&
|
||||
Array.isArray(issue.assignees) ? (
|
||||
@ -479,7 +479,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
||||
</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.
|
||||
</div>
|
||||
)
|
||||
@ -495,7 +495,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
||||
|
||||
{issues && issues.length > 0 && (
|
||||
<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
|
||||
className="h-1 rounded-full bg-green-600"
|
||||
style={{
|
||||
@ -510,16 +510,16 @@ export const ActiveCycleDetails: React.FC = () => {
|
||||
}}
|
||||
/>
|
||||
</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?.length}
|
||||
</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-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">
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-[#a9bbd0]" />
|
||||
<span>Ideal</span>
|
||||
@ -531,7 +531,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<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>
|
||||
Pending Issues -{" "}
|
||||
|
@ -48,12 +48,12 @@ export const ActiveCycleProgressStats: React.FC<Props> = ({ cycle }) => {
|
||||
>
|
||||
<Tab.List
|
||||
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
|
||||
className={({ selected }) =>
|
||||
`px-3 py-1 text-brand-base rounded-3xl border border-brand-base ${
|
||||
selected ? " bg-brand-accent text-white" : " hover:bg-brand-surface-2"
|
||||
`px-3 py-1 text-custom-text-100 rounded-3xl border border-custom-border-100 ${
|
||||
selected ? " bg-custom-primary text-white" : " hover:bg-custom-background-80"
|
||||
}`
|
||||
}
|
||||
>
|
||||
@ -61,8 +61,8 @@ export const ActiveCycleProgressStats: React.FC<Props> = ({ cycle }) => {
|
||||
</Tab>
|
||||
<Tab
|
||||
className={({ selected }) =>
|
||||
`px-3 py-1 text-brand-base rounded-3xl border border-brand-base ${
|
||||
selected ? " bg-brand-accent text-white" : " hover:bg-brand-surface-2"
|
||||
`px-3 py-1 text-custom-text-100 rounded-3xl border border-custom-border-100 ${
|
||||
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.Panel
|
||||
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) => {
|
||||
if (assignee.assignee_id)
|
||||
@ -103,7 +103,7 @@ export const ActiveCycleProgressStats: React.FC<Props> = ({ cycle }) => {
|
||||
key={`unassigned-${index}`}
|
||||
title={
|
||||
<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
|
||||
src="/user.png"
|
||||
height="100%"
|
||||
@ -123,7 +123,7 @@ export const ActiveCycleProgressStats: React.FC<Props> = ({ cycle }) => {
|
||||
</Tab.Panel>
|
||||
<Tab.Panel
|
||||
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) => (
|
||||
<SingleProgressStats
|
||||
@ -146,7 +146,7 @@ export const ActiveCycleProgressStats: React.FC<Props> = ({ cycle }) => {
|
||||
</Tab.Panel>
|
||||
</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.
|
||||
</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"
|
||||
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>
|
||||
);
|
||||
|
||||
@ -34,7 +34,7 @@ export const CyclesListGanttChartView: FC<Props> = ({ cycles }) => {
|
||||
<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" }} />
|
||||
<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}
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
@ -19,8 +19,10 @@ import {
|
||||
} from "components/cycles";
|
||||
// ui
|
||||
import { EmptyState, Loader } from "components/ui";
|
||||
// icons
|
||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
// images
|
||||
import emptyCycle from "public/empty-state/empty-cycle.svg";
|
||||
import emptyCycle from "public/empty-state/cycle.svg";
|
||||
// helpers
|
||||
import { getDateRangeStatus } from "helpers/date-time.helper";
|
||||
// types
|
||||
@ -171,10 +173,10 @@ export const CyclesView: React.FC<Props> = ({ cycles, viewType }) => {
|
||||
{cycles ? (
|
||||
cycles.length > 0 ? (
|
||||
viewType === "list" ? (
|
||||
<div className="divide-y divide-brand-base">
|
||||
<div className="divide-y divide-custom-border-100">
|
||||
{cycles.map((cycle) => (
|
||||
<div className="hover:bg-brand-surface-2">
|
||||
<div className="flex flex-col border-brand-base">
|
||||
<div className="hover:bg-custom-background-80">
|
||||
<div className="flex flex-col border-custom-border-100">
|
||||
<SingleCycleList
|
||||
key={cycle.id}
|
||||
cycle={cycle}
|
||||
@ -205,10 +207,17 @@ export const CyclesView: React.FC<Props> = ({ cycles, viewType }) => {
|
||||
)
|
||||
) : (
|
||||
<EmptyState
|
||||
type="cycle"
|
||||
title="Create New Cycle"
|
||||
description="Sprint more effectively with Cycles by confining your project to a fixed amount of time. Create new cycle now."
|
||||
imgURL={emptyCycle}
|
||||
title="Plan your project with cycles"
|
||||
description="Cycle is a custom time period in which a team works to complete items on their backlog."
|
||||
image={emptyCycle}
|
||||
buttonText="New Cycle"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "q",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
/>
|
||||
)
|
||||
) : viewType === "list" ? (
|
||||
|
@ -110,7 +110,7 @@ export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
|
||||
leaveFrom="opacity-100"
|
||||
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>
|
||||
|
||||
<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"
|
||||
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="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">
|
||||
@ -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">
|
||||
<Dialog.Title
|
||||
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
|
||||
</Dialog.Title>
|
||||
<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-{" "}
|
||||
<span className="break-words font-medium text-brand-base">
|
||||
<span className="break-words font-medium text-custom-text-100">
|
||||
{data?.name}
|
||||
</span>
|
||||
? 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 (
|
||||
<form onSubmit={handleSubmit(handleCreateUpdateCycle)}>
|
||||
<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
|
||||
</h3>
|
||||
<div className="space-y-3">
|
||||
@ -107,7 +107,7 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
|
||||
</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>
|
||||
<PrimaryButton type="submit" loading={isSubmitting}>
|
||||
{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"
|
||||
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>
|
||||
);
|
||||
|
||||
@ -41,7 +41,7 @@ export const CycleIssuesGanttChartView: FC<Props> = ({}) => {
|
||||
style={{ backgroundColor: data?.state_detail?.color || "#858e96" }}
|
||||
/>
|
||||
<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}
|
||||
</div>
|
||||
</Tooltip>
|
||||
@ -51,7 +51,7 @@ export const CycleIssuesGanttChartView: FC<Props> = ({}) => {
|
||||
className={`z-[999999]`}
|
||||
>
|
||||
<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
|
||||
</span>
|
||||
</div>
|
||||
|
@ -234,7 +234,7 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
|
||||
leaveFrom="opacity-100"
|
||||
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>
|
||||
<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">
|
||||
@ -247,7 +247,7 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
|
||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<Dialog.Panel className="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
|
||||
handleFormSubmit={handleFormSubmit}
|
||||
handleClose={handleClose}
|
||||
|
@ -66,9 +66,9 @@ export const CycleSelect: React.FC<IssueCycleSelectProps> = ({
|
||||
{({ open }) => (
|
||||
<>
|
||||
<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">
|
||||
{cycles?.find((c) => c.id === value)?.name ?? "Cycles"}
|
||||
</div>
|
||||
@ -82,7 +82,7 @@ export const CycleSelect: React.FC<IssueCycleSelectProps> = ({
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<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">
|
||||
{options ? (
|
||||
@ -100,7 +100,7 @@ export const CycleSelect: React.FC<IssueCycleSelectProps> = ({
|
||||
: ""
|
||||
} ${
|
||||
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}
|
||||
>
|
||||
@ -110,14 +110,14 @@ export const CycleSelect: React.FC<IssueCycleSelectProps> = ({
|
||||
</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
|
||||
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}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4 text-gray-400" aria-hidden="true" />
|
||||
|
@ -292,14 +292,14 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
||||
<div
|
||||
className={`fixed top-[66px] ${
|
||||
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 ? (
|
||||
<>
|
||||
<div className="flex flex-col items-start justify-center">
|
||||
<div className="flex gap-2.5 px-5 text-sm">
|
||||
<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)}
|
||||
</span>
|
||||
</div>
|
||||
@ -309,8 +309,8 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
||||
<>
|
||||
<Popover.Button
|
||||
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 ${
|
||||
cycle.start_date ? "" : "text-brand-secondary"
|
||||
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-custom-text-200"
|
||||
}`}
|
||||
>
|
||||
<CalendarDaysIcon className="h-3 w-3" />
|
||||
@ -352,15 +352,15 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
||||
)}
|
||||
</Popover>
|
||||
<span>
|
||||
<ArrowLongRightIcon className="h-3 w-3 text-brand-secondary" />
|
||||
<ArrowLongRightIcon className="h-3 w-3 text-custom-text-200" />
|
||||
</span>
|
||||
<Popover className="flex h-full items-center justify-center rounded-lg">
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Popover.Button
|
||||
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 ${
|
||||
cycle.end_date ? "" : "text-brand-secondary"
|
||||
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-custom-text-200"
|
||||
}`}
|
||||
>
|
||||
<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 items-start justify-between gap-2">
|
||||
<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}
|
||||
</h4>
|
||||
</div>
|
||||
@ -431,14 +431,14 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
||||
</CustomMenu>
|
||||
</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}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4 text-sm">
|
||||
<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" />
|
||||
<span>Lead</span>
|
||||
</div>
|
||||
@ -457,17 +457,17 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
||||
{cycle.owned_by.first_name.charAt(0)}
|
||||
</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 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" />
|
||||
<span>Progress</span>
|
||||
</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">
|
||||
<ProgressBar value={cycle.completed_issues} maxValue={cycle.total_issues} />
|
||||
</span>
|
||||
@ -477,7 +477,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
||||
</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>
|
||||
{({ open }) => (
|
||||
<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 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 ? (
|
||||
<span className="rounded bg-[#09A953]/10 px-1.5 py-0.5 text-xs text-[#09A953]">
|
||||
{progressPercentage ? `${progressPercentage}%` : ""}
|
||||
@ -506,9 +506,9 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
||||
<ExclamationIcon
|
||||
height={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"
|
||||
? "Cycle is yet to start."
|
||||
: "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-center gap-1">
|
||||
<span>
|
||||
<DocumentIcon className="h-3 w-3 text-brand-secondary" />
|
||||
<DocumentIcon className="h-3 w-3 text-custom-text-200" />
|
||||
</span>
|
||||
<span>
|
||||
Pending Issues -{" "}
|
||||
@ -532,7 +532,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
||||
</span>
|
||||
</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">
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-[#A9BBD0]" />
|
||||
<span>Ideal</span>
|
||||
@ -561,7 +561,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
||||
)}
|
||||
</Disclosure>
|
||||
</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>
|
||||
{({ open }) => (
|
||||
<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 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>
|
||||
|
||||
{cycle.total_issues > 0 ? (
|
||||
@ -584,9 +584,9 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
||||
<ExclamationIcon
|
||||
height={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.
|
||||
</span>
|
||||
</div>
|
||||
|
@ -128,7 +128,7 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
||||
|
||||
return (
|
||||
<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}`}>
|
||||
<a className="w-full">
|
||||
<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"
|
||||
? "#3F76FF"
|
||||
: cycleStatus === "draft"
|
||||
? "#858E96"
|
||||
? "rgb(var(--color-text-200))"
|
||||
: ""
|
||||
}`}
|
||||
/>
|
||||
@ -218,12 +218,12 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
||||
handleAddToFavorites();
|
||||
}}
|
||||
>
|
||||
<StarIcon className="h-4 w-4 " color="#858E96" />
|
||||
<StarIcon className="h-4 w-4 " color="rgb(var(--color-text-200))" />
|
||||
</button>
|
||||
)}
|
||||
</span>
|
||||
</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" && (
|
||||
<>
|
||||
<div className="flex items-start gap-1">
|
||||
@ -240,10 +240,10 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
||||
</div>
|
||||
|
||||
<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="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 !== "" ? (
|
||||
<img
|
||||
src={cycle.owned_by.avatar}
|
||||
@ -253,17 +253,17 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
||||
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)}
|
||||
</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 className="flex h-5 items-center gap-2">
|
||||
<div className="w-16">Members:</div>
|
||||
{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} />
|
||||
</div>
|
||||
) : (
|
||||
@ -279,11 +279,9 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
||||
e.preventDefault();
|
||||
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" />
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
@ -323,7 +321,7 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
||||
<Disclosure>
|
||||
{({ open }) => (
|
||||
<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"
|
||||
}`}
|
||||
>
|
||||
@ -369,7 +367,7 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
||||
</div>
|
||||
<Transition show={open}>
|
||||
<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="space-y-3 text-xs">
|
||||
{stateGroups.map((group) => (
|
||||
@ -389,7 +387,7 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
||||
<div>
|
||||
<span>
|
||||
{cycle[group.key as keyof ICycle] as number}{" "}
|
||||
<span className="text-brand-secondary">
|
||||
<span className="text-custom-text-200">
|
||||
-{" "}
|
||||
{cycle.total_issues > 0
|
||||
? `${Math.round(
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
// hooks
|
||||
@ -152,12 +151,12 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
||||
|
||||
return (
|
||||
<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}`}>
|
||||
<a className="w-full">
|
||||
<div className="flex h-full flex-col gap-4 rounded-b-[10px] p-4">
|
||||
<div className="flex items-center justify-between gap-1">
|
||||
<span className="flex items-start gap-2">
|
||||
<div className="flex items-start gap-2">
|
||||
<ContrastIcon
|
||||
className="mt-1 h-5 w-5"
|
||||
color={`${
|
||||
@ -168,7 +167,7 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
||||
: cycleStatus === "completed"
|
||||
? "#3F76FF"
|
||||
: cycleStatus === "draft"
|
||||
? "#858E96"
|
||||
? "rgb(var(--color-text-200))"
|
||||
: ""
|
||||
}`}
|
||||
/>
|
||||
@ -179,15 +178,15 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
||||
position="top-left"
|
||||
>
|
||||
<h3 className="break-words w-full text-base font-semibold">
|
||||
{truncateText(cycle.name, 70)}
|
||||
{truncateText(cycle.name, 60)}
|
||||
</h3>
|
||||
</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}
|
||||
</p>
|
||||
</div>
|
||||
</span>
|
||||
<span className="flex items-center gap-4 capitalize">
|
||||
</div>
|
||||
<div className="flex-shrink-0 flex items-center gap-4">
|
||||
<span
|
||||
className={`rounded-full px-1.5 py-0.5
|
||||
${
|
||||
@ -203,14 +202,14 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
||||
}`}
|
||||
>
|
||||
{cycleStatus === "current" ? (
|
||||
<span className="flex gap-1">
|
||||
<span className="flex gap-1 whitespace-nowrap">
|
||||
<PersonRunningIcon className="h-4 w-4" />
|
||||
{findHowManyDaysLeft(cycle.end_date ?? new Date())} Days Left
|
||||
{findHowManyDaysLeft(cycle.end_date ?? new Date())} days left
|
||||
</span>
|
||||
) : cycleStatus === "upcoming" ? (
|
||||
<span className="flex gap-1">
|
||||
<AlarmClockIcon className="h-4 w-4" />
|
||||
{findHowManyDaysLeft(cycle.start_date ?? new Date())} Days Left
|
||||
{findHowManyDaysLeft(cycle.start_date ?? new Date())} days left
|
||||
</span>
|
||||
) : cycleStatus === "completed" ? (
|
||||
<span className="flex items-center gap-1">
|
||||
@ -235,20 +234,20 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
||||
</span>
|
||||
|
||||
{cycleStatus !== "draft" && (
|
||||
<div className="flex items-center justify-start gap-2 text-brand-secondary">
|
||||
<div className="flex items-start gap-1 ">
|
||||
<div className="flex items-center justify-start gap-2 text-custom-text-200">
|
||||
<div className="flex items-start gap-1 whitespace-nowrap">
|
||||
<CalendarDaysIcon className="h-4 w-4" />
|
||||
<span>{renderShortDateWithYearFormat(startDate)}</span>
|
||||
</div>
|
||||
<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" />
|
||||
<span>{renderShortDateWithYearFormat(endDate)}</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">
|
||||
{cycle.owned_by.avatar && cycle.owned_by.avatar !== "" ? (
|
||||
<img
|
||||
src={cycle.owned_by.avatar}
|
||||
@ -258,7 +257,7 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
||||
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)}
|
||||
</span>
|
||||
)}
|
||||
@ -287,7 +286,7 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
||||
}`}
|
||||
>
|
||||
{cycleStatus === "current" ? (
|
||||
<span className="flex gap-1">
|
||||
<span className="flex gap-1 whitespace-nowrap">
|
||||
{cycle.total_issues > 0 ? (
|
||||
<>
|
||||
<RadialProgressBar
|
||||
@ -336,7 +335,7 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
||||
handleAddToFavorites();
|
||||
}}
|
||||
>
|
||||
<StarIcon className="h-4 w-4 " color="#858E96" />
|
||||
<StarIcon className="h-4 w-4 " color="rgb(var(--color-text-200))" />
|
||||
</button>
|
||||
)}
|
||||
<div className="flex items-center">
|
||||
@ -380,7 +379,7 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
||||
</CustomMenu.MenuItem>
|
||||
</CustomMenu>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
@ -108,21 +108,21 @@ export const TransferIssuesModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<Dialog.Panel className="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 items-center justify-between px-5">
|
||||
<div className="flex items-center gap-3">
|
||||
<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>
|
||||
<button onClick={handleClose}>
|
||||
<XMarkIcon className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 border-b border-brand-base px-5 pb-3">
|
||||
<MagnifyingGlassIcon className="h-4 w-4 text-brand-secondary" />
|
||||
<div className="flex items-center gap-2 border-b border-custom-border-100 px-5 pb-3">
|
||||
<MagnifyingGlassIcon className="h-4 w-4 text-custom-text-200" />
|
||||
<input
|
||||
className="bg-brand-surface-1 outline-none"
|
||||
className="bg-custom-background-90 outline-none"
|
||||
placeholder="Search for a cycle..."
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
value={query}
|
||||
@ -134,7 +134,7 @@ export const TransferIssuesModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
||||
filteredOptions.map((option: ICycle) => (
|
||||
<button
|
||||
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={() => {
|
||||
transferIssue({
|
||||
new_cycle_id: option?.id,
|
||||
@ -145,7 +145,7 @@ export const TransferIssuesModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
||||
<ContrastIcon className="h-5 w-5" />
|
||||
<div className="flex w-full justify-between">
|
||||
<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)}
|
||||
</span>
|
||||
</div>
|
||||
@ -156,16 +156,16 @@ export const TransferIssuesModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
||||
<ExclamationIcon
|
||||
height={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
|
||||
issues.
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
<p className="text-center text-brand-secondary">Loading...</p>
|
||||
<p className="text-center text-custom-text-200">Loading...</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -38,8 +38,8 @@ export const TransferIssues: React.FC<Props> = ({ handleClick }) => {
|
||||
: 0;
|
||||
return (
|
||||
<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">
|
||||
<ExclamationIcon height={14} width={14} className="fill-current 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-custom-text-200" />
|
||||
<span>Completed cycles are not editable.</span>
|
||||
</div>
|
||||
|
||||
|
@ -30,7 +30,7 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
||||
|
||||
const [isOpen, setIsOpen] = 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[]>([]);
|
||||
|
||||
@ -49,7 +49,7 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
||||
return (
|
||||
<Popover className="relative z-[1]" ref={ref}>
|
||||
<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)}
|
||||
>
|
||||
{label}
|
||||
@ -63,8 +63,8 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
||||
leaveFrom="transform opacity-100 scale-100"
|
||||
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">
|
||||
<div className="h-[230px] w-[250px] overflow-auto rounded-[4px] border border-brand-base bg-brand-surface-2 p-2 shadow-xl">
|
||||
<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-custom-border-100 bg-custom-background-80 p-2 shadow-xl">
|
||||
<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">
|
||||
{tabOptions.map((tab) => (
|
||||
@ -76,7 +76,7 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
||||
setOpenColorPicker(false);
|
||||
}}
|
||||
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}
|
||||
@ -89,7 +89,7 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
||||
<Tab.Panel>
|
||||
{recentEmojis.length > 0 && (
|
||||
<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">
|
||||
{recentEmojis.map((emoji) => (
|
||||
<button
|
||||
@ -107,7 +107,7 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
||||
</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 className="grid grid-cols-8 gap-x-2 gap-y-3">
|
||||
{emojis.map((emoji) => (
|
||||
@ -173,7 +173,7 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
||||
/>
|
||||
</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">
|
||||
{icons.material_rounded.map((icon, index) => (
|
||||
<button
|
||||
|
@ -240,7 +240,7 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
||||
leaveFrom="opacity-100"
|
||||
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>
|
||||
|
||||
<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"
|
||||
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)}>
|
||||
<div className="space-y-3">
|
||||
<div className="text-lg font-medium leading-6">
|
||||
@ -282,9 +282,9 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
||||
</div>
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<div className="flex items-center">
|
||||
<span className="flex h-full items-center rounded-lg bg-brand-surface-2">
|
||||
<span className="rounded-lg px-2 text-sm text-brand-secondary">1</span>
|
||||
<span className="rounded-r-lg bg-brand-base">
|
||||
<span className="flex h-full items-center rounded-lg bg-custom-background-80">
|
||||
<span className="rounded-lg px-2 text-sm text-custom-text-200">1</span>
|
||||
<span className="rounded-r-lg bg-custom-background-100">
|
||||
<Input
|
||||
id="name"
|
||||
name="value1"
|
||||
@ -298,9 +298,9 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="flex h-full items-center rounded-lg bg-brand-surface-2">
|
||||
<span className="rounded-lg px-2 text-sm text-brand-secondary">2</span>
|
||||
<span className="rounded-r-lg bg-brand-base">
|
||||
<span className="flex h-full items-center rounded-lg bg-custom-background-80">
|
||||
<span className="rounded-lg px-2 text-sm text-custom-text-200">2</span>
|
||||
<span className="rounded-r-lg bg-custom-background-100">
|
||||
<Input
|
||||
id="name"
|
||||
name="value2"
|
||||
@ -314,9 +314,9 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="flex h-full items-center rounded-lg bg-brand-surface-2">
|
||||
<span className="rounded-lg px-2 text-sm text-brand-secondary">3</span>
|
||||
<span className="rounded-r-lg bg-brand-base">
|
||||
<span className="flex h-full items-center rounded-lg bg-custom-background-80">
|
||||
<span className="rounded-lg px-2 text-sm text-custom-text-200">3</span>
|
||||
<span className="rounded-r-lg bg-custom-background-100">
|
||||
<Input
|
||||
id="name"
|
||||
name="value3"
|
||||
@ -330,9 +330,9 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="flex h-full items-center rounded-lg bg-brand-surface-2">
|
||||
<span className="rounded-lg px-2 text-sm text-brand-secondary">4</span>
|
||||
<span className="rounded-r-lg bg-brand-base">
|
||||
<span className="flex h-full items-center rounded-lg bg-custom-background-80">
|
||||
<span className="rounded-lg px-2 text-sm text-custom-text-200">4</span>
|
||||
<span className="rounded-r-lg bg-custom-background-100">
|
||||
<Input
|
||||
id="name"
|
||||
name="value4"
|
||||
@ -346,9 +346,9 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="flex h-full items-center rounded-lg bg-brand-surface-2">
|
||||
<span className="rounded-lg px-2 text-sm text-brand-secondary">5</span>
|
||||
<span className="rounded-r-lg bg-brand-base">
|
||||
<span className="flex h-full items-center rounded-lg bg-custom-background-80">
|
||||
<span className="rounded-lg px-2 text-sm text-custom-text-200">5</span>
|
||||
<span className="rounded-r-lg bg-custom-background-100">
|
||||
<Input
|
||||
id="name"
|
||||
name="value5"
|
||||
@ -362,9 +362,9 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="flex h-full items-center rounded-lg bg-brand-surface-2">
|
||||
<span className="rounded-lg px-2 text-sm text-brand-secondary">6</span>
|
||||
<span className="rounded-r-lg bg-brand-base">
|
||||
<span className="flex h-full items-center rounded-lg bg-custom-background-80">
|
||||
<span className="rounded-lg px-2 text-sm text-custom-text-200">6</span>
|
||||
<span className="rounded-r-lg bg-custom-background-100">
|
||||
<Input
|
||||
id="name"
|
||||
name="value6"
|
||||
|
@ -46,7 +46,7 @@ export const DeleteEstimateModal: React.FC<Props> = ({
|
||||
leaveFrom="opacity-100"
|
||||
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>
|
||||
|
||||
<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"
|
||||
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 w-full items-center justify-start gap-6">
|
||||
<span className="place-items-center rounded-full bg-red-500/20 p-4">
|
||||
@ -74,9 +74,11 @@ export const DeleteEstimateModal: React.FC<Props> = ({
|
||||
</span>
|
||||
</div>
|
||||
<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-{" "}
|
||||
<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.
|
||||
This action cannot be undone.
|
||||
</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">
|
||||
{estimate.name}
|
||||
{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
|
||||
</span>
|
||||
)}
|
||||
</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}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{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
|
||||
</SecondaryButton>
|
||||
)}
|
||||
@ -114,11 +117,11 @@ export const SingleEstimate: React.FC<Props> = ({
|
||||
</div>
|
||||
</div>
|
||||
{estimate.points.length > 0 ? (
|
||||
<div className="flex text-xs text-brand-secondary">
|
||||
<div className="flex text-xs text-custom-text-200">
|
||||
Estimate points (
|
||||
<span className="flex gap-1">
|
||||
{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}
|
||||
{index !== estimate.points.length - 1 && ","}{" "}
|
||||
</h6>
|
||||
@ -128,7 +131,7 @@ export const SingleEstimate: React.FC<Props> = ({
|
||||
</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>
|
||||
|
@ -38,13 +38,13 @@ export const GanttChartBlocks: FC<{
|
||||
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="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) : "-"}
|
||||
</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={{
|
||||
width: `${block?.position?.width}px`,
|
||||
}}
|
||||
@ -56,7 +56,7 @@ export const GanttChartBlocks: FC<{
|
||||
</div>
|
||||
|
||||
<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) : "-"}
|
||||
</div>
|
||||
</div>
|
||||
@ -68,11 +68,11 @@ export const GanttChartBlocks: FC<{
|
||||
</div>
|
||||
|
||||
{/* 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.length > 0 &&
|
||||
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)}
|
||||
</div>
|
||||
))}
|
||||
|
@ -7,18 +7,18 @@ export const BiWeekChartView: FC<any> = () => {
|
||||
|
||||
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.length > 0 &&
|
||||
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
||||
<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">
|
||||
{_itemRoot?.title}
|
||||
</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.length > 0 &&
|
||||
_itemRoot.children.map((_item: any, _idx: any) => (
|
||||
@ -29,7 +29,7 @@ export const BiWeekChartView: FC<any> = () => {
|
||||
>
|
||||
<div
|
||||
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>
|
||||
@ -37,7 +37,7 @@ export const BiWeekChartView: FC<any> = () => {
|
||||
<div
|
||||
className={`relative h-full w-full flex-1 flex justify-center ${
|
||||
["sat", "sun"].includes(_item?.dayData?.shortTitle || "")
|
||||
? `bg-brand-surface-2`
|
||||
? `bg-custom-background-80`
|
||||
: ``
|
||||
}`}
|
||||
>
|
||||
|
@ -7,18 +7,18 @@ export const DayChartView: FC<any> = () => {
|
||||
|
||||
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.length > 0 &&
|
||||
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
||||
<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">
|
||||
{_itemRoot?.title}
|
||||
</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.length > 0 &&
|
||||
_itemRoot.children.map((_item: any, _idx: any) => (
|
||||
@ -29,7 +29,7 @@ export const DayChartView: FC<any> = () => {
|
||||
>
|
||||
<div
|
||||
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>
|
||||
|
@ -7,18 +7,18 @@ export const HourChartView: FC<any> = () => {
|
||||
|
||||
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.length > 0 &&
|
||||
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
||||
<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">
|
||||
{_itemRoot?.title}
|
||||
</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.length > 0 &&
|
||||
_itemRoot.children.map((_item: any, _idx: any) => (
|
||||
@ -29,7 +29,7 @@ export const HourChartView: FC<any> = () => {
|
||||
>
|
||||
<div
|
||||
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>
|
||||
|
@ -215,17 +215,19 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
||||
return (
|
||||
<div
|
||||
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` : ``
|
||||
} flex h-full flex-col rounded-sm select-none bg-brand-base shadow`}
|
||||
border ? `border border-custom-border-100` : ``
|
||||
} flex h-full flex-col rounded-sm select-none bg-custom-background-100 shadow`}
|
||||
>
|
||||
{/* 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 && (
|
||||
<div className="text-lg font-medium flex gap-2 items-center">
|
||||
<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
|
||||
</div>
|
||||
</div>
|
||||
@ -242,7 +244,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
||||
{/* 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="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)}
|
||||
>
|
||||
{blocksSidebarView ? (
|
||||
@ -255,7 +257,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
||||
{title && (
|
||||
<div className="text-lg font-medium flex gap-2 items-center">
|
||||
<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
|
||||
</div>
|
||||
</div>
|
||||
@ -277,8 +279,10 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
||||
allViews.map((_chatView: any, _idx: any) => (
|
||||
<div
|
||||
key={_chatView?.key}
|
||||
className={`cursor-pointer rounded-sm border border-brand-base p-1 px-2 text-xs ${
|
||||
currentView === _chatView?.key ? `bg-brand-surface-2` : `hover:bg-brand-surface-1`
|
||||
className={`cursor-pointer rounded-sm border border-custom-border-100 p-1 px-2 text-xs ${
|
||||
currentView === _chatView?.key
|
||||
? `bg-custom-background-80`
|
||||
: `hover:bg-custom-background-90`
|
||||
}`}
|
||||
onClick={() => handleChartView(_chatView?.key)}
|
||||
>
|
||||
@ -289,7 +293,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
||||
|
||||
<div className="flex items-center gap-1">
|
||||
<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}
|
||||
>
|
||||
Today
|
||||
@ -297,7 +301,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
||||
</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)}
|
||||
>
|
||||
{fullScreenMode ? (
|
||||
@ -309,7 +313,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
||||
</div>
|
||||
|
||||
{/* 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
|
||||
className="relative flex h-full w-full flex-1 flex-col overflow-hidden overflow-x-auto"
|
||||
id="scroll-container"
|
||||
|
@ -7,18 +7,18 @@ export const MonthChartView: FC<any> = () => {
|
||||
|
||||
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.length > 0 &&
|
||||
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
||||
<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">
|
||||
{_itemRoot?.title}
|
||||
</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.length > 0 &&
|
||||
_itemRoot.children.map((_item: any, _idx: any) => (
|
||||
@ -29,7 +29,7 @@ export const MonthChartView: FC<any> = () => {
|
||||
>
|
||||
<div
|
||||
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>
|
||||
@ -37,7 +37,7 @@ export const MonthChartView: FC<any> = () => {
|
||||
<div
|
||||
className={`relative h-full w-full flex-1 flex justify-center ${
|
||||
["sat", "sun"].includes(_item?.dayData?.shortTitle || "")
|
||||
? `bg-brand-surface-1`
|
||||
? `bg-custom-background-90`
|
||||
: ``
|
||||
}`}
|
||||
>
|
||||
|
@ -7,18 +7,18 @@ export const QuarterChartView: FC<any> = () => {
|
||||
|
||||
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.length > 0 &&
|
||||
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
||||
<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">
|
||||
{_itemRoot?.title}
|
||||
</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.length > 0 &&
|
||||
_itemRoot.children.map((_item: any, _idx: any) => (
|
||||
@ -29,7 +29,7 @@ export const QuarterChartView: FC<any> = () => {
|
||||
>
|
||||
<div
|
||||
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>
|
||||
|
@ -7,18 +7,18 @@ export const WeekChartView: FC<any> = () => {
|
||||
|
||||
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.length > 0 &&
|
||||
renderView.map((_itemRoot: any, _idxRoot: any) => (
|
||||
<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">
|
||||
{_itemRoot?.title}
|
||||
</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.length > 0 &&
|
||||
_itemRoot.children.map((_item: any, _idx: any) => (
|
||||
@ -29,7 +29,7 @@ export const WeekChartView: FC<any> = () => {
|
||||
>
|
||||
<div
|
||||
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>
|
||||
@ -37,7 +37,7 @@ export const WeekChartView: FC<any> = () => {
|
||||
<div
|
||||
className={`relative h-full w-full flex-1 flex justify-center ${
|
||||
["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