Skip to content

Commit b1989ba

Browse files
feat: loading states update (#3639)
* dev: implement layout skeleton loader and helper function * chore: implemented layout loader * chore: settings loader added * chore: cycle, module, view, pages, notification and projects loader added * chore: kanban loader improvement * chore: loader utils updated
1 parent 8313998 commit b1989ba

Some content is hidden

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

51 files changed

+951
-507
lines changed

web/components/cycles/cycles-view.tsx

+20-42
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useCycle } from "hooks/store";
55
// components
66
import { CyclesBoard, CyclesList, CyclesListGanttChartView } from "components/cycles";
77
// ui components
8-
import { Loader } from "@plane/ui";
8+
import { CycleModuleBoardLayout, CycleModuleListLayout, GanttLayoutLoader } from "components/ui";
99
// types
1010
import { TCycleLayout, TCycleView } from "@plane/types";
1111

@@ -25,6 +25,7 @@ export const CyclesView: FC<ICyclesView> = observer((props) => {
2525
currentProjectDraftCycleIds,
2626
currentProjectUpcomingCycleIds,
2727
currentProjectCycleIds,
28+
loader,
2829
} = useCycle();
2930

3031
const cyclesList =
@@ -36,55 +37,32 @@ export const CyclesView: FC<ICyclesView> = observer((props) => {
3637
? currentProjectUpcomingCycleIds
3738
: currentProjectCycleIds;
3839

40+
if (loader || !cyclesList)
41+
return (
42+
<>
43+
{layout === "list" && <CycleModuleListLayout />}
44+
{layout === "board" && <CycleModuleBoardLayout />}
45+
{layout === "gantt" && <GanttLayoutLoader />}
46+
</>
47+
);
48+
3949
return (
4050
<>
4151
{layout === "list" && (
42-
<>
43-
{cyclesList ? (
44-
<CyclesList cycleIds={cyclesList} filter={filter} workspaceSlug={workspaceSlug} projectId={projectId} />
45-
) : (
46-
<Loader className="space-y-4 p-8">
47-
<Loader.Item height="50px" />
48-
<Loader.Item height="50px" />
49-
<Loader.Item height="50px" />
50-
</Loader>
51-
)}
52-
</>
52+
<CyclesList cycleIds={cyclesList} filter={filter} workspaceSlug={workspaceSlug} projectId={projectId} />
5353
)}
5454

5555
{layout === "board" && (
56-
<>
57-
{cyclesList ? (
58-
<CyclesBoard
59-
cycleIds={cyclesList}
60-
filter={filter}
61-
workspaceSlug={workspaceSlug}
62-
projectId={projectId}
63-
peekCycle={peekCycle}
64-
/>
65-
) : (
66-
<Loader className="grid grid-cols-1 gap-9 p-8 md:grid-cols-2 lg:grid-cols-3">
67-
<Loader.Item height="200px" />
68-
<Loader.Item height="200px" />
69-
<Loader.Item height="200px" />
70-
</Loader>
71-
)}
72-
</>
56+
<CyclesBoard
57+
cycleIds={cyclesList}
58+
filter={filter}
59+
workspaceSlug={workspaceSlug}
60+
projectId={projectId}
61+
peekCycle={peekCycle}
62+
/>
7363
)}
7464

75-
{layout === "gantt" && (
76-
<>
77-
{cyclesList ? (
78-
<CyclesListGanttChartView cycleIds={cyclesList} workspaceSlug={workspaceSlug} />
79-
) : (
80-
<Loader className="space-y-4">
81-
<Loader.Item height="50px" />
82-
<Loader.Item height="50px" />
83-
<Loader.Item height="50px" />
84-
</Loader>
85-
)}
86-
</>
87-
)}
65+
{layout === "gantt" && <CyclesListGanttChartView cycleIds={cyclesList} workspaceSlug={workspaceSlug} />}
8866
</>
8967
);
9068
});

web/components/exporter/guide.tsx

+3-7
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import { IntegrationService } from "services/integrations";
1515
import { Exporter, SingleExport } from "components/exporter";
1616
import { EmptyState, getEmptyStateImagePath } from "components/empty-state";
1717
// ui
18-
import { Button, Loader } from "@plane/ui";
18+
import { Button } from "@plane/ui";
19+
import { ImportExportSettingsLoader } from "components/ui";
1920
// icons
2021
import { MoveLeft, MoveRight, RefreshCw } from "lucide-react";
2122
// fetch-keys
@@ -158,12 +159,7 @@ const IntegrationGuide = observer(() => {
158159
</div>
159160
)
160161
) : (
161-
<Loader className="mt-6 grid grid-cols-1 gap-3">
162-
<Loader.Item height="40px" width="100%" />
163-
<Loader.Item height="40px" width="100%" />
164-
<Loader.Item height="40px" width="100%" />
165-
<Loader.Item height="40px" width="100%" />
166-
</Loader>
162+
<ImportExportSettingsLoader />
167163
)}
168164
</div>
169165
</div>

