create-aphex 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +9 -88
- package/package.json +4 -4
- package/templates/base/.dockerignore +0 -44
- package/templates/base/.env.example +0 -38
- package/templates/base/CHANGELOG.md +0 -119
- package/templates/base/Dockerfile +0 -69
- package/templates/base/README.md +0 -147
- package/templates/base/aphex.config.ts +0 -45
- package/templates/base/docker-compose.yml +0 -31
- package/templates/base/drizzle/0000_tiny_redwing.sql +0 -226
- package/templates/base/drizzle/meta/0000_snapshot.json +0 -1379
- package/templates/base/drizzle/meta/_journal.json +0 -13
- package/templates/base/drizzle.config.ts +0 -17
- package/templates/base/package.json +0 -81
- package/templates/base/prod.docker-compose.yml +0 -61
- package/templates/base/src/app.css +0 -32
- package/templates/base/src/app.d.ts +0 -26
- package/templates/base/src/app.html +0 -11
- package/templates/base/src/hooks.server.ts +0 -52
- package/templates/base/src/lib/assets/favicon.svg +0 -5
- package/templates/base/src/lib/auth-client.ts +0 -19
- package/templates/base/src/lib/index.ts +0 -1
- package/templates/base/src/lib/schemaTypes/index.ts +0 -11
- package/templates/base/src/lib/schemaTypes/post.ts +0 -47
- package/templates/base/src/lib/server/auth/better-auth/instance.ts +0 -165
- package/templates/base/src/lib/server/auth/index.ts +0 -25
- package/templates/base/src/lib/server/auth/instance.ts +0 -7
- package/templates/base/src/lib/server/auth/service.ts +0 -486
- package/templates/base/src/lib/server/cache/index.ts +0 -10
- package/templates/base/src/lib/server/db/auth-schema.ts +0 -86
- package/templates/base/src/lib/server/db/cms-schema.ts +0 -23
- package/templates/base/src/lib/server/db/index.ts +0 -55
- package/templates/base/src/lib/server/db/schema.ts +0 -3
- package/templates/base/src/lib/server/email/components/EmailLayout.svelte +0 -24
- package/templates/base/src/lib/server/email/components/EmailVerification.svelte +0 -26
- package/templates/base/src/lib/server/email/components/Invitation.svelte +0 -30
- package/templates/base/src/lib/server/email/components/PasswordReset.svelte +0 -28
- package/templates/base/src/lib/server/email/index.ts +0 -28
- package/templates/base/src/lib/server/email/invitation-hook.ts +0 -56
- package/templates/base/src/lib/server/email/renderer.ts +0 -13
- package/templates/base/src/lib/server/email/templates/email-verification.ts +0 -8
- package/templates/base/src/lib/server/email/templates/invitation.ts +0 -8
- package/templates/base/src/lib/server/email/templates/password-reset.ts +0 -7
- package/templates/base/src/lib/server/services/organization.ts +0 -68
- package/templates/base/src/lib/server/storage/index.ts +0 -28
- package/templates/base/src/lib/stores/activeTab.svelte.ts +0 -14
- package/templates/base/src/lib/utils/imageBuilder.ts +0 -3
- package/templates/base/src/lib/utils/slug.ts +0 -33
- package/templates/base/src/routes/(protected)/admin/+layout.server.ts +0 -86
- package/templates/base/src/routes/(protected)/admin/+layout.svelte +0 -78
- package/templates/base/src/routes/(protected)/admin/+page.server.ts +0 -60
- package/templates/base/src/routes/(protected)/admin/+page.svelte +0 -34
- package/templates/base/src/routes/(protected)/admin/organizations/+page.server.ts +0 -39
- package/templates/base/src/routes/(protected)/admin/organizations/+page.svelte +0 -31
- package/templates/base/src/routes/(protected)/admin/organizations/_components/CreateOrganization.svelte +0 -141
- package/templates/base/src/routes/(protected)/admin/organizations/_components/OrganizationsList.svelte +0 -102
- package/templates/base/src/routes/(protected)/admin/settings/+layout.server.ts +0 -42
- package/templates/base/src/routes/(protected)/admin/settings/+layout.svelte +0 -116
- package/templates/base/src/routes/(protected)/admin/settings/+page.server.ts +0 -16
- package/templates/base/src/routes/(protected)/admin/settings/+page.svelte +0 -32
- package/templates/base/src/routes/(protected)/admin/settings/_components/AccountSettings.svelte +0 -177
- package/templates/base/src/routes/(protected)/admin/settings/_components/ApiKeysSettings.svelte +0 -472
- package/templates/base/src/routes/(protected)/admin/settings/_components/OrganizationsSettings.svelte +0 -182
- package/templates/base/src/routes/(protected)/admin/settings/account/+page.server.ts +0 -25
- package/templates/base/src/routes/(protected)/admin/settings/account/+page.svelte +0 -23
- package/templates/base/src/routes/(protected)/admin/settings/api-keys/+page.server.ts +0 -54
- package/templates/base/src/routes/(protected)/admin/settings/api-keys/+page.svelte +0 -14
- package/templates/base/src/routes/(protected)/admin/settings/members/+page.server.ts +0 -31
- package/templates/base/src/routes/(protected)/admin/settings/members/+page.svelte +0 -338
- package/templates/base/src/routes/(protected)/admin/settings/roles/+page.server.ts +0 -17
- package/templates/base/src/routes/(protected)/admin/settings/roles/+page.svelte +0 -339
- package/templates/base/src/routes/+layout.svelte +0 -12
- package/templates/base/src/routes/+page.svelte +0 -2
- package/templates/base/src/routes/api/[...slug]/+server.ts +0 -35
- package/templates/base/src/routes/api/instance-settings/+server.ts +0 -70
- package/templates/base/src/routes/api/invitations/+server.ts +0 -54
- package/templates/base/src/routes/api/invitations/[id]/accept/+server.ts +0 -54
- package/templates/base/src/routes/api/invitations/[id]/reject/+server.ts +0 -49
- package/templates/base/src/routes/api/settings/api-keys/+server.ts +0 -57
- package/templates/base/src/routes/api/settings/api-keys/[id]/+server.ts +0 -53
- package/templates/base/src/routes/god-mode/+layout.server.ts +0 -32
- package/templates/base/src/routes/god-mode/+layout.svelte +0 -155
- package/templates/base/src/routes/god-mode/+page.server.ts +0 -10
- package/templates/base/src/routes/god-mode/+page.svelte +0 -32
- package/templates/base/src/routes/god-mode/_components/CreateOrganization.svelte +0 -141
- package/templates/base/src/routes/god-mode/_components/OrganizationsList.svelte +0 -169
- package/templates/base/src/routes/god-mode/organizations/+page.server.ts +0 -43
- package/templates/base/src/routes/god-mode/organizations/+page.svelte +0 -74
- package/templates/base/src/routes/invitations/+page.server.ts +0 -48
- package/templates/base/src/routes/invitations/+page.svelte +0 -264
- package/templates/base/src/routes/invite/[token]/+page.server.ts +0 -59
- package/templates/base/src/routes/invite/[token]/+page.svelte +0 -109
- package/templates/base/src/routes/login/+page.server.ts +0 -14
- package/templates/base/src/routes/login/+page.svelte +0 -332
- package/templates/base/src/routes/media/[id]/[filename]/+server.ts +0 -3
- package/templates/base/src/routes/reset-password/[token]/+page.server.ts +0 -15
- package/templates/base/src/routes/reset-password/[token]/+page.svelte +0 -179
- package/templates/base/src/routes/verify-email/+page.svelte +0 -41
- package/templates/base/static/images/aphex-darkmode.png +0 -0
- package/templates/base/static/images/aphex-lightmode.png +0 -0
- package/templates/base/static/robots.txt +0 -3
- package/templates/base/svelte.config.js +0 -19
- package/templates/base/tsconfig.json +0 -20
- package/templates/base/vite.config.ts +0 -138
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { json } from '@sveltejs/kit';
|
|
2
|
-
import type { RequestHandler } from './$types';
|
|
3
|
-
import { auth } from '$lib/server/auth';
|
|
4
|
-
|
|
5
|
-
// DELETE - Delete an API key
|
|
6
|
-
export const DELETE: RequestHandler = async ({ params, request, locals }) => {
|
|
7
|
-
if (!locals.auth || locals.auth.type !== 'session') {
|
|
8
|
-
return json({ error: 'Unauthorized' }, { status: 401 });
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const session = locals.auth;
|
|
12
|
-
|
|
13
|
-
try {
|
|
14
|
-
// Check user's organization role - only owner, admin, and editor can delete API keys
|
|
15
|
-
const { databaseAdapter } = locals.aphexCMS;
|
|
16
|
-
const memberships = await databaseAdapter.findUserOrganizations(session.user.id);
|
|
17
|
-
const currentMembership = memberships.find((m) => m.organization.id === session.organizationId);
|
|
18
|
-
const orgRole = currentMembership?.member.role;
|
|
19
|
-
|
|
20
|
-
if (orgRole !== 'owner' && orgRole !== 'admin' && orgRole !== 'editor') {
|
|
21
|
-
return json(
|
|
22
|
-
{
|
|
23
|
-
error: 'Forbidden',
|
|
24
|
-
message: 'Only organization owners, admins, and editors can delete API keys'
|
|
25
|
-
},
|
|
26
|
-
{ status: 403 }
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const { id } = params;
|
|
31
|
-
|
|
32
|
-
if (!id) {
|
|
33
|
-
return json({ error: 'ID not found in params' }, { status: 400 });
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// TODO - don't actually delete the API KEY - instead
|
|
37
|
-
const data = await auth.api.deleteApiKey({
|
|
38
|
-
body: {
|
|
39
|
-
keyId: id // required
|
|
40
|
-
},
|
|
41
|
-
headers: request.headers
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
if (data.success) {
|
|
45
|
-
return json({ success: true });
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return json({ error: 'Failed to delete API key' }, { status: 500 });
|
|
49
|
-
} catch (error) {
|
|
50
|
-
console.error('Error deleting API key:', error);
|
|
51
|
-
return json({ error: 'Failed to delete API key' }, { status: 500 });
|
|
52
|
-
}
|
|
53
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { redirect } from '@sveltejs/kit';
|
|
2
|
-
import type { LayoutServerLoad } from './$types';
|
|
3
|
-
|
|
4
|
-
export const load: LayoutServerLoad = async ({ locals }) => {
|
|
5
|
-
const auth = locals.auth;
|
|
6
|
-
|
|
7
|
-
if (!auth || auth.type !== 'session') {
|
|
8
|
-
throw redirect(302, '/login');
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
if (auth.user.role !== 'super_admin') {
|
|
12
|
-
return {
|
|
13
|
-
unauthorized: true,
|
|
14
|
-
user: {
|
|
15
|
-
id: auth.user.id,
|
|
16
|
-
email: auth.user.email,
|
|
17
|
-
name: auth.user.name,
|
|
18
|
-
role: auth.user.role
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
unauthorized: false,
|
|
25
|
-
user: {
|
|
26
|
-
id: auth.user.id,
|
|
27
|
-
email: auth.user.email,
|
|
28
|
-
name: auth.user.name,
|
|
29
|
-
role: auth.user.role
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
};
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { page } from '$app/state';
|
|
3
|
-
import { goto } from '$app/navigation';
|
|
4
|
-
import { ModeWatcher } from 'mode-watcher';
|
|
5
|
-
import { authClient } from '$lib/auth-client';
|
|
6
|
-
import { Button } from '@aphexcms/ui/shadcn/button';
|
|
7
|
-
|
|
8
|
-
let { children, data } = $props();
|
|
9
|
-
|
|
10
|
-
const basePath = '/god-mode';
|
|
11
|
-
|
|
12
|
-
const tabs = [
|
|
13
|
-
{ label: 'General', href: basePath },
|
|
14
|
-
{ label: 'Organizations', href: `${basePath}/organizations` }
|
|
15
|
-
];
|
|
16
|
-
|
|
17
|
-
function isActive(href: string) {
|
|
18
|
-
if (href === basePath) return page.url.pathname === basePath;
|
|
19
|
-
return page.url.pathname.startsWith(href);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async function handleSignOut() {
|
|
23
|
-
await authClient.signOut();
|
|
24
|
-
goto('/login');
|
|
25
|
-
}
|
|
26
|
-
</script>
|
|
27
|
-
|
|
28
|
-
<ModeWatcher />
|
|
29
|
-
|
|
30
|
-
{#if data.unauthorized}
|
|
31
|
-
<div class="flex min-h-screen flex-col">
|
|
32
|
-
<header class="flex items-center justify-between px-6 py-4">
|
|
33
|
-
<svg
|
|
34
|
-
class="h-8 w-8 fill-black dark:fill-white"
|
|
35
|
-
version="1.1"
|
|
36
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
37
|
-
viewBox="0 0 512 512"
|
|
38
|
-
>
|
|
39
|
-
<path
|
|
40
|
-
d="M0 0 C17.1474496 14.16905616 25.92496627 35.45820085 34.56640625 55.4140625 C35.34334316 57.19720923 36.12053079 58.98024674 36.89794922 60.76318359 C51.78722595 94.97195072 66.32335778 129.32882671 80.31640625 163.9140625 C80.6444928 164.72450012 80.97257935 165.53493774 81.31060791 166.36993408 C99.98913061 212.53216334 117.78569191 259.01293728 134.00390625 306.1015625 C134.36190811 307.13669983 134.36190811 307.13669983 134.72714233 308.19274902 C137.32766526 315.72906515 139.80262285 323.3004011 142.1171875 330.9296875 C142.43800545 331.95940926 142.43800545 331.95940926 142.76530457 333.00993347 C145.2565569 341.39135358 146.09964488 351.05219488 142.44140625 359.23046875 C139.92789443 362.992009 136.34564423 365.89944351 132.31640625 367.9140625 C124.8558052 368.61421121 118.36839373 368.62364314 112.31640625 363.9140625 C105.53664487 356.69699976 100.652558 348.68983785 95.94140625 340.0390625 C90.47619491 330.29913602 84.93335438 322.05287151 77.31640625 313.9140625 C75.27331056 311.57880549 73.26394666 309.2152832 71.25390625 306.8515625 C70.24519648 305.67152884 69.23608749 304.49183631 68.2265625 303.3125 C67.73816895 302.74112305 67.24977539 302.16974609 66.74658203 301.58105469 C65.40017275 300.01169952 64.04454028 298.45078423 62.6875 296.890625 C48.81582552 280.69615056 38.44623629 261.89870442 27.89111328 243.45849609 C-8.42360388 178.69858879 -8.42360388 178.69858879 -68.08203125 137.78515625 C-79.11186673 135.11741947 -89.899608 136.09230489 -99.68359375 141.9140625 C-115.46806791 152.47947666 -122.3076261 172.13261849 -126.43359375 189.7890625 C-126.73185059 191.06136719 -126.73185059 191.06136719 -127.03613281 192.359375 C-130.16760015 206.71148601 -131.06828893 221.08194412 -130.99609375 235.7265625 C-130.9939386 236.51966827 -130.99178345 237.31277405 -130.98956299 238.12991333 C-131.31394288 266.6844263 -131.31394288 266.6844263 -123.23828125 293.5859375 C-112.95312656 315.60340432 -111.26097095 345.34400812 -119.5 368.0390625 C-124.86779615 381.07766965 -132.78250397 390.79435644 -145.68359375 396.9140625 C-155.27731384 400.41943083 -164.20346687 401.56551213 -174.37109375 401.4140625 C-176.32958252 401.39702271 -176.32958252 401.39702271 -178.32763672 401.37963867 C-197.70054192 400.99323331 -215.16231823 397.0095896 -230.68359375 384.9140625 C-231.37066406 384.41519531 -232.05773437 383.91632813 -232.765625 383.40234375 C-244.80767188 373.97296976 -251.15090869 358.63090674 -253.68359375 343.9140625 C-253.9270261 339.66653687 -253.91464574 335.41789154 -253.93359375 331.1640625 C-253.96453125 329.45089844 -253.96453125 329.45089844 -253.99609375 327.703125 C-254.00125 326.58164062 -254.00640625 325.46015625 -254.01171875 324.3046875 C-254.02106445 323.29438477 -254.03041016 322.28408203 -254.04003906 321.24316406 C-253.25260131 313.88871121 -250.02140677 307.08532381 -247.0859375 300.359375 C-246.73986954 299.55749252 -246.39380157 298.75561005 -246.0372467 297.9294281 C-245.29136983 296.20150738 -244.54396437 294.47424582 -243.79516602 292.74758911 C-241.75797546 288.04789133 -239.73451175 283.34229198 -237.7109375 278.63671875 C-237.0834108 277.17808662 -237.0834108 277.17808662 -236.44320679 275.68998718 C-232.12759637 265.64489937 -227.89599701 255.56528394 -223.68359375 245.4765625 C-223.31303864 244.58933502 -222.94248352 243.70210754 -222.56069946 242.78799438 C-221.05624911 239.1852842 -219.55230259 235.58236459 -218.04930115 231.97904968 C-215.45620988 225.7624217 -212.85713855 219.54832537 -210.25390625 213.3359375 C-199.87599396 188.56875674 -189.53860671 163.78483086 -179.21582031 138.99462891 C-176.70326253 132.96093438 -174.18966694 126.92767262 -171.67578125 120.89453125 C-171.2632309 119.90436005 -170.85068054 118.91418884 -170.42562866 117.89401245 C-168.35461551 112.92351005 -166.28304289 107.95324201 -164.21044922 102.98339844 C-160.33953189 93.69973915 -156.47385511 84.41400336 -152.62658691 75.12051392 C-150.82992691 70.78139762 -149.03030349 66.44351312 -147.23046875 62.10571289 C-146.38199036 60.05847127 -145.53492768 58.01064218 -144.68945312 55.9621582 C-140.72547669 46.35880091 -136.72273166 36.78723512 -132.3203125 27.375 C-132.00310242 26.69433975 -131.68589233 26.0136795 -131.35906982 25.31239319 C-123.25124472 8.26154126 -109.39227096 -6.16254505 -91.68359375 -13.0859375 C-59.99340229 -22.6620319 -26.67593546 -20.59334511 0 0 Z "
|
|
41
|
-
transform="translate(308.68359375,64.0859375)"
|
|
42
|
-
/>
|
|
43
|
-
<path
|
|
44
|
-
d="M0 0 C18.24717952 9.79342293 31.4582424 26.28742033 37.6171875 45.97265625 C39.90862161 58.10790422 38.62948747 76.77026254 32.3125 87.5625 C31.23887442 89.06398132 30.13305826 90.54284625 29 92 C28.04867187 93.39798828 28.04867187 93.39798828 27.078125 94.82421875 C22.05477616 102.1158627 16.59613089 108.96607145 8 112 C-4.55244493 113.74100692 -12.66496084 107.03937869 -22.140625 99.87890625 C-25.14482573 97.61370274 -28.2068393 95.46853473 -31.33056641 93.37231445 C-44.35072813 84.61921656 -53.55106508 73.69367426 -57 58 C-59.27762162 41.63399726 -53.36243485 19.43955677 -44.1875 5.9375 C-32.8352893 -8.66127096 -15.43371672 -7.37348527 0 0 Z "
|
|
45
|
-
transform="translate(254,240)"
|
|
46
|
-
/>
|
|
47
|
-
</svg>
|
|
48
|
-
<button
|
|
49
|
-
class="text-muted-foreground hover:text-foreground text-sm transition-colors"
|
|
50
|
-
onclick={handleSignOut}
|
|
51
|
-
>
|
|
52
|
-
{data.user.email}
|
|
53
|
-
</button>
|
|
54
|
-
</header>
|
|
55
|
-
|
|
56
|
-
<main class="flex flex-1 flex-col items-center justify-center px-4 pb-24">
|
|
57
|
-
<div class="flex flex-col items-center text-center">
|
|
58
|
-
<h2 class="text-lg font-semibold">Access Denied</h2>
|
|
59
|
-
<p class="text-muted-foreground mt-2 text-sm">
|
|
60
|
-
You don't have permission to access God Mode. This area is restricted to super admins.
|
|
61
|
-
</p>
|
|
62
|
-
<Button class="mt-6" href="/admin">Back to Dashboard</Button>
|
|
63
|
-
</div>
|
|
64
|
-
</main>
|
|
65
|
-
</div>
|
|
66
|
-
{:else}
|
|
67
|
-
<div class="flex min-h-screen flex-1 flex-col gap-4 p-4 md:gap-8 md:p-8">
|
|
68
|
-
<div class="mx-auto w-full max-w-6xl">
|
|
69
|
-
<!-- Mobile breadcrumb -->
|
|
70
|
-
<div class="mb-2 md:hidden">
|
|
71
|
-
<a
|
|
72
|
-
href="/admin"
|
|
73
|
-
class="text-muted-foreground hover:text-foreground text-sm transition-colors"
|
|
74
|
-
>
|
|
75
|
-
Dashboard
|
|
76
|
-
</a>
|
|
77
|
-
<span class="text-muted-foreground/50 mx-1 text-sm">/</span>
|
|
78
|
-
<span class="text-sm">God Mode</span>
|
|
79
|
-
</div>
|
|
80
|
-
<div class="flex items-center justify-between gap-2">
|
|
81
|
-
<div>
|
|
82
|
-
<h1 class="text-3xl font-semibold">God Mode</h1>
|
|
83
|
-
<p class="text-muted-foreground">Instance administration</p>
|
|
84
|
-
</div>
|
|
85
|
-
<a
|
|
86
|
-
href="/admin"
|
|
87
|
-
class="text-muted-foreground hover:text-foreground hidden text-sm transition-colors md:block"
|
|
88
|
-
>
|
|
89
|
-
Back to Dashboard
|
|
90
|
-
</a>
|
|
91
|
-
</div>
|
|
92
|
-
</div>
|
|
93
|
-
|
|
94
|
-
<!-- Mobile tabs -->
|
|
95
|
-
<div class="mx-auto w-full max-w-6xl md:hidden">
|
|
96
|
-
<div class="border-b">
|
|
97
|
-
<div class="flex gap-4">
|
|
98
|
-
{#each tabs as tab}
|
|
99
|
-
<a
|
|
100
|
-
href={tab.href}
|
|
101
|
-
class="border-b-2 px-1 pb-2 text-sm font-medium transition-colors {isActive(tab.href)
|
|
102
|
-
? 'border-primary text-primary'
|
|
103
|
-
: 'text-muted-foreground hover:text-foreground border-transparent'}"
|
|
104
|
-
>
|
|
105
|
-
{tab.label}
|
|
106
|
-
</a>
|
|
107
|
-
{/each}
|
|
108
|
-
</div>
|
|
109
|
-
</div>
|
|
110
|
-
</div>
|
|
111
|
-
|
|
112
|
-
<div
|
|
113
|
-
class="mx-auto grid w-full max-w-6xl items-start gap-6 md:grid-cols-[180px_1fr] lg:grid-cols-[250px_1fr]"
|
|
114
|
-
>
|
|
115
|
-
<!-- Desktop sidebar nav -->
|
|
116
|
-
<nav class="text-muted-foreground hidden gap-1 text-sm md:grid">
|
|
117
|
-
{#each tabs as tab}
|
|
118
|
-
<a
|
|
119
|
-
href={tab.href}
|
|
120
|
-
class="rounded-md px-2 py-1.5 {isActive(tab.href)
|
|
121
|
-
? 'text-primary bg-muted font-semibold'
|
|
122
|
-
: ''}"
|
|
123
|
-
>
|
|
124
|
-
{tab.label}
|
|
125
|
-
</a>
|
|
126
|
-
{/each}
|
|
127
|
-
</nav>
|
|
128
|
-
<div>
|
|
129
|
-
{@render children()}
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
132
|
-
|
|
133
|
-
<!-- Footer branding -->
|
|
134
|
-
<div class="mx-auto mt-auto pt-8">
|
|
135
|
-
<p class="text-muted-foreground text-center text-xs">Aphex CMS - Built with SvelteKit</p>
|
|
136
|
-
<div class="mt-2 flex justify-center opacity-20">
|
|
137
|
-
<svg
|
|
138
|
-
class="h-8 w-8 fill-black dark:fill-white"
|
|
139
|
-
version="1.1"
|
|
140
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
141
|
-
viewBox="0 0 512 512"
|
|
142
|
-
>
|
|
143
|
-
<path
|
|
144
|
-
d="M0 0 C17.1474496 14.16905616 25.92496627 35.45820085 34.56640625 55.4140625 C35.34334316 57.19720923 36.12053079 58.98024674 36.89794922 60.76318359 C51.78722595 94.97195072 66.32335778 129.32882671 80.31640625 163.9140625 C80.6444928 164.72450012 80.97257935 165.53493774 81.31060791 166.36993408 C99.98913061 212.53216334 117.78569191 259.01293728 134.00390625 306.1015625 C134.36190811 307.13669983 134.36190811 307.13669983 134.72714233 308.19274902 C137.32766526 315.72906515 139.80262285 323.3004011 142.1171875 330.9296875 C142.43800545 331.95940926 142.43800545 331.95940926 142.76530457 333.00993347 C145.2565569 341.39135358 146.09964488 351.05219488 142.44140625 359.23046875 C139.92789443 362.992009 136.34564423 365.89944351 132.31640625 367.9140625 C124.8558052 368.61421121 118.36839373 368.62364314 112.31640625 363.9140625 C105.53664487 356.69699976 100.652558 348.68983785 95.94140625 340.0390625 C90.47619491 330.29913602 84.93335438 322.05287151 77.31640625 313.9140625 C75.27331056 311.57880549 73.26394666 309.2152832 71.25390625 306.8515625 C70.24519648 305.67152884 69.23608749 304.49183631 68.2265625 303.3125 C67.73816895 302.74112305 67.24977539 302.16974609 66.74658203 301.58105469 C65.40017275 300.01169952 64.04454028 298.45078423 62.6875 296.890625 C48.81582552 280.69615056 38.44623629 261.89870442 27.89111328 243.45849609 C-8.42360388 178.69858879 -8.42360388 178.69858879 -68.08203125 137.78515625 C-79.11186673 135.11741947 -89.899608 136.09230489 -99.68359375 141.9140625 C-115.46806791 152.47947666 -122.3076261 172.13261849 -126.43359375 189.7890625 C-126.73185059 191.06136719 -126.73185059 191.06136719 -127.03613281 192.359375 C-130.16760015 206.71148601 -131.06828893 221.08194412 -130.99609375 235.7265625 C-130.9939386 236.51966827 -130.99178345 237.31277405 -130.98956299 238.12991333 C-131.31394288 266.6844263 -131.31394288 266.6844263 -123.23828125 293.5859375 C-112.95312656 315.60340432 -111.26097095 345.34400812 -119.5 368.0390625 C-124.86779615 381.07766965 -132.78250397 390.79435644 -145.68359375 396.9140625 C-155.27731384 400.41943083 -164.20346687 401.56551213 -174.37109375 401.4140625 C-176.32958252 401.39702271 -176.32958252 401.39702271 -178.32763672 401.37963867 C-197.70054192 400.99323331 -215.16231823 397.0095896 -230.68359375 384.9140625 C-231.37066406 384.41519531 -232.05773437 383.91632813 -232.765625 383.40234375 C-244.80767188 373.97296976 -251.15090869 358.63090674 -253.68359375 343.9140625 C-253.9270261 339.66653687 -253.91464574 335.41789154 -253.93359375 331.1640625 C-253.96453125 329.45089844 -253.96453125 329.45089844 -253.99609375 327.703125 C-254.00125 326.58164062 -254.00640625 325.46015625 -254.01171875 324.3046875 C-254.02106445 323.29438477 -254.03041016 322.28408203 -254.04003906 321.24316406 C-253.25260131 313.88871121 -250.02140677 307.08532381 -247.0859375 300.359375 C-246.73986954 299.55749252 -246.39380157 298.75561005 -246.0372467 297.9294281 C-245.29136983 296.20150738 -244.54396437 294.47424582 -243.79516602 292.74758911 C-241.75797546 288.04789133 -239.73451175 283.34229198 -237.7109375 278.63671875 C-237.0834108 277.17808662 -237.0834108 277.17808662 -236.44320679 275.68998718 C-232.12759637 265.64489937 -227.89599701 255.56528394 -223.68359375 245.4765625 C-223.31303864 244.58933502 -222.94248352 243.70210754 -222.56069946 242.78799438 C-221.05624911 239.1852842 -219.55230259 235.58236459 -218.04930115 231.97904968 C-215.45620988 225.7624217 -212.85713855 219.54832537 -210.25390625 213.3359375 C-199.87599396 188.56875674 -189.53860671 163.78483086 -179.21582031 138.99462891 C-176.70326253 132.96093438 -174.18966694 126.92767262 -171.67578125 120.89453125 C-171.2632309 119.90436005 -170.85068054 118.91418884 -170.42562866 117.89401245 C-168.35461551 112.92351005 -166.28304289 107.95324201 -164.21044922 102.98339844 C-160.33953189 93.69973915 -156.47385511 84.41400336 -152.62658691 75.12051392 C-150.82992691 70.78139762 -149.03030349 66.44351312 -147.23046875 62.10571289 C-146.38199036 60.05847127 -145.53492768 58.01064218 -144.68945312 55.9621582 C-140.72547669 46.35880091 -136.72273166 36.78723512 -132.3203125 27.375 C-132.00310242 26.69433975 -131.68589233 26.0136795 -131.35906982 25.31239319 C-123.25124472 8.26154126 -109.39227096 -6.16254505 -91.68359375 -13.0859375 C-59.99340229 -22.6620319 -26.67593546 -20.59334511 0 0 Z "
|
|
145
|
-
transform="translate(308.68359375,64.0859375)"
|
|
146
|
-
/>
|
|
147
|
-
<path
|
|
148
|
-
d="M0 0 C18.24717952 9.79342293 31.4582424 26.28742033 37.6171875 45.97265625 C39.90862161 58.10790422 38.62948747 76.77026254 32.3125 87.5625 C31.23887442 89.06398132 30.13305826 90.54284625 29 92 C28.04867187 93.39798828 28.04867187 93.39798828 27.078125 94.82421875 C22.05477616 102.1158627 16.59613089 108.96607145 8 112 C-4.55244493 113.74100692 -12.66496084 107.03937869 -22.140625 99.87890625 C-25.14482573 97.61370274 -28.2068393 95.46853473 -31.33056641 93.37231445 C-44.35072813 84.61921656 -53.55106508 73.69367426 -57 58 C-59.27762162 41.63399726 -53.36243485 19.43955677 -44.1875 5.9375 C-32.8352893 -8.66127096 -15.43371672 -7.37348527 0 0 Z "
|
|
149
|
-
transform="translate(254,240)"
|
|
150
|
-
/>
|
|
151
|
-
</svg>
|
|
152
|
-
</div>
|
|
153
|
-
</div>
|
|
154
|
-
</div>
|
|
155
|
-
{/if}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { PageServerLoad } from './$types';
|
|
2
|
-
|
|
3
|
-
export const load: PageServerLoad = async ({ locals }) => {
|
|
4
|
-
const { databaseAdapter } = locals.aphexCMS;
|
|
5
|
-
const instanceSettings = await databaseAdapter.getInstanceSettings();
|
|
6
|
-
|
|
7
|
-
return {
|
|
8
|
-
instanceSettings
|
|
9
|
-
};
|
|
10
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import * as Card from '@aphexcms/ui/shadcn/card';
|
|
3
|
-
import type { PageData } from './$types';
|
|
4
|
-
|
|
5
|
-
let { data }: { data: PageData } = $props();
|
|
6
|
-
</script>
|
|
7
|
-
|
|
8
|
-
<svelte:head>
|
|
9
|
-
<title>Aphex CMS - God Mode</title>
|
|
10
|
-
</svelte:head>
|
|
11
|
-
|
|
12
|
-
<div class="space-y-8">
|
|
13
|
-
<div class="hidden sm:block">
|
|
14
|
-
<h2 class="text-xl font-semibold">General</h2>
|
|
15
|
-
<p class="text-muted-foreground text-sm">Identify your instance and get key details.</p>
|
|
16
|
-
</div>
|
|
17
|
-
|
|
18
|
-
<Card.Root>
|
|
19
|
-
<Card.Header>
|
|
20
|
-
<Card.Title>Instance Information</Card.Title>
|
|
21
|
-
<Card.Description>Details about this Aphex CMS instance</Card.Description>
|
|
22
|
-
</Card.Header>
|
|
23
|
-
<Card.Content>
|
|
24
|
-
<div class="grid gap-4">
|
|
25
|
-
<div class="flex items-center justify-between">
|
|
26
|
-
<span class="text-muted-foreground text-sm">Admin</span>
|
|
27
|
-
<span class="text-sm font-medium">{data.user.email}</span>
|
|
28
|
-
</div>
|
|
29
|
-
</div>
|
|
30
|
-
</Card.Content>
|
|
31
|
-
</Card.Root>
|
|
32
|
-
</div>
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { goto, invalidateAll } from '$app/navigation';
|
|
3
|
-
import { Button } from '@aphexcms/ui/shadcn/button';
|
|
4
|
-
import { Input } from '@aphexcms/ui/shadcn/input';
|
|
5
|
-
import { Label } from '@aphexcms/ui/shadcn/label';
|
|
6
|
-
import * as Dialog from '@aphexcms/ui/shadcn/dialog';
|
|
7
|
-
import { organizations } from '@aphexcms/cms-core/client';
|
|
8
|
-
|
|
9
|
-
let open = $state(false);
|
|
10
|
-
let name = $state('');
|
|
11
|
-
let slug = $state('');
|
|
12
|
-
let isSubmitting = $state(false);
|
|
13
|
-
let error = $state<string | null>(null);
|
|
14
|
-
|
|
15
|
-
function generateSlug(text: string): string {
|
|
16
|
-
return text
|
|
17
|
-
.toLowerCase()
|
|
18
|
-
.trim()
|
|
19
|
-
.replace(/[^\w\s-]/g, '')
|
|
20
|
-
.replace(/[\s_-]+/g, '-')
|
|
21
|
-
.replace(/^-+|-+$/g, '');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function handleNameInput(event: Event) {
|
|
25
|
-
const target = event.target as HTMLInputElement;
|
|
26
|
-
name = target.value;
|
|
27
|
-
if (!slug || slug === generateSlug(name.slice(0, -1))) {
|
|
28
|
-
slug = generateSlug(name);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function handleSlugInput(event: Event) {
|
|
33
|
-
const target = event.target as HTMLInputElement;
|
|
34
|
-
slug = target.value.toLowerCase().replace(/[^a-z0-9-]/g, '');
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function resetForm() {
|
|
38
|
-
name = '';
|
|
39
|
-
slug = '';
|
|
40
|
-
error = null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function handleSubmit(event: Event) {
|
|
44
|
-
event.preventDefault();
|
|
45
|
-
error = null;
|
|
46
|
-
|
|
47
|
-
if (!name.trim() || !slug.trim()) {
|
|
48
|
-
error = 'Name and slug are required';
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
isSubmitting = true;
|
|
53
|
-
try {
|
|
54
|
-
const result = await organizations.create({
|
|
55
|
-
name: name.trim(),
|
|
56
|
-
slug: slug.trim()
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
if (!result.success || !result.data) {
|
|
60
|
-
throw new Error('Failed to create organization');
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
resetForm();
|
|
64
|
-
open = false;
|
|
65
|
-
await invalidateAll();
|
|
66
|
-
await goto(`/admin?orgId=${result.data.id}`);
|
|
67
|
-
} catch (err) {
|
|
68
|
-
error = err instanceof Error ? err.message : 'Failed to create organization';
|
|
69
|
-
} finally {
|
|
70
|
-
isSubmitting = false;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
</script>
|
|
74
|
-
|
|
75
|
-
<Dialog.Root bind:open onOpenChange={(v) => !v && resetForm()}>
|
|
76
|
-
<Dialog.Trigger>
|
|
77
|
-
{#snippet child({ props })}
|
|
78
|
-
<Button {...props}>Create Organization</Button>
|
|
79
|
-
{/snippet}
|
|
80
|
-
</Dialog.Trigger>
|
|
81
|
-
<Dialog.Content class="sm:max-w-[480px]">
|
|
82
|
-
<Dialog.Header>
|
|
83
|
-
<Dialog.Title>Create Organization</Dialog.Title>
|
|
84
|
-
<Dialog.Description>Create a new organization for your instance</Dialog.Description>
|
|
85
|
-
</Dialog.Header>
|
|
86
|
-
<form onsubmit={handleSubmit} class="grid gap-4 py-4">
|
|
87
|
-
<div>
|
|
88
|
-
<Label for="org-name">Organization name</Label>
|
|
89
|
-
<Input
|
|
90
|
-
id="org-name"
|
|
91
|
-
value={name}
|
|
92
|
-
oninput={handleNameInput}
|
|
93
|
-
placeholder="My Organization"
|
|
94
|
-
disabled={isSubmitting}
|
|
95
|
-
class="mt-1"
|
|
96
|
-
/>
|
|
97
|
-
</div>
|
|
98
|
-
<div>
|
|
99
|
-
<Label for="org-slug">Slug</Label>
|
|
100
|
-
<div class="mt-1 flex gap-2">
|
|
101
|
-
<Input
|
|
102
|
-
id="org-slug"
|
|
103
|
-
value={slug}
|
|
104
|
-
oninput={handleSlugInput}
|
|
105
|
-
placeholder="my-organization"
|
|
106
|
-
disabled={isSubmitting}
|
|
107
|
-
class="flex-1"
|
|
108
|
-
/>
|
|
109
|
-
<Button
|
|
110
|
-
type="button"
|
|
111
|
-
variant="outline"
|
|
112
|
-
size="sm"
|
|
113
|
-
onclick={() => (slug = generateSlug(name))}
|
|
114
|
-
disabled={!name.trim() || isSubmitting}
|
|
115
|
-
>
|
|
116
|
-
Generate
|
|
117
|
-
</Button>
|
|
118
|
-
</div>
|
|
119
|
-
<p class="text-muted-foreground mt-1 text-xs">
|
|
120
|
-
Lowercase letters, numbers, and hyphens only.
|
|
121
|
-
</p>
|
|
122
|
-
</div>
|
|
123
|
-
{#if error}
|
|
124
|
-
<p class="text-destructive text-sm">{error}</p>
|
|
125
|
-
{/if}
|
|
126
|
-
<Dialog.Footer>
|
|
127
|
-
<Button
|
|
128
|
-
type="button"
|
|
129
|
-
variant="outline"
|
|
130
|
-
onclick={() => (open = false)}
|
|
131
|
-
disabled={isSubmitting}
|
|
132
|
-
>
|
|
133
|
-
Cancel
|
|
134
|
-
</Button>
|
|
135
|
-
<Button type="submit" disabled={isSubmitting || !name.trim()}>
|
|
136
|
-
{isSubmitting ? 'Creating...' : 'Create'}
|
|
137
|
-
</Button>
|
|
138
|
-
</Dialog.Footer>
|
|
139
|
-
</form>
|
|
140
|
-
</Dialog.Content>
|
|
141
|
-
</Dialog.Root>
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { onMount } from 'svelte';
|
|
3
|
-
import { goto, invalidateAll } from '$app/navigation';
|
|
4
|
-
import * as Card from '@aphexcms/ui/shadcn/card';
|
|
5
|
-
import * as AlertDialog from '@aphexcms/ui/shadcn/alert-dialog';
|
|
6
|
-
import { Button } from '@aphexcms/ui/shadcn/button';
|
|
7
|
-
import { Badge } from '@aphexcms/ui/shadcn/badge';
|
|
8
|
-
import { Trash2 } from '@lucide/svelte';
|
|
9
|
-
import { organizations, type OrganizationListItem } from '@aphexcms/cms-core/client';
|
|
10
|
-
|
|
11
|
-
let orgList = $state<OrganizationListItem[]>([]);
|
|
12
|
-
let error = $state<string | null>(null);
|
|
13
|
-
let isLoading = $state(true);
|
|
14
|
-
let deletingOrgId = $state<string | null>(null);
|
|
15
|
-
let switchingOrgId = $state<string | null>(null);
|
|
16
|
-
let orgToDelete = $state<OrganizationListItem | null>(null);
|
|
17
|
-
|
|
18
|
-
onMount(async () => {
|
|
19
|
-
await loadOrganizations();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
async function loadOrganizations() {
|
|
23
|
-
try {
|
|
24
|
-
isLoading = true;
|
|
25
|
-
const result = await organizations.list();
|
|
26
|
-
|
|
27
|
-
if (!result.success || !result.data) {
|
|
28
|
-
throw new Error('Failed to fetch organizations');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
orgList = result.data;
|
|
32
|
-
} catch (err) {
|
|
33
|
-
error = err instanceof Error ? err.message : 'An unknown error occurred';
|
|
34
|
-
} finally {
|
|
35
|
-
isLoading = false;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async function handleDeleteOrganization(org: OrganizationListItem) {
|
|
40
|
-
if (deletingOrgId) return;
|
|
41
|
-
|
|
42
|
-
deletingOrgId = org.id;
|
|
43
|
-
try {
|
|
44
|
-
const result = await organizations.remove(org.id);
|
|
45
|
-
|
|
46
|
-
if (!result.success) {
|
|
47
|
-
throw new Error(result.error || 'Failed to delete organization');
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
await loadOrganizations();
|
|
51
|
-
await invalidateAll();
|
|
52
|
-
} catch (err) {
|
|
53
|
-
error = err instanceof Error ? err.message : 'Failed to delete organization';
|
|
54
|
-
} finally {
|
|
55
|
-
deletingOrgId = null;
|
|
56
|
-
orgToDelete = null;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async function handleOrgClick(org: OrganizationListItem) {
|
|
61
|
-
if (switchingOrgId) return;
|
|
62
|
-
|
|
63
|
-
if (org.isActive) {
|
|
64
|
-
goto('/admin');
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
switchingOrgId = org.id;
|
|
69
|
-
try {
|
|
70
|
-
const result = await organizations.switch({ organizationId: org.id });
|
|
71
|
-
|
|
72
|
-
if (!result.success) {
|
|
73
|
-
throw new Error(result.error || 'Failed to switch organization');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
await invalidateAll();
|
|
77
|
-
goto('/admin');
|
|
78
|
-
} catch (err) {
|
|
79
|
-
error = err instanceof Error ? err.message : 'Failed to switch organization';
|
|
80
|
-
} finally {
|
|
81
|
-
switchingOrgId = null;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
</script>
|
|
85
|
-
|
|
86
|
-
<Card.Root>
|
|
87
|
-
<Card.Header>
|
|
88
|
-
<Card.Title>Organizations</Card.Title>
|
|
89
|
-
<Card.Description>All organizations in this instance</Card.Description>
|
|
90
|
-
</Card.Header>
|
|
91
|
-
<Card.Content>
|
|
92
|
-
{#if isLoading}
|
|
93
|
-
<p class="text-muted-foreground text-sm">Loading...</p>
|
|
94
|
-
{:else if error}
|
|
95
|
-
<div class="bg-destructive/10 text-destructive border-destructive/20 rounded-lg border p-4">
|
|
96
|
-
<p class="text-sm">{error}</p>
|
|
97
|
-
</div>
|
|
98
|
-
{:else if orgList.length === 0}
|
|
99
|
-
<p class="text-muted-foreground text-sm">No organizations yet</p>
|
|
100
|
-
{:else}
|
|
101
|
-
<div class="space-y-3">
|
|
102
|
-
{#each orgList as org (org.id)}
|
|
103
|
-
<div
|
|
104
|
-
class="hover:bg-muted/50 flex items-center justify-between gap-4 rounded-lg border p-4 transition-colors"
|
|
105
|
-
>
|
|
106
|
-
<button
|
|
107
|
-
class="flex min-w-0 flex-1 flex-col gap-2 text-left sm:flex-row sm:items-center sm:justify-between"
|
|
108
|
-
onclick={() => handleOrgClick(org)}
|
|
109
|
-
disabled={switchingOrgId !== null}
|
|
110
|
-
>
|
|
111
|
-
<div class="min-w-0">
|
|
112
|
-
<p class="truncate font-medium">{org.name}</p>
|
|
113
|
-
<p class="text-muted-foreground truncate text-sm">/{org.slug}</p>
|
|
114
|
-
</div>
|
|
115
|
-
<div class="flex items-center gap-2">
|
|
116
|
-
{#if org.role}
|
|
117
|
-
<Badge variant="outline" class="capitalize">{org.role}</Badge>
|
|
118
|
-
{/if}
|
|
119
|
-
{#if org.isActive}
|
|
120
|
-
<Badge variant="default">Active</Badge>
|
|
121
|
-
{/if}
|
|
122
|
-
<span class="text-muted-foreground hidden text-sm sm:inline">→</span>
|
|
123
|
-
</div>
|
|
124
|
-
</button>
|
|
125
|
-
{#if org.role === 'owner'}
|
|
126
|
-
<Button
|
|
127
|
-
variant="ghost"
|
|
128
|
-
size="icon"
|
|
129
|
-
onclick={(e) => {
|
|
130
|
-
e.stopPropagation();
|
|
131
|
-
orgToDelete = org;
|
|
132
|
-
}}
|
|
133
|
-
disabled={deletingOrgId === org.id}
|
|
134
|
-
class="text-destructive hover:text-destructive hover:bg-destructive/10 h-8 w-8 shrink-0"
|
|
135
|
-
>
|
|
136
|
-
<Trash2 class="h-4 w-4" />
|
|
137
|
-
</Button>
|
|
138
|
-
{/if}
|
|
139
|
-
</div>
|
|
140
|
-
{/each}
|
|
141
|
-
</div>
|
|
142
|
-
{/if}
|
|
143
|
-
</Card.Content>
|
|
144
|
-
</Card.Root>
|
|
145
|
-
|
|
146
|
-
<!-- Delete Confirmation Dialog -->
|
|
147
|
-
<AlertDialog.Root
|
|
148
|
-
open={orgToDelete !== null}
|
|
149
|
-
onOpenChange={(open) => !open && (orgToDelete = null)}
|
|
150
|
-
>
|
|
151
|
-
<AlertDialog.Content>
|
|
152
|
-
<AlertDialog.Header>
|
|
153
|
-
<AlertDialog.Title>Delete Organization</AlertDialog.Title>
|
|
154
|
-
<AlertDialog.Description>
|
|
155
|
-
Are you sure you want to delete <strong>{orgToDelete?.name}</strong>? This action cannot be
|
|
156
|
-
undone. All members will be removed and all pending invitations will be cancelled.
|
|
157
|
-
</AlertDialog.Description>
|
|
158
|
-
</AlertDialog.Header>
|
|
159
|
-
<AlertDialog.Footer>
|
|
160
|
-
<AlertDialog.Cancel onclick={() => (orgToDelete = null)}>Cancel</AlertDialog.Cancel>
|
|
161
|
-
<AlertDialog.Action
|
|
162
|
-
onclick={() => orgToDelete && handleDeleteOrganization(orgToDelete)}
|
|
163
|
-
class="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
164
|
-
>
|
|
165
|
-
Delete Organization
|
|
166
|
-
</AlertDialog.Action>
|
|
167
|
-
</AlertDialog.Footer>
|
|
168
|
-
</AlertDialog.Content>
|
|
169
|
-
</AlertDialog.Root>
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { PageServerLoad } from './$types';
|
|
2
|
-
import { authService } from '$lib/server/auth/service';
|
|
3
|
-
|
|
4
|
-
export const load: PageServerLoad = async ({ locals }) => {
|
|
5
|
-
const { databaseAdapter } = locals.aphexCMS;
|
|
6
|
-
|
|
7
|
-
// Load all orgs and instance settings in parallel
|
|
8
|
-
const [allOrgs, instanceSettings] = await Promise.all([
|
|
9
|
-
databaseAdapter.findAllOrganizations(),
|
|
10
|
-
databaseAdapter.getInstanceSettings()
|
|
11
|
-
]);
|
|
12
|
-
|
|
13
|
-
// Enrich each org with member count and owner info
|
|
14
|
-
const orgsWithDetails = await Promise.all(
|
|
15
|
-
allOrgs.map(async (org) => {
|
|
16
|
-
const members = await databaseAdapter.findOrganizationMembers(org.id);
|
|
17
|
-
const owner = members.find((m) => m.role === 'owner');
|
|
18
|
-
|
|
19
|
-
let ownerEmail: string | undefined;
|
|
20
|
-
if (owner) {
|
|
21
|
-
const ownerUser = await authService.getUserById(owner.userId);
|
|
22
|
-
ownerEmail = ownerUser?.email;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return {
|
|
26
|
-
id: org.id,
|
|
27
|
-
name: org.name,
|
|
28
|
-
slug: org.slug,
|
|
29
|
-
role: 'owner' as const,
|
|
30
|
-
isActive: false,
|
|
31
|
-
createdBy: org.createdBy,
|
|
32
|
-
createdAt: org.createdAt,
|
|
33
|
-
memberCount: members.length,
|
|
34
|
-
ownerEmail
|
|
35
|
-
};
|
|
36
|
-
})
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
return {
|
|
40
|
-
organizations: orgsWithDetails,
|
|
41
|
-
instanceSettings
|
|
42
|
-
};
|
|
43
|
-
};
|