Compare commits

..

4 Commits

Author SHA1 Message Date
Lakhan Baheti 7e8e055676 file formatting 2026-03-04 09:40:32 +05:30
Lakhan e44ccac463 fix: formatting 2024-11-29 14:19:28 +05:30
Lakhan 4dd22845ef fix: avatar url 2024-11-29 14:00:25 +05:30
Lakhan 1a0c9306a1 added relation, estimate property 2024-11-29 13:59:05 +05:30
27 changed files with 2115 additions and 1873 deletions
@@ -22,7 +22,7 @@ export const WorkspaceListItem = observer(({ workspaceId }: TWorkspaceListItemPr
return (
<Link
key={workspaceId}
href={`${WEB_BASE_URL}/${encodeURIComponent(workspace.slug)}`}
href={encodeURI(WEB_BASE_URL + "/" + workspace.slug)}
target="_blank"
className="group flex items-center justify-between p-4 gap-2.5 truncate border border-custom-border-200/70 hover:border-custom-border-200 hover:bg-custom-background-90 rounded-md"
>
+1 -2
View File
@@ -30,8 +30,7 @@ export class WorkspaceService extends APIService {
* @returns Promise<any>
*/
async workspaceSlugCheck(slug: string): Promise<any> {
const params = new URLSearchParams({ slug });
return this.get(`/api/instances/workspace-slug-check/?${params.toString()}`)
return this.get(`/api/instances/workspace-slug-check/?slug=${slug}`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
+3 -3
View File
@@ -14,7 +14,7 @@ export interface IWorkspaceStore {
// computed
workspaceIds: string[];
// helper actions
hydrate: (data: Record<string, IWorkspace>) => void;
hydrate: (data: any) => void;
getWorkspaceById: (workspaceId: string) => IWorkspace | undefined;
// fetch actions
fetchWorkspaces: () => Promise<IWorkspace[]>;
@@ -59,9 +59,9 @@ export class WorkspaceStore implements IWorkspaceStore {
// helper actions
/**
* @description Hydrates the workspaces
* @param data - Record<string, IWorkspace>
* @param data - any
*/
hydrate = (data: Record<string, IWorkspace>) => {
hydrate = (data: any) => {
if (data) this.workspaces = data;
};
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "admin",
"version": "0.24.0",
"version": "0.23.1",
"private": true,
"scripts": {
"dev": "turbo run develop",
+1 -1
View File
@@ -1,4 +1,4 @@
{
"name": "plane-api",
"version": "0.24.0"
"version": "0.23.1"
}
@@ -38,6 +38,22 @@ def release_lock(lock_id):
redis_client = redis_instance()
redis_client.delete(lock_id)
def is_valid_url(url: str) -> bool:
"""Check if URL starts with http:// or https://"""
return url.startswith(("http://", "https://"))
def get_avatar_url(base_host, actor):
# Check if avatar_url is present
if not actor.avatar_url:
return ""
# Check if avatar_url is a valid URL
if is_valid_url(actor.avatar_url):
return actor.avatar_url
# Return the full URL
return f"{base_host}/{actor.avatar_url}"
@shared_task
def stack_email_notification():
@@ -218,7 +234,7 @@ def send_email_notification(
{
"actor_comments": comment,
"actor_detail": {
"avatar_url": f"{base_api}{actor.avatar_url}",
"avatar_url": get_avatar_url(base_api, actor),
"first_name": actor.first_name,
"last_name": actor.last_name,
},
@@ -235,7 +251,7 @@ def send_email_notification(
{
"actor_comments": mention,
"actor_detail": {
"avatar_url": f"{base_api}{actor.avatar_url}",
"avatar_url": get_avatar_url(base_api, actor),
"first_name": actor.first_name,
"last_name": actor.last_name,
},
@@ -251,7 +267,7 @@ def send_email_notification(
template_data.append(
{
"actor_detail": {
"avatar_url": f"{base_api}{actor.avatar_url}",
"avatar_url": get_avatar_url(base_api, actor),
"first_name": actor.first_name,
"last_name": actor.last_name,
},
@@ -18,9 +18,6 @@ class WorkspaceSerializer(BaseSerializer):
# Check if the slug is restricted
if value in RESTRICTED_WORKSPACE_SLUGS:
raise serializers.ValidationError("Slug is not valid")
# Check uniqueness case-insensitively
if Workspace.objects.filter(slug__iexact=value).exists():
raise serializers.ValidationError("Slug is already in use")
return value
class Meta:
@@ -25,7 +25,7 @@ class InstanceWorkSpaceAvailabilityCheckEndpoint(BaseAPIView):
)
workspace = (
Workspace.objects.filter(slug__iexact=slug).exists()
Workspace.objects.filter(slug=slug).exists()
or slug in RESTRICTED_WORKSPACE_SLUGS
)
return Response({"status": not workspace}, status=status.HTTP_200_OK)
+7 -25
View File
@@ -1,33 +1,23 @@
# Python imports
import os
import atexit
# Third party imports
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.instrumentation.django import DjangoInstrumentor
# Global variable to track initialization
_TRACER_PROVIDER = None
import os
def init_tracer():
"""Initialize OpenTelemetry with proper shutdown handling"""
global _TRACER_PROVIDER
# If already initialized, return existing provider
if _TRACER_PROVIDER is not None:
return _TRACER_PROVIDER
# Check if already initialized to prevent double initialization
if trace.get_tracer_provider().__class__.__name__ == "TracerProvider":
return
# Configure the tracer provider
service_name = os.environ.get("SERVICE_NAME", "plane-ce-api")
resource = Resource.create({"service.name": service_name})
tracer_provider = TracerProvider(resource=resource)
# Set as global tracer provider
trace.set_tracer_provider(tracer_provider)
# Configure the OTLP exporter
@@ -39,20 +29,12 @@ def init_tracer():
# Initialize Django instrumentation
DjangoInstrumentor().instrument()
# Store provider globally
_TRACER_PROVIDER = tracer_provider
# Register shutdown handler
atexit.register(shutdown_tracer)
return tracer_provider
def shutdown_tracer():
"""Shutdown OpenTelemetry tracers and processors"""
global _TRACER_PROVIDER
provider = trace.get_tracer_provider()
if _TRACER_PROVIDER is not None:
if hasattr(_TRACER_PROVIDER, "shutdown"):
_TRACER_PROVIDER.shutdown()
_TRACER_PROVIDER = None
if hasattr(provider, "shutdown"):
provider.shutdown()
@@ -180,7 +180,87 @@
{% endif %}
</tr>
</table>
{% endif %}
{% endif %} {% if update.changes.relates_to.new_value %} <!-- Relates to changed -->
<table width="100%" border="0" cellspacing="0" cellpadding="0" style="border-collapse: collapse; margin: 0;margin-bottom:15px; padding: 0; display:inline-block">
<td align="center" valign="middle" style="padding:0; text-align: center; display:inline-block">
<img src="https://plane-marketing.s3.ap-south-1.amazonaws.com/plane-assets/emails/blocking.png" width="12" height="12" border="0" style="margin:0px; padding:0px;margin-right:5px;" />
</td>
<td align="center" valign="middle" style="padding:0; text-align: center;">
<span style="font-size: 0.8rem; font-weight: 500; color: #525252; margin: 0px; display: inline-block;">
Relates to:
</span>
</td>
{% if update.changes.relates_to.new_value.0 %}
<td style="padding-left: 5px;overflow-wrap: break-word;"> {% for relates_to in update.changes.relates_to.new_value|slice:":2" %} <span style=" font-size: 0.8rem; font-weight: 500; color: #3a5bc7; margin-right: 3px; padding-top: 0px; display: inline-block;" > {{ relates_to }} </span> {% endfor %} </td>
{% endif %} {% if update.changes.relates_to.new_value.2 %}
<td> <span style=" font-size: 0.8rem; font-weight: 500; color: #3a5bc7; margin-right: 5px; padding-top: 0px; display: inline-block;" > +{{ update.changes.relates_to.new_value|length|add:"-2" }} more </span> </td>
{% endif %} {% if update.changes.relates_to.old_value.0 %}
<td style="padding-left: 8px;"> {% for relates_to in update.changes.relates_to.old_value|slice:":2" %} <span style=" font-size: 0.8rem; font-weight: 500; color: #641723; margin-right: 3px; padding-top: 0px; text-decoration: line-through; display:inline-block;" > {{ relates_to }} </span> {% endfor %} </td>
{% endif %} {% if update.changes.relates_to.old_value.2 %}
<td> <span style=" font-size: 0.8rem; font-weight: 500; color: #641723; margin-right: 5px; padding-top: 0px; display: inline-block;" > +{{ update.changes.relates_to.old_value|length|add:"-2" }} more </span> </td>
{% endif %}
</table>
{% endif %}{% if update.changes.parent.new_value %} <!-- Parent changed -->
<table width="100%" border="0" cellspacing="0" cellpadding="0" style="border-collapse: collapse; margin: 0;margin-bottom:15px; padding: 0; display:inline-block">
<td align="center" valign="middle" style="padding:0; text-align: center; display:inline-block">
<img src="https://plane-marketing.s3.ap-south-1.amazonaws.com/plane-assets/emails/blocking.png" width="12" height="12" border="0" style="margin:0px; padding:0px;margin-right:5px;" />
</td>
<td align="center" valign="middle" style="padding:0; text-align: center;">
<span style="font-size: 0.8rem; font-weight: 500; color: #525252; margin: 0px; display: inline-block;">
Parent:
</span>
</td>
{% if update.changes.parent.new_value.0 %}
<td style="padding-left: 5px;overflow-wrap: break-word;"> {% for parent in update.changes.parent.new_value|slice:":2" %} <span style=" font-size: 0.8rem; font-weight: 500; color: #3a5bc7; margin-right: 3px; padding-top: 0px; display: inline-block;" > {{ parent }} </span> {% endfor %} </td>
{% endif %} {% if update.changes.parent.new_value.2 %}
<td> <span style=" font-size: 0.8rem; font-weight: 500; color: #3a5bc7; margin-right: 5px; padding-top: 0px; display: inline-block;" > +{{ update.changes.parent.new_value|length|add:"-2" }} more </span> </td>
{% endif %} {% if update.changes.parent.old_value.0 %}
<td style="padding-left: 8px;"> {% for parent in update.changes.parent.old_value|slice:":2" %} <span style=" font-size: 0.8rem; font-weight: 500; color: #641723; margin-right: 3px; padding-top: 0px; text-decoration: line-through; display:inline-block;" > {{ parent }} </span> {% endfor %} </td>
{% endif %} {% if update.changes.parent.old_value.2 %}
<td> <span style=" font-size: 0.8rem; font-weight: 500; color: #641723; margin-right: 5px; padding-top: 0px; display: inline-block;" > +{{ update.changes.parent.old_value|length|add:"-2" }} more </span> </td>
{% endif %}
</table>
{% endif %}{% if update.changes.blocked_by.new_value %} <!-- Blocked by changed -->
<table width="100%" border="0" cellspacing="0" cellpadding="0" style="border-collapse: collapse; margin: 0; margin-bottom:15px; padding: 0; display:inline-block">
<td align="center" valign="middle" style="padding:0; text-align: center; display:inline-block">
<img src="https://plane-marketing.s3.ap-south-1.amazonaws.com/plane-assets/emails/blocking.png" width="12" height="12" border="0" style="margin:0px; padding:0px;margin-right:5px;" />
</td>
<td align="center" valign="middle" style="padding:0; text-align: center;">
<span style="font-size: 0.8rem; font-weight: 500; color: #525252; margin: 0px; display: inline-block;">
Blocked by:
</span>
</td>
{% if update.changes.blocked_by.new_value.0 %}
<td style="padding-left: 5px;overflow-wrap: break-word;"> {% for blocked_by in update.changes.blocked_by.new_value|slice:":2" %} <span style=" font-size: 0.8rem; font-weight: 500; color: #3a5bc7; margin-right: 3px; padding-top: 0px; display: inline-block;" > {{ blocked_by }} </span> {% endfor %} </td>
{% endif %} {% if update.changes.blocked_by.new_value.2 %}
<td> <span style=" font-size: 0.8rem; font-weight: 500; color: #3a5bc7; margin-left: 5px; padding-top: 0px; display: inline-block;" > +{{ update.changes.blocked_by.new_value|length|add:"-2" }} more </span> </td>
{% endif %} {% if update.changes.blocked_by.old_value.0 %}
<td style="padding-left: 8px;"> {% for blocked_by in update.changes.blocked_by.old_value|slice:":2" %} <span style=" font-size: 0.8rem; font-weight: 500; color: #641723; margin-right: 3px; padding-top: 0px; text-decoration: line-through; display:inline-block;" > {{ blocked_by }} </span> {% endfor %} </td>
{% endif %} {% if update.changes.blocked_by.old_value.2 %}
<td> <span style=" font-size: 0.8rem; font-weight: 500; color: #641723; margin-right: 5px; padding-top: 0px; display: inline-block;" > +{{ update.changes.blocked_by.old_value|length|add:"-2" }} more </span> </td>
{% endif %}
</table>
{% endif %}{% if update.changes.estimate_point.new_value %} <!-- Estimate point changed -->
<table width="100%" border="0" cellspacing="0" cellpadding="0" style="border-collapse: collapse; margin: 0;margin-bottom:15px; padding: 0; display:inline-block">
<td align="center" valign="middle" style="padding:0; text-align: center; display:inline-block">
<img src="https://plane-marketing.s3.ap-south-1.amazonaws.com/plane-assets/emails/blocking.png" width="12" height="12" border="0" style="margin:0px; padding:0px;margin-right:5px;" />
</td>
<td align="center" valign="middle" style="padding:0; text-align: center;">
<span style="font-size: 0.8rem; font-weight: 500; color: #525252; margin: 0px; display: inline-block;">
Estimates:
</span>
</td>
{% if update.changes.estimate_point.new_value.0 %}
<td style="padding-left: 5px;overflow-wrap: break-word;"> {% for estimate_point in update.changes.estimate_point.new_value|slice:":2" %} <span style=" font-size: 0.8rem; font-weight: 500; color: #3a5bc7; margin-right: 3px; padding-top: 0px; display: inline-block;" > {{ estimate_point }} </span> {% endfor %} </td>
{% endif %} {% if update.changes.estimate_point.new_value.2 %}
<td> <span style=" font-size: 0.8rem; font-weight: 500; color: #3a5bc7; margin-right: 3px; padding-top: 0px; display: inline-block;" > +{{ update.changes.estimate_point.new_value|length|add:"-2" }} more </span> </td>
{% endif %} {% if update.changes.estimate_point.old_value.0 %}
<td style="padding-left: 8px;"> {% for estimate_point in update.changes.estimate_point.old_value|slice:":2" %} <span style=" font-size: 0.8rem; font-weight: 500; color: #641723; margin-right: 3px; padding-top: 0px; text-decoration: line-through; display:inline-block;" > {{ estimate_point }} </span> {% endfor %} </td>
{% endif %} {% if update.changes.estimate_point.old_value.2 %}
<td> <span style=" font-size: 0.8rem; font-weight: 500; color: #641723; margin-right: 3px; padding-top: 0px; display: inline-block;" > +{{ update.changes.estimate_point.old_value|length|add:"-2" }} more </span> </td>
{% endif %}
</table>
{% endif %}
</div>
</div>
{% endif %} <!-- Outer update Box end --> {% endfor %} {% if comments.0 %} <!-- Comments outer update Box -->
@@ -240,4 +320,4 @@
</table>
</div>
</body>
</html>
</html>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "live",
"version": "0.24.0",
"version": "0.23.1",
"description": "",
"main": "./src/server.ts",
"private": true,
+2 -2
View File
@@ -1,6 +1,6 @@
{
"repository": "https://github.com/makeplane/plane.git",
"version": "0.24.0",
"version": "0.23.1",
"license": "AGPL-3.0",
"private": true,
"workspaces": [
@@ -22,7 +22,7 @@
"devDependencies": {
"prettier": "latest",
"prettier-plugin-tailwindcss": "^0.5.4",
"turbo": "^2.3.3"
"turbo": "^2.3.2"
},
"packageManager": "yarn@1.22.22",
"name": "plane"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@plane/constants",
"version": "0.24.0",
"version": "0.23.1",
"private": true,
"main": "./index.ts"
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@plane/editor",
"version": "0.24.0",
"version": "0.23.1",
"description": "Core Editor that powers Plane",
"private": true,
"main": "./dist/index.mjs",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@plane/eslint-config",
"private": true,
"version": "0.24.0",
"version": "0.23.1",
"files": [
"library.js",
"next.js",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@plane/helpers",
"version": "0.24.0",
"version": "0.23.1",
"description": "Helper functions shared across multiple apps internally",
"private": true,
"main": "./dist/index.js",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "tailwind-config-custom",
"version": "0.24.0",
"version": "0.23.1",
"description": "common tailwind configuration across monorepo",
"main": "index.js",
"private": true,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@plane/types",
"version": "0.24.0",
"version": "0.23.1",
"private": true,
"types": "./src/index.d.ts",
"main": "./src/index.d.ts"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@plane/typescript-config",
"version": "0.24.0",
"version": "0.23.1",
"private": true,
"files": [
"base.json",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "@plane/ui",
"description": "UI components shared across multiple apps internally",
"private": true,
"version": "0.24.0",
"version": "0.23.1",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
+1 -8
View File
@@ -3,14 +3,7 @@ import * as React from "react";
import { ISvgIcons } from "./type";
export const WorkspaceIcon: React.FC<ISvgIcons> = ({ className }) => (
<svg
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
role="img"
aria-label="Workspace icon"
>
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
<path
fillRule="evenodd"
clipRule="evenodd"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "space",
"version": "0.24.0",
"version": "0.23.1",
"private": true,
"scripts": {
"dev": "turbo run develop",
+3
View File
@@ -31,4 +31,7 @@ export const filterActivityOnSelectedFilters = (
): TIssueActivityComment[] =>
activity.filter((activity) => filter.includes(activity.activity_type as TActivityFilters));
// boolean to decide if the local db cache is enabled
export const ENABLE_LOCAL_DB_CACHE = false;
export const ENABLE_ISSUE_DEPENDENCIES = false;
@@ -16,6 +16,7 @@ import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { PlaneVersionNumber } from "@/plane-web/components/global";
import { WorkspaceEditionBadge } from "@/plane-web/components/workspace";
import { ENABLE_LOCAL_DB_CACHE } from "@/plane-web/constants/issues";
export interface WorkspaceHelpSectionProps {
setSidebarActive?: React.Dispatch<React.SetStateAction<boolean>>;
@@ -110,21 +111,23 @@ export const SidebarHelpSection: React.FC<WorkspaceHelpSectionProps> = observer(
</a>
</CustomMenu.MenuItem>
<div className="my-1 border-t border-custom-border-200" />
<CustomMenu.MenuItem>
<div
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
}}
className="flex w-full items-center justify-between text-xs hover:bg-custom-background-80"
>
<span className="racking-tight">Local Cache</span>
<ToggleSwitch
value={canUseLocalDB}
onChange={() => toggleLocalDB(workspaceSlug?.toString(), projectId?.toString())}
/>
</div>
</CustomMenu.MenuItem>
{ENABLE_LOCAL_DB_CACHE && (
<CustomMenu.MenuItem>
<div
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
}}
className="flex w-full items-center justify-between text-xs hover:bg-custom-background-80"
>
<span className="racking-tight">Local Cache</span>
<ToggleSwitch
value={canUseLocalDB}
onChange={() => toggleLocalDB(workspaceSlug?.toString(), projectId?.toString())}
/>
</div>
</CustomMenu.MenuItem>
)}
<CustomMenu.MenuItem>
<button
type="button"
@@ -170,9 +173,8 @@ export const SidebarHelpSection: React.FC<WorkspaceHelpSectionProps> = observer(
<Tooltip tooltipContent={`${isCollapsed ? "Expand" : "Hide"}`} isMobile={isMobile}>
<button
type="button"
className={`grid place-items-center rounded-md p-1 text-custom-text-200 outline-none hover:bg-custom-background-90 hover:text-custom-text-100 ${
isCollapsed ? "w-full" : ""
}`}
className={`grid place-items-center rounded-md p-1 text-custom-text-200 outline-none hover:bg-custom-background-90 hover:text-custom-text-100 ${isCollapsed ? "w-full" : ""
}`}
onClick={() => toggleSidebar()}
>
<MoveLeft className={`h-4 w-4 duration-300 ${isCollapsed ? "rotate-180" : ""}`} />
+2 -1
View File
@@ -9,6 +9,7 @@ import { TUserPermissions } from "@plane/types/src/enums";
import { API_BASE_URL } from "@/helpers/common.helper";
// local
import { persistence } from "@/local-db/storage.sqlite";
import { ENABLE_LOCAL_DB_CACHE } from "@/plane-web/constants/issues";
import { EUserPermissions } from "@/plane-web/constants/user-permissions";
// services
import { AuthService } from "@/services/auth.service";
@@ -277,6 +278,6 @@ export class UserStore implements IUserStore {
}
get localDBEnabled() {
return this.userSettings.canUseLocalDB;
return ENABLE_LOCAL_DB_CACHE && this.userSettings.canUseLocalDB;
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "web",
"version": "0.24.0",
"version": "0.23.1",
"private": true,
"scripts": {
"dev": "turbo run develop",
+1960 -1791
View File
File diff suppressed because it is too large Load Diff