web/components/integration/guide.tsx

+3-7
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import { IntegrationService } from "services/integrations";
1414
import { DeleteImportModal, GithubImporterRoot, JiraImporterRoot, SingleImport } from "components/integration";
1515
import { EmptyState, getEmptyStateImagePath } from "components/empty-state";
1616
// ui
17-
import { Button, Loader } from "@plane/ui";
17+
import { Button } from "@plane/ui";
18+
import { ImportExportSettingsLoader } from "components/ui";
1819
// icons
1920
import { RefreshCw } from "lucide-react";
2021
// types
@@ -153,12 +154,7 @@ const IntegrationGuide = observer(() => {
153154
</div>
154155
)
155156
) : (
156-
<Loader className="mt-6 grid grid-cols-1 gap-3">
157-
<Loader.Item height="40px" width="100%" />
158-
<Loader.Item height="40px" width="100%" />
159-
<Loader.Item height="40px" width="100%" />
160-
<Loader.Item height="40px" width="100%" />
161-
</Loader>
157+
<ImportExportSettingsLoader />
162158
)}
163159
</div>
164160
</div>

web/components/integration/single-integration-card.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ export const SingleIntegrationCard: React.FC<Props> = observer(({ integration })
168168
)
169169
) : (
170170
<Loader>
171-
<Loader.Item height="35px" width="150px" />
171+
<Loader.Item height="32px" width="64px" />
172172
</Loader>
173173
)}
174174
</div>

