Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
f6f2d94
feat: multi-terminology support [wip].
ItzNotABug Sep 28, 2025
3fae9d6
update: restructure dirs.
ItzNotABug Sep 29, 2025
bc16dea
update: abstracted indexes for base views.
ItzNotABug Sep 29, 2025
cd5c781
remove: duplicate components.
ItzNotABug Sep 29, 2025
e451f18
Merge branch 'index-suggestions' into 'multiple-terminologies'.
ItzNotABug Sep 30, 2025
a3eb1c8
fix: import.
ItzNotABug Sep 30, 2025
5eca86e
update: imports and folder structure.
ItzNotABug Sep 30, 2025
aca5241
lint.
ItzNotABug Sep 30, 2025
88a153e
Merge branch 'main' into multiple-terminologies
ItzNotABug Sep 30, 2025
d00e280
misc: changes, docs update, svelte5 migration.
ItzNotABug Sep 30, 2025
7410780
Merge branch 'main' into 'multiple-terminologies'.
ItzNotABug Oct 3, 2025
8f5f4c1
simplify.
ItzNotABug Oct 3, 2025
645ae62
update: migrate empty sheet as a reusable component.
ItzNotABug Oct 3, 2025
6cecb2c
lint.
ItzNotABug Oct 3, 2025
4354c90
update: misc, address a todo.
ItzNotABug Oct 3, 2025
e87894d
update: make breadcrumbs and header reusable.
ItzNotABug Oct 3, 2025
ef7d6d4
update: improved context and terminology sharing.
ItzNotABug Oct 3, 2025
d2c2870
lint.
ItzNotABug Oct 3, 2025
d5afa9b
remove: leftover log
ItzNotABug Oct 5, 2025
466cc8d
address: todo.
ItzNotABug Oct 7, 2025
31aa0ff
address: todo for `trackError`.
ItzNotABug Oct 7, 2025
e1aa598
fixes, stricter params.
ItzNotABug Oct 7, 2025
74e6eae
fixes, stricter params.
ItzNotABug Oct 7, 2025
e06980a
fix: `getContext` undefined issue.
ItzNotABug Oct 7, 2025
95bbe56
update: resizing on indexes.
ItzNotABug Oct 7, 2025
4288215
fix: accessor.
ItzNotABug Oct 7, 2025
a871810
fix: slash issues on routes causing flawed selection on tabs.
ItzNotABug Oct 7, 2025
470a4e1
Merge branch 'main' into 'multiple-terminologies'.
ItzNotABug Oct 7, 2025
7d7dfab
use: `creatingEntity`.
ItzNotABug Oct 7, 2025
fc78c44
remove: legacy logic.
ItzNotABug Oct 7, 2025
6fef9a2
update: proper type.
ItzNotABug Oct 7, 2025
4ef68a4
update: migrate.
ItzNotABug Oct 9, 2025
2ce3811
remove: database derived store.
ItzNotABug Oct 9, 2025
db8420d
address comments, fix nav bug.
ItzNotABug Oct 9, 2025
aea5e82
misc.
ItzNotABug Oct 9, 2025
2abb2bc
address comment with hardcoded paths for `nonSheetPages` checks.
ItzNotABug Oct 9, 2025
9d1f4ce
misc: fixes.
ItzNotABug Oct 9, 2025
ea665d7
misc: fixes.
ItzNotABug Oct 9, 2025
8a449d5
update: moreee changes!
ItzNotABug Oct 9, 2025
43eff98
feat: wrapped sdk support.
ItzNotABug Oct 10, 2025
e97ef6c
bump: sdk for `DocumentsDB`.
ItzNotABug Oct 10, 2025
f0d1a5d
update: sdks side updates.
ItzNotABug Oct 10, 2025
f49f888
update: sdks side updates.
ItzNotABug Oct 10, 2025
1f254a6
address comments.
ItzNotABug Oct 10, 2025
604f0ab
Merge branch 'main' into multiple-terminologies
ItzNotABug Oct 10, 2025
d53c8ef
fix: add fallback.
ItzNotABug Oct 10, 2025
ae9aa07
fix: infy-loop
ItzNotABug Oct 10, 2025
0e7938a
fix: `$derived` overuse.
ItzNotABug Oct 10, 2025
222eb9a
fix: relationships.
ItzNotABug Oct 11, 2025
7c4c256
address: pending todo.
ItzNotABug Oct 13, 2025
83a8870
address rabbits comment.
ItzNotABug Oct 13, 2025
f1712be
address rabbits comment.
ItzNotABug Oct 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
},
"dependencies": {
"@ai-sdk/svelte": "^1.1.24",
"@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@636ed39",
"@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@2659",
"@appwrite.io/pink-icons": "0.25.0",
"@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@8f82877",
"@appwrite.io/pink-legacy": "^1.0.3",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 16 additions & 10 deletions src/lib/actions/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const analytics = Analytics({
});

export function trackEvent(name: string, data: object = null): void {
if (!isTrackingAllowed()) {
if (!name || !isTrackingAllowed()) {
return;
}

Expand All @@ -76,7 +76,7 @@ export function trackEvent(name: string, data: object = null): void {
}

export function trackError(exception: Error, event: Submit): void {
if (exception instanceof AppwriteException && exception.type) {
if (exception instanceof AppwriteException && exception.type && event) {
trackEvent(Submit.Error, {
type: exception.type,
form: event
Expand Down Expand Up @@ -148,11 +148,14 @@ export enum Click {
ConnectRepositoryClick = 'click_connect_repository',
CreditsRedeemClick = 'click_credits_redeem',
CloudSignupClick = 'click_cloud_signup',

DatabaseColumnDelete = 'click_column_delete',
DatabaseIndexDelete = 'click_index_delete',
DatabaseTableDelete = 'click_table_delete',
DatabaseRowDelete = 'click_row_delete',
DatabaseDatabaseDelete = 'click_database_delete',
DatabaseImportCsv = 'click_database_import_csv',

DomainCreateClick = 'click_domain_create',
DomainDeleteClick = 'click_domain_delete',
DomainRetryDomainVerificationClick = 'click_domain_retry_domain_verification',
Expand Down Expand Up @@ -265,7 +268,7 @@ export enum Submit {
AuthSessionAlertsUpdate = 'submit_auth_session_alerts_update',
AuthMembershipPrivacyUpdate = 'submit_auth_membership_privacy_update',
AuthMockNumbersUpdate = 'submit_auth_mock_numbers_update',
AuthInvalidateSesssion = 'submit_auth_invalidate_session',
AuthInvalidateSession = 'submit_auth_invalidate_session',
SessionsLengthUpdate = 'submit_sessions_length_update',
SessionsLimitUpdate = 'submit_sessions_limit_update',
SessionDelete = 'submit_session_delete',
Expand All @@ -284,15 +287,18 @@ export enum Submit {
RowDelete = 'submit_row_delete',
RowUpdate = 'submit_row_update',
RowUpdatePermissions = 'submit_row_update_permissions',

IndexCreate = 'submit_index_create',
IndexDelete = 'submit_index_delete',
TableCreate = 'submit_row_create',
TableDelete = 'submit_row_delete',
TableUpdateName = 'submit_row_update_name',
TableUpdatePermissions = 'submit_row_update_permissions',
TableUpdateSecurity = 'submit_row_update_security',
TableUpdateEnabled = 'submit_row_update_enabled',
TableUpdateDisplayNames = 'submit_row_update_display_names',

TableCreate = 'submit_table_create',
TableDelete = 'submit_table_delete',
TableUpdateName = 'submit_table_update_name',
TableUpdatePermissions = 'submit_table_update_permissions',
TableUpdateSecurity = 'submit_table_update_security',
TableUpdateEnabled = 'submit_table_update_enabled',
TableUpdateDisplayNames = 'submit_table_update_display_names',

FunctionCreate = 'submit_function_create',
FunctionDelete = 'submit_function_delete',
FunctionUpdateName = 'submit_function_update_name',
Expand Down
15 changes: 8 additions & 7 deletions src/lib/components/backupRestoreBox.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,22 @@
}

function updateOrAddItem(payload: Payload) {
// todo: @itznotabug - might need a change to $table?
const { $id, status, $collection, policyId } = payload;
if ($collection === 'archives' && policyId !== null) {
// the internal structure still uses `$collection`,
// and is basically an identifier of the op. type here!
const { $id, status, $collection: type, policyId } = payload;
if (type === 'archives' && policyId !== null) {
return;
}

if ($collection in backupRestoreItems) {
const collectionMap = backupRestoreItems[$collection];
if (type in backupRestoreItems) {
const collectionMap = backupRestoreItems[type];

if (collectionMap.has($id)) {
collectionMap.get($id).status = status;
if (status === 'completed') {
invalidate(Dependencies.BACKUPS);

if ($collection === 'restorations') {
if (type === 'restorations') {
const { newId, newName } =
collectionMap.get($id).options?.['databases']?.['database'][0] || {};

Expand All @@ -81,7 +82,7 @@
} else if (status === 'pending' || status === 'processing' || status === 'uploading') {
collectionMap.set($id, payload);
}
backupRestoreItems[$collection] = collectionMap;
backupRestoreItems[type] = collectionMap;
}
}

Expand Down
43 changes: 43 additions & 0 deletions src/lib/helpers/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,49 @@ export function singular(str: string): string {
return str.replace(/s$/, '');
}

/**
* Given a string, returns the plural version of it.
*
* Handles common English pluralization rules:
* - Words ending in consonant + y → ies
* - Words ending in vowel + y → s
* - Words ending in sibilants (s, sh, ch, x, z) → es
* - Regular words → s
*
* @export
* @param {string} str
* @returns {string}
*/
export function plural(str: string): string {
if (!str) return str;

const lower = str.toLowerCase();

// Words ending in sibilants: s, sh, ch, x, z
if (
lower.endsWith('s') ||
lower.endsWith('x') ||
lower.endsWith('z') ||
lower.endsWith('ch') ||
lower.endsWith('sh')
) {
return str + 'es';
}

// Words ending in consonant + y → ies
// Words ending in vowel + y → s
if (str.endsWith('y')) {
const beforeY = str.slice(-2, -1).toLowerCase();
if (beforeY && !['a', 'e', 'i', 'o', 'u'].includes(beforeY)) {
return str.slice(0, -1) + 'ies';
}
return str + 's';
}

// Default: add 's'
return str + 's';
}

/**
* Convert a dash/underscore/space separated string to camelCase.
*
Expand Down
36 changes: 36 additions & 0 deletions src/lib/stores/navigation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { resolve } from '$app/paths';
import { goto } from '$app/navigation';
import type { Pathname, RouteId, RouteParams } from '$app/types';

// taken directly from svelte's source!
type ResolveArgs<T extends RouteId | Pathname> = T extends RouteId
? RouteParams<T> extends Record<string, never>
? [route: T]
: [route: T, params: RouteParams<T>]
: [route: T];

export function withPath(base: string, ...parts: string[]) {
// remove slashes at the end if any
const normalizedBase = base.replace(/\/+$/, '');

// remove slashes at the start of each part if any
const normalizedParts = parts.map((part) => part.replace(/^\/+/, ''));

// join em with slashes
return [normalizedBase, ...normalizedParts].join('/');
}

export function resolveRoute<T extends RouteId>(route: T, params?: Record<string, string>) {
// type cast is necessary here!
const resolveArgs = params ? ([route, params] as [T, RouteParams<T>]) : [route];

return resolve(...(resolveArgs as ResolveArgs<T>));
}

export function navigate<T extends RouteId>(
route: T,
params?: Record<string, string>
): Promise<void> {
// type cast is necessary here!
return goto(resolveRoute(route, params));
}
4 changes: 3 additions & 1 deletion src/lib/stores/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import {
Sites,
Tokens,
TablesDB,
Domains
Domains,
DocumentsDB
} from '@appwrite.io/console';
import { Billing } from '../sdk/billing';
import { Backups } from '../sdk/backups';
Expand Down Expand Up @@ -131,6 +132,7 @@ const sdkForProject = {
migrations: new Migrations(clientProject),
sites: new Sites(clientProject),
tablesDB: new TablesDB(clientProject),
documentsDB: new DocumentsDB(clientProject),
console: new Console(clientProject) // for suggestions API
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
type: 'success',
message: 'Updated session invalidation check.'
});
trackEvent(Submit.AuthInvalidateSesssion);
trackEvent(Submit.AuthInvalidateSession);
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
trackError(error, Submit.AuthInvalidateSesssion);
trackError(error, Submit.AuthInvalidateSession);
}
}
</script>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,48 +1,53 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { base } from '$app/paths';
import { page } from '$app/state';
import { Empty, PaginationWithLimit } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { Container, ResponsiveContainerHeader } from '$lib/layout';
import type { Models } from '@appwrite.io/console';
import type { PageData } from './$types';
import Create from './create.svelte';
import Grid from './grid.svelte';
import { columns } from './store';
import Table from './table.svelte';
import type { PageProps } from './$types';
import { Icon } from '@appwrite.io/pink-svelte';
import { registerCommands } from '$lib/commandCenter';
import { canWriteDatabases } from '$lib/stores/roles';
import { Icon } from '@appwrite.io/pink-svelte';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
import EmptySearch from '$lib/components/emptySearch.svelte';
export let data: PageData;
import { resolveRoute } from '$lib/stores/navigation';
const { data }: PageProps = $props();
let showCreate = false;
const project = page.params.project;
let showCreate = $state(false);
async function handleCreate(event: CustomEvent<Models.Database>) {
showCreate = false;
await goto(
`${base}/project-${page.params.region}-${project}/databases/database-${event.detail.$id}`
resolveRoute('/(console)/project-[region]-[project]/databases/database-[database]', {
...page.params,
database: event.detail.$id
})
);
}
$: $registerCommands([
{
label: 'Create database',
callback: () => {
showCreate = true;
},
keys: ['c'],
disabled: showCreate || !$canWriteDatabases,
icon: IconPlus,
group: 'databases',
rank: 10
}
]);
$effect(() => {
$registerCommands([
{
label: 'Create database',
callback: () => {
showCreate = true;
},
keys: ['c'],
disabled: showCreate || !$canWriteDatabases,
icon: IconPlus,
group: 'databases',
rank: 10
}
]);
});
</script>

<Container>
Expand Down Expand Up @@ -74,7 +79,7 @@
{:else if data.search}
<EmptySearch target="databases" hidePagination>
<Button
href={`${base}/project-${page.params.region}-${page.params.project}/databases`}
href={resolveRoute('/(console)/project-[region]-[project]/databases', page.params)}
size="s"
secondary>Clear Search</Button>
</EmptySearch>
Expand Down
Loading