Skip to content

Commit a8de609

Browse files
fix: merge conflicts
Merge branch 'preview' of github.com:makeplane/plane into feat/power-k-v2
2 parents 0a30544 + cf7f891 commit a8de609

44 files changed

Lines changed: 235 additions & 199 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/api/plane/api/serializers/project.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Third party imports
2+
import random
23
from rest_framework import serializers
34

45
# Module imports
@@ -24,6 +25,47 @@ class ProjectCreateSerializer(BaseSerializer):
2425
and workspace association for new project initialization.
2526
"""
2627

28+
PROJECT_ICON_DEFAULT_COLORS = [
29+
"#95999f",
30+
"#6d7b8a",
31+
"#5e6ad2",
32+
"#02b5ed",
33+
"#02b55c",
34+
"#f2be02",
35+
"#e57a00",
36+
"#f38e82",
37+
]
38+
PROJECT_ICON_DEFAULT_ICONS = [
39+
"home",
40+
"apps",
41+
"settings",
42+
"star",
43+
"favorite",
44+
"done",
45+
"check_circle",
46+
"add_task",
47+
"create_new_folder",
48+
"dataset",
49+
"terminal",
50+
"key",
51+
"rocket",
52+
"public",
53+
"quiz",
54+
"mood",
55+
"gavel",
56+
"eco",
57+
"diamond",
58+
"forest",
59+
"bolt",
60+
"sync",
61+
"cached",
62+
"library_add",
63+
"view_timeline",
64+
"view_kanban",
65+
"empty_dashboard",
66+
"cycle",
67+
]
68+
2769
class Meta:
2870
model = Project
2971
fields = [
@@ -44,10 +86,10 @@ class Meta:
4486
"archive_in",
4587
"close_in",
4688
"timezone",
47-
"logo_props",
4889
"external_source",
4990
"external_id",
5091
"is_issue_type_enabled",
92+
"is_time_tracking_enabled",
5193
]
5294

5395
read_only_fields = [
@@ -57,6 +99,7 @@ class Meta:
5799
"updated_at",
58100
"created_by",
59101
"updated_by",
102+
"logo_props",
60103
]
61104

62105
def validate(self, data):
@@ -86,6 +129,16 @@ def create(self, validated_data):
86129
if ProjectIdentifier.objects.filter(name=identifier, workspace_id=self.context["workspace_id"]).exists():
87130
raise serializers.ValidationError(detail="Project Identifier is taken")
88131

132+
if validated_data.get("logo_props", None) is None:
133+
# Generate a random icon and color for the project icon
134+
validated_data["logo_props"] = {
135+
"in_use": "icon",
136+
"icon": {
137+
"name": random.choice(self.PROJECT_ICON_DEFAULT_ICONS),
138+
"color": random.choice(self.PROJECT_ICON_DEFAULT_COLORS),
139+
},
140+
}
141+
89142
project = Project.objects.create(**validated_data, workspace_id=self.context["workspace_id"])
90143
return project
91144

apps/api/plane/app/views/search/base.py

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -367,31 +367,15 @@ def get(self, request, slug):
367367
.order_by("-created_at")
368368
)
369369

370-
if issue_id:
371-
issue_created_by = (
372-
Issue.objects.filter(id=issue_id)
373-
.values_list("created_by_id", flat=True)
374-
.first()
375-
)
376-
users = (
377-
users.filter(Q(role__gt=10) | Q(member_id=issue_created_by))
378-
.distinct()
379-
.values(
380-
"member__avatar_url",
381-
"member__display_name",
382-
"member__id",
383-
)
384-
)
385-
else:
386-
users = (
387-
users.filter(Q(role__gt=10))
388-
.distinct()
389-
.values(
390-
"member__avatar_url",
391-
"member__display_name",
392-
"member__id",
393-
)
370+
users = (
371+
users
372+
.distinct()
373+
.values(
374+
"member__avatar_url",
375+
"member__display_name",
376+
"member__id",
394377
)
378+
)
395379

396380
response_data["user_mention"] = list(users[:count])
397381

apps/web/app/(all)/[workspaceSlug]/(projects)/analytics/[tabId]/page.tsx

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,18 @@ import { useRouter } from "next/navigation";
66
// plane package imports
77
import { EUserPermissions, EUserPermissionsLevel, PROJECT_TRACKER_ELEMENTS } from "@plane/constants";
88
import { useTranslation } from "@plane/i18n";
9+
import { EmptyStateDetailed } from "@plane/propel/empty-state";
910
import { Tabs } from "@plane/ui";
1011
import type { TabItem } from "@plane/ui";
1112
// components
1213
import AnalyticsFilterActions from "@/components/analytics/analytics-filter-actions";
1314
import { PageHead } from "@/components/core/page-title";
14-
import { ComicBoxButton } from "@/components/empty-state/comic-box-button";
15-
import { DetailedEmptyState } from "@/components/empty-state/detailed-empty-state-root";
1615
// hooks
1716
import { captureClick } from "@/helpers/event-tracker.helper";
1817
import { useCommandPalette } from "@/hooks/store/use-command-palette";
1918
import { useProject } from "@/hooks/store/use-project";
2019
import { useWorkspace } from "@/hooks/store/use-workspace";
2120
import { useUserPermissions } from "@/hooks/store/user";
22-
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
2321
import { getAnalyticsTabs } from "@/plane-web/components/analytics/tabs";
2422

2523
type Props = {
@@ -46,9 +44,6 @@ const AnalyticsPage = observer((props: Props) => {
4644
const { currentWorkspace } = useWorkspace();
4745
const { allowPermissions } = useUserPermissions();
4846

49-
// helper hooks
50-
const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/onboarding/analytics" });
51-
5247
// permissions
5348
const canPerformEmptyStateActions = allowPermissions(
5449
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
@@ -96,22 +91,20 @@ const AnalyticsPage = observer((props: Props) => {
9691
/>
9792
</div>
9893
) : (
99-
<DetailedEmptyState
100-
title={t("workspace_analytics.empty_state.general.title")}
101-
description={t("workspace_analytics.empty_state.general.description")}
102-
assetPath={resolvedPath}
103-
customPrimaryButton={
104-
<ComicBoxButton
105-
label={t("workspace_analytics.empty_state.general.primary_button.text")}
106-
title={t("workspace_analytics.empty_state.general.primary_button.comic.title")}
107-
description={t("workspace_analytics.empty_state.general.primary_button.comic.description")}
108-
onClick={() => {
94+
<EmptyStateDetailed
95+
assetKey="project"
96+
title={t("workspace_projects.empty_state.no_projects.title")}
97+
description={t("workspace_projects.empty_state.no_projects.description")}
98+
actions={[
99+
{
100+
label: "Create a project",
101+
onClick: () => {
109102
toggleCreateProjectModal(true);
110103
captureClick({ elementName: PROJECT_TRACKER_ELEMENTS.EMPTY_STATE_CREATE_PROJECT_BUTTON });
111-
}}
112-
disabled={!canPerformEmptyStateActions}
113-
/>
114-
}
104+
},
105+
disabled: !canPerformEmptyStateActions,
106+
},
107+
]}
115108
/>
116109
)}
117110
</>

apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/webhooks/page.tsx

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import useSWR from "swr";
88
import { EUserPermissions, EUserPermissionsLevel, WORKSPACE_SETTINGS_TRACKER_ELEMENTS } from "@plane/constants";
99
import { useTranslation } from "@plane/i18n";
1010
// components
11+
import { EmptyStateCompact } from "@plane/propel/empty-state";
1112
import { NotAuthorizedView } from "@/components/auth-screens/not-authorized-view";
1213
import { PageHead } from "@/components/core/page-title";
13-
import { DetailedEmptyState } from "@/components/empty-state/detailed-empty-state-root";
1414
import { SettingsContentWrapper } from "@/components/settings/content-wrapper";
1515
import { SettingsHeading } from "@/components/settings/heading";
1616
import { WebhookSettingsLoader } from "@/components/ui/loader/settings/web-hook";
@@ -20,7 +20,6 @@ import { captureClick } from "@/helpers/event-tracker.helper";
2020
import { useWebhook } from "@/hooks/store/use-webhook";
2121
import { useWorkspace } from "@/hooks/store/use-workspace";
2222
import { useUserPermissions } from "@/hooks/store/user";
23-
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
2423

2524
const WebhooksListPage = observer(() => {
2625
// states
@@ -35,7 +34,6 @@ const WebhooksListPage = observer(() => {
3534
const { currentWorkspace } = useWorkspace();
3635
// derived values
3736
const canPerformWorkspaceAdminActions = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE);
38-
const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/workspace-settings/webhooks" });
3937

4038
useSWR(
4139
workspaceSlug && canPerformWorkspaceAdminActions ? `WEBHOOKS_LIST_${workspaceSlug}` : null,
@@ -90,21 +88,23 @@ const WebhooksListPage = observer(() => {
9088
) : (
9189
<div className="flex h-full w-full flex-col">
9290
<div className="h-full w-full flex items-center justify-center">
93-
<DetailedEmptyState
94-
className="!p-0"
95-
title=""
96-
description=""
97-
assetPath={resolvedPath}
98-
size="md"
99-
primaryButton={{
100-
text: t("workspace_settings.settings.webhooks.add_webhook"),
101-
onClick: () => {
102-
captureClick({
103-
elementName: WORKSPACE_SETTINGS_TRACKER_ELEMENTS.EMPTY_STATE_ADD_WEBHOOK_BUTTON,
104-
});
105-
setShowCreateWebhookModal(true);
91+
<EmptyStateCompact
92+
assetKey="webhook"
93+
title={t("settings.webhooks.title")}
94+
description={t("settings.webhooks.description")}
95+
actions={[
96+
{
97+
label: t("settings.webhooks.cta_primary"),
98+
onClick: () => {
99+
captureClick({
100+
elementName: WORKSPACE_SETTINGS_TRACKER_ELEMENTS.EMPTY_STATE_ADD_WEBHOOK_BUTTON,
101+
});
102+
setShowCreateWebhookModal(true);
103+
},
106104
},
107-
}}
105+
]}
106+
align="start"
107+
rootClassName="py-20"
108108
/>
109109
</div>
110110
</div>

apps/web/core/components/cycles/archived-cycles/root.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@ import { useParams } from "next/navigation";
44
import useSWR from "swr";
55
// plane imports
66
import { useTranslation } from "@plane/i18n";
7+
import { EmptyStateDetailed } from "@plane/propel/empty-state";
78
import type { TCycleFilters } from "@plane/types";
89
import { calculateTotalFilters } from "@plane/utils";
910
// components
10-
import { DetailedEmptyState } from "@/components/empty-state/detailed-empty-state-root";
1111
import { CycleModuleListLayoutLoader } from "@/components/ui/loader/cycle-module-list-loader";
1212
// hooks
1313
import { useCycle } from "@/hooks/store/use-cycle";
1414
import { useCycleFilter } from "@/hooks/store/use-cycle-filter";
15-
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
1615
// local imports
1716
import { CycleAppliedFiltersList } from "../applied-filters";
1817
import { ArchivedCyclesView } from "./view";
@@ -28,7 +27,6 @@ export const ArchivedCycleLayoutRoot: React.FC = observer(() => {
2827
const { clearAllFilters, currentProjectArchivedFilters, updateFilters } = useCycleFilter();
2928
// derived values
3029
const totalArchivedCycles = currentProjectArchivedCycleIds?.length ?? 0;
31-
const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/archived/empty-cycles" });
3230

3331
useSWR(
3432
workspaceSlug && projectId ? `ARCHIVED_CYCLES_${workspaceSlug.toString()}_${projectId.toString()}` : null,
@@ -69,10 +67,10 @@ export const ArchivedCycleLayoutRoot: React.FC = observer(() => {
6967
)}
7068
{totalArchivedCycles === 0 ? (
7169
<div className="h-full place-items-center">
72-
<DetailedEmptyState
73-
title={t("project_cycles.empty_state.archived.title")}
74-
description={t("project_cycles.empty_state.archived.description")}
75-
assetPath={resolvedPath}
70+
<EmptyStateDetailed
71+
assetKey="archived-cycle"
72+
title={t("workspace.archive_cycles.title")}
73+
description={t("workspace.archive_cycles.description")}
7674
/>
7775
</div>
7876
) : (

apps/web/core/components/exporter/prev-exports.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ import useSWR, { mutate } from "swr";
44
import { MoveLeft, MoveRight, RefreshCw } from "lucide-react";
55
// plane imports
66
import { useTranslation } from "@plane/i18n";
7+
import { EmptyStateCompact } from "@plane/propel/empty-state";
78
import type { IExportData } from "@plane/types";
89
import { Table } from "@plane/ui";
910
// components
10-
import { DetailedEmptyState } from "@/components/empty-state/detailed-empty-state-root";
1111
import { ImportExportSettingsLoader } from "@/components/ui/loader/settings/import-and-export";
1212
// constants
1313
import { EXPORT_SERVICES_LIST } from "@/constants/fetch-keys";
14-
// hooks
15-
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
1614
// services
1715
import { IntegrationService } from "@/services/integrations";
1816
// local imports
@@ -35,7 +33,6 @@ export const PrevExports = observer((props: Props) => {
3533
// hooks
3634
const { t } = useTranslation();
3735
const columns = useExportColumns();
38-
const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/workspace-settings/exports" });
3936

4037
const { data: exporterServices } = useSWR(
4138
workspaceSlug && cursor ? EXPORT_SERVICES_LIST(workspaceSlug as string, cursor, `${per_page}`) : null,
@@ -125,12 +122,12 @@ export const PrevExports = observer((props: Props) => {
125122
</div>
126123
) : (
127124
<div className="flex h-full w-full items-center justify-center">
128-
<DetailedEmptyState
129-
title={t("workspace_settings.empty_state.exports.title")}
130-
description={t("workspace_settings.empty_state.exports.description")}
131-
assetPath={resolvedPath}
132-
className="w-full !px-0"
133-
size="sm"
125+
<EmptyStateCompact
126+
assetKey="export"
127+
title={t("settings.exports.title")}
128+
description={t("settings.exports.description")}
129+
align="start"
130+
rootClassName="py-20"
134131
/>
135132
</div>
136133
)

apps/web/core/components/inbox/sidebar/root.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ export const InboxSidebar: FC<IInboxSidebarProps> = observer((props) => {
137137
{getAppliedFiltersCount > 0 ? (
138138
<EmptyStateDetailed
139139
assetKey="search"
140-
title={t("common.search.title")}
141-
description={t("common.search.description")}
140+
title={t("common_empty_state.search.title")}
141+
description={t("common_empty_state.search.description")}
142142
assetClassName="size-20"
143143
/>
144144
) : currentTab === EInboxIssueCurrentTab.OPEN ? (
@@ -162,6 +162,7 @@ export const InboxSidebar: FC<IInboxSidebarProps> = observer((props) => {
162162
title="No request closed yet"
163163
description="All the work items whether accepted or declined can be found here."
164164
assetClassName="size-20"
165+
className="px-10"
165166
/>
166167
)}
167168
</div>

0 commit comments

Comments
 (0)