web/components/issues/issue-layouts/kanban/block.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,14 @@ export const KanbanIssueBlock: React.FC<IssueBlockProps> = memo((props) => {
138138
>
139139
<div
140140
className={cn(
141-
"rounded border-[0.5px] border-custom-border-200 bg-custom-background-100 px-3 py-2 text-sm transition-all hover:border-custom-border-400",
141+
"rounded border-[0.5px] border-custom-border-200 bg-custom-background-100 text-sm transition-all hover:border-custom-border-400",
142142
{ "hover:cursor-grab": !isDragDisabled },
143143
{ "border-custom-primary-100": snapshot.isDragging },
144144
{ "border border-custom-primary-70 hover:border-custom-primary-70": peekIssueId === issue.id }
145145
)}
146146
>
147147
<RenderIfVisible
148-
classNames="space-y-2"
148+
classNames="space-y-2 px-3 py-2"
149149
root={scrollableContainerRef}
150150
defaultHeight="100px"
151151
horizonatlOffset={50}

web/components/issues/issue-layouts/roots/all-issue-layout-root.tsx

+53-58
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ import { GlobalViewsAppliedFiltersRoot, IssuePeekOverview } from "components/iss
1212
import { SpreadsheetView } from "components/issues/issue-layouts";
1313
import { AllIssueQuickActions } from "components/issues/issue-layouts/quick-action-dropdowns";
1414
import { EmptyState, getEmptyStateImagePath } from "components/empty-state";
15-
// ui
16-
import { Spinner } from "@plane/ui";
15+
import { SpreadsheetLayoutLoader } from "components/ui";
1716
// types
1817
import { TIssue, IIssueDisplayFilterOptions } from "@plane/types";
1918
import { EIssueActions } from "../types";
@@ -178,64 +177,60 @@ export const AllIssueLayoutRoot: React.FC = observer(() => {
178177

179178
const isEditingAllowed = !!currentWorkspaceRole && currentWorkspaceRole >= EUserWorkspaceRoles.MEMBER;
180179

181-
return (
182-
<div className="relative flex h-full w-full flex-col overflow-hidden">
183-
{!globalViewId || globalViewId !== dataViewId || loader === "init-loader" || !issueIds ? (
184-
<div className="flex h-full w-full items-center justify-center">
185-
<Spinner />
186-
</div>
187-
) : (
188-
<>
189-
<GlobalViewsAppliedFiltersRoot globalViewId={globalViewId} />
190-
191-
{(issueIds ?? {}).length == 0 ? (
192-
<EmptyState
193-
image={emptyStateImage}
194-
title={(workspaceProjectIds ?? []).length > 0 ? currentViewDetails.title : "No project"}
195-
description={
196-
(workspaceProjectIds ?? []).length > 0
197-
? currentViewDetails.description
198-
: "To create issues or manage your work, you need to create a project or be a part of one."
199-
}
200-
size="sm"
201-
primaryButton={
202-
(workspaceProjectIds ?? []).length > 0
203-
? currentView !== "custom-view" && currentView !== "subscribed"
204-
? {
205-
text: "Create new issue",
206-
onClick: () => {
207-
setTrackElement("All issues empty state");
208-
commandPaletteStore.toggleCreateIssueModal(true, EIssuesStoreType.PROJECT);
209-
},
210-
}
211-
: undefined
212-
: {
213-
text: "Start your first project",
214-
onClick: () => {
215-
setTrackElement("All issues empty state");
216-
commandPaletteStore.toggleCreateProjectModal(true);
217-
},
218-
}
180+
if (loader === "init-loader" || !globalViewId || globalViewId !== dataViewId || !issueIds) {
181+
return <SpreadsheetLayoutLoader />;
182+
}
183+
184+
if (issueIds.length === 0) {
185+
return (
186+
<EmptyState
187+
image={emptyStateImage}
188+
title={(workspaceProjectIds ?? []).length > 0 ? currentViewDetails.title : "No project"}
189+
description={
190+
(workspaceProjectIds ?? []).length > 0
191+
? currentViewDetails.description
192+
: "To create issues or manage your work, you need to create a project or be a part of one."
193+
}
194+
size="sm"
195+
primaryButton={
196+
(workspaceProjectIds ?? []).length > 0
197+
? currentView !== "custom-view" && currentView !== "subscribed"
198+
? {
199+
text: "Create new issue",
200+
onClick: () => {
201+
setTrackElement("All issues empty state");
202+
commandPaletteStore.toggleCreateIssueModal(true, EIssuesStoreType.PROJECT);
203+
},
204+
}
205+
: undefined
206+
: {
207+
text: "Start your first project",
208+
onClick: () => {
209+
setTrackElement("All issues empty state");
210+
commandPaletteStore.toggleCreateProjectModal(true);
211+
},
219212
}
220-
disabled={!isEditingAllowed}
221-
/>
222-
) : (
223-
<div className="relative h-full w-full overflow-auto">
224-
<SpreadsheetView
225-
displayProperties={issueFilters?.displayProperties ?? {}}
226-
displayFilters={issueFilters?.displayFilters ?? {}}
227-
handleDisplayFilterUpdate={handleDisplayFiltersUpdate}
228-
issueIds={issueIds}
229-
quickActions={renderQuickActions}
230-
handleIssues={handleIssues}
231-
canEditProperties={canEditProperties}
232-
viewId={globalViewId}
233-
/>
234-
</div>
235-
)}
236-
</>
237-
)}
213+
}
214+
disabled={!isEditingAllowed}
215+
/>
216+
);
217+
}
238218

219+
return (
220+
<div className="relative flex h-full w-full flex-col overflow-hidden">
221+
<GlobalViewsAppliedFiltersRoot globalViewId={globalViewId} />
222+
<div className="relative h-full w-full overflow-auto">
223+
<SpreadsheetView
224+
displayProperties={issueFilters?.displayProperties ?? {}}
225+
displayFilters={issueFilters?.displayFilters ?? {}}
226+
handleDisplayFilterUpdate={handleDisplayFiltersUpdate}
227+
issueIds={issueIds}
228+
quickActions={renderQuickActions}
229+
handleIssues={handleIssues}
230+
canEditProperties={canEditProperties}
231+
viewId={globalViewId}
232+
/>
233+
</div>
239234
{/* peek overview */}
240235
<IssuePeekOverview />
241236
</div>

web/components/issues/issue-layouts/roots/archived-issue-layout-root.tsx

+17-22
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
} from "components/issues";
1414
import { EIssuesStoreType } from "constants/issue";
1515
// ui
16-
import { Spinner } from "@plane/ui";
16+
import { ListLayoutLoader } from "components/ui";
1717

1818
export const ArchivedIssueLayoutRoot: React.FC = observer(() => {
1919
// router
@@ -36,31 +36,26 @@ export const ArchivedIssueLayoutRoot: React.FC = observer(() => {
3636
}
3737
);
3838

39+
if (issues?.loader === "init-loader" || !issues?.groupedIssueIds) {
40+
return <ListLayoutLoader />;
41+
}
42+
43+
if (issues?.groupedIssueIds?.length === 0) {
44+
return (
45+
<div className="relative h-full w-full overflow-y-auto">
46+
<ProjectArchivedEmptyState />
47+
</div>
48+
);
49+
}
50+
3951
if (!workspaceSlug || !projectId) return <></>;
4052
return (
4153
<div className="relative flex h-full w-full flex-col overflow-hidden">
4254
<ArchivedIssueAppliedFiltersRoot />
43-
44-
{issues?.loader === "init-loader" ? (
45-
<div className="flex h-full w-full items-center justify-center">
46-
<Spinner />
47-
</div>
48-
) : (
49-
<>
50-
{!issues?.groupedIssueIds ? (
51-
<ProjectArchivedEmptyState />
52-
) : (
53-
<>
54-
<div className="relative h-full w-full overflow-auto">
55-
<ArchivedIssueListLayout />
56-
</div>
57-
58-
{/* peek overview */}
59-
<IssuePeekOverview is_archived />
60-
</>
61-
)}
62-
</>
63-
)}
55+
<div className="relative h-full w-full overflow-auto">
56+
<ArchivedIssueListLayout />
57+
</div>
58+
<IssuePeekOverview is_archived />
6459
</div>
6560
);
6661
});

0 commit comments

Comments
 (0)