|
25 | 25 | import { onMount, type ComponentType } from 'svelte';
|
26 | 26 | import { canWriteProjects } from '$lib/stores/roles';
|
27 | 27 | import { checkPricingRefAndRedirect } from '$lib/helpers/pricingRedirect';
|
28 |
| - import { Badge, Icon, Typography, Alert, Tag, Tooltip } from '@appwrite.io/pink-svelte'; |
29 |
| - import { isSmallViewport } from '$lib/stores/viewport'; |
| 28 | + import { Badge, Icon, Typography, Alert } from '@appwrite.io/pink-svelte'; |
| 29 | +
|
30 | 30 | import {
|
31 | 31 | IconAndroid,
|
32 | 32 | IconApple,
|
|
41 | 41 | import { currentPlan, regions as regionsStore } from '$lib/stores/organization';
|
42 | 42 | import SelectProjectCloud from '$lib/components/billing/alerts/selectProjectCloud.svelte';
|
43 | 43 | import { toLocaleDate } from '$lib/helpers/date';
|
| 44 | + import { ArchiveProject } from '$lib/components'; |
44 | 45 |
|
45 | 46 | export let data;
|
46 | 47 |
|
|
129 | 130 | return !data.organization.projects?.includes(project.$id);
|
130 | 131 | }
|
131 | 132 |
|
132 |
| - function formatName(name: string, limit: number = 19) { |
133 |
| - const mobileLimit = 16; |
134 |
| - const actualLimit = $isSmallViewport ? mobileLimit : limit; |
135 |
| - return name ? (name.length > actualLimit ? `${name.slice(0, actualLimit)}...` : name) : '-'; |
136 |
| - } |
137 |
| -
|
138 |
| - $: projectsToArchive = data.projects.projects.filter( |
139 |
| - (project) => !data.organization.projects?.includes(project.$id) |
140 |
| - ); |
| 133 | + $: activeProjects = data.projects.projects.filter((project) => !isSetToArchive(project)); |
| 134 | + $: archivedProjects = data.projects.projects.filter((project) => isSetToArchive(project)); |
141 | 135 | </script>
|
142 | 136 |
|
143 | 137 | <SelectProjectCloud selectedProjects={data.organization.projects || []} bind:showSelectProject />
|
|
167 | 161 | </DropList>
|
168 | 162 | </div>
|
169 | 163 |
|
170 |
| - {#if isCloud && $currentPlan?.projects && $currentPlan?.projects > 0 && data.organization.projects.length > 0 && data.projects.total > 2 && $canWriteProjects} |
| 164 | + {#if isCloud && $currentPlan?.projects && $currentPlan?.projects > 0 && data.organization.projects.length > 0 && archivedProjects.length > 0 && $canWriteProjects} |
171 | 165 | <Alert.Inline
|
172 |
| - title={`${data.projects.total - data.organization.projects.length} projects will be archived on ${toLocaleDate(billingProjectsLimitDate)}`}> |
| 166 | + title={`${archivedProjects.length} projects will be archived on ${toLocaleDate(billingProjectsLimitDate)}`}> |
173 | 167 | <Typography.Text>
|
174 |
| - {#each projectsToArchive as project, index}{@const text = `<b>${project.name}</b>`} |
175 |
| - {@html text}{index == projectsToArchive.length - 2 |
| 168 | + {#each archivedProjects as project, index}{@const text = `<b>${project.name}</b>`} |
| 169 | + {@html text}{index == archivedProjects.length - 2 |
176 | 170 | ? ', and '
|
177 |
| - : index < projectsToArchive.length - 1 |
| 171 | + : index < archivedProjects.length - 1 |
178 | 172 | ? ', '
|
179 | 173 | : ''}
|
180 | 174 | {/each}
|
|
199 | 193 | </Alert.Inline>
|
200 | 194 | {/if}
|
201 | 195 |
|
202 |
| - {#if data.projects.total} |
203 |
| - <CardContainer |
204 |
| - disableEmpty={!$canWriteProjects} |
205 |
| - total={data.projects.total} |
206 |
| - offset={data.offset} |
207 |
| - on:click={handleCreateProject}> |
208 |
| - {#each data.projects.projects as project} |
209 |
| - {@const platforms = filterPlatforms( |
210 |
| - project.platforms.map((platform) => getPlatformInfo(platform.type)) |
211 |
| - )} |
212 |
| - {@const formatted = isSetToArchive(project) |
213 |
| - ? formatName(project.name) |
214 |
| - : project.name} |
215 |
| - <GridItem1 |
216 |
| - href={`${base}/project-${project.region}-${project.$id}/overview/platforms`}> |
217 |
| - <svelte:fragment slot="eyebrow"> |
218 |
| - {project?.platforms?.length ? project?.platforms?.length : 'No'} apps |
219 |
| - </svelte:fragment> |
220 |
| - <svelte:fragment slot="title"> |
221 |
| - <Tooltip |
222 |
| - maxWidth={project.name.length.toString()} |
223 |
| - placement="top" |
224 |
| - disabled={!isSetToArchive(project)}> |
225 |
| - {formatted} |
226 |
| - <span slot="tooltip"> |
227 |
| - {project.name} |
228 |
| - </span> |
229 |
| - </Tooltip> |
230 |
| - </svelte:fragment> |
| 196 | + {#if data.projects.total > 0} |
| 197 | + {#if activeProjects.length > 0} |
| 198 | + <CardContainer |
| 199 | + disableEmpty={!$canWriteProjects} |
| 200 | + total={activeProjects.length} |
| 201 | + offset={data.offset} |
| 202 | + on:click={handleCreateProject}> |
| 203 | + {#each activeProjects as project} |
| 204 | + {@const platforms = filterPlatforms( |
| 205 | + project.platforms.map((platform) => getPlatformInfo(platform.type)) |
| 206 | + )} |
| 207 | + <GridItem1 |
| 208 | + href={`${base}/project-${project.region}-${project.$id}/overview/platforms`}> |
| 209 | + <svelte:fragment slot="eyebrow"> |
| 210 | + {project?.platforms?.length ? project?.platforms?.length : 'No'} apps |
| 211 | + </svelte:fragment> |
| 212 | + <svelte:fragment slot="title"> |
| 213 | + {project.name} |
| 214 | + </svelte:fragment> |
231 | 215 |
|
232 |
| - <svelte:fragment slot="status"> |
233 |
| - {#if isSetToArchive(project)} |
234 |
| - <Tag |
235 |
| - size="s" |
236 |
| - style="white-space: nowrap;" |
237 |
| - on:click={(event) => { |
238 |
| - event.preventDefault(); |
239 |
| - showSelectProject = true; |
240 |
| - }}>Set to archive</Tag> |
241 |
| - {/if} |
242 |
| - </svelte:fragment> |
| 216 | + {#each platforms.slice(0, 2) as platform} |
| 217 | + {@const icon = getIconForPlatform(platform.icon)} |
| 218 | + <Badge |
| 219 | + variant="secondary" |
| 220 | + content={platform.name} |
| 221 | + style="width: max-content;"> |
| 222 | + <Icon {icon} size="s" slot="start" /> |
| 223 | + </Badge> |
| 224 | + {/each} |
243 | 225 |
|
244 |
| - {#each platforms.slice(0, 2) as platform} |
245 |
| - {@const icon = getIconForPlatform(platform.icon)} |
246 |
| - <Badge |
247 |
| - variant="secondary" |
248 |
| - content={platform.name} |
249 |
| - style="width: max-content;"> |
250 |
| - <Icon {icon} size="s" slot="start" /> |
251 |
| - </Badge> |
252 |
| - {/each} |
| 226 | + {#if platforms.length > 3} |
| 227 | + <Badge |
| 228 | + variant="secondary" |
| 229 | + content={`+${platforms.length - 2}`} |
| 230 | + style="width: max-content;" /> |
| 231 | + {/if} |
253 | 232 |
|
254 |
| - {#if platforms.length > 3} |
255 |
| - <Badge |
256 |
| - variant="secondary" |
257 |
| - content={`+${platforms.length - 2}`} |
258 |
| - style="width: max-content;" /> |
259 |
| - {/if} |
| 233 | + <svelte:fragment slot="icons"> |
| 234 | + {#if isCloud && $regionsStore?.regions} |
| 235 | + {@const region = findRegion(project)} |
| 236 | + <Typography.Text>{region.name}</Typography.Text> |
| 237 | + {/if} |
| 238 | + </svelte:fragment> |
| 239 | + </GridItem1> |
| 240 | + {/each} |
| 241 | + <svelte:fragment slot="empty"> |
| 242 | + <p>Create a new project</p> |
| 243 | + </svelte:fragment> |
| 244 | + </CardContainer> |
| 245 | + {/if} |
260 | 246 |
|
261 |
| - <svelte:fragment slot="icons"> |
262 |
| - {#if isCloud && $regionsStore?.regions} |
263 |
| - {@const region = findRegion(project)} |
264 |
| - <Typography.Text>{region.name}</Typography.Text> |
265 |
| - {/if} |
266 |
| - </svelte:fragment> |
267 |
| - </GridItem1> |
268 |
| - {/each} |
269 |
| - <svelte:fragment slot="empty"> |
270 |
| - <p>Create a new project</p> |
271 |
| - </svelte:fragment> |
272 |
| - </CardContainer> |
| 247 | + <!-- Archived Projects Section --> |
| 248 | + <ArchiveProject projectsToArchive={archivedProjects} /> |
273 | 249 | {:else}
|
274 | 250 | <Empty
|
275 | 251 | single
|
|
283 | 259 | name="Projects"
|
284 | 260 | limit={data.limit}
|
285 | 261 | offset={data.offset}
|
286 |
| - total={data.projects.total} /> |
| 262 | + total={activeProjects.length} /> |
287 | 263 | </Container>
|
288 | 264 |
|
289 | 265 | <CreateOrganization bind:show={addOrganization} />
|
|
0 commit comments