Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
93 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
801eed8
move filters button to right side and fix search placeholder
HarshMN2345 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
b8a472f
lint issue
HarshMN2345 Sep 30, 2025
69d2cd6
removed button and using link in updateTopics
HarshMN2345 Sep 30, 2025
5cb9b63
Unnecessary padding above Name input
HarshMN2345 Sep 30, 2025
448ab66
Remove unnecessary extra spacing here
HarshMN2345 Sep 30, 2025
dbee85e
Read the guide in the docs should open a new tab
HarshMN2345 Sep 30, 2025
13c68f0
Add wizard footer with Create button (Currently we have a divider and…
HarshMN2345 Sep 30, 2025
a41cfd8
fix subscribers screen
HarshMN2345 Sep 30, 2025
8a9efc1
fixed the width of provider popup
HarshMN2345 Sep 30, 2025
77b01de
fixed align action menu issue
HarshMN2345 Sep 30, 2025
6bfa007
refactor the flow for push notifcations
HarshMN2345 Sep 30, 2025
3393329
Fix topics modal target counts based on provider typr
HarshMN2345 Sep 30, 2025
71997d2
remove any
HarshMN2345 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
fde78df
improvements
HarshMN2345 Oct 7, 2025
95bbe56
update: resizing on indexes.
ItzNotABug Oct 7, 2025
4288215
fix: accessor.
ItzNotABug Oct 7, 2025
ce3d0e0
done changes liek replacing anchor with Links and removing bad empty …
HarshMN2345 Oct 7, 2025
8ea21ad
lint issue
HarshMN2345 Oct 7, 2025
920d4f7
svelte 5 migartion
HarshMN2345 Oct 7, 2025
c470fc4
lint error
HarshMN2345 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
33db74b
clarify effect deps
HarshMN2345 Oct 7, 2025
fc78c44
remove: legacy logic.
ItzNotABug Oct 7, 2025
6fef9a2
update: proper type.
ItzNotABug Oct 7, 2025
7f5c0df
replace div with Layout.Stack in popoverContent and inline maxWidth s…
HarshMN2345 Oct 8, 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
72d4494
Remove pnpm store caching from Docker build
TorstenDittmann Oct 13, 2025
f0931a2
Merge pull request #2468 from appwrite/fix-dockerfile-railway
TorstenDittmann Oct 13, 2025
d982b81
Enable email verificaiton on Stage
Meldiron Oct 14, 2025
3b9d688
Merge pull request #2469 from appwrite/chore-enable-stage-emai-verifi…
Meldiron Oct 14, 2025
8c3b1b6
use page currentPlan for limits to refresh button state on org switch
HarshMN2345 Oct 14, 2025
8c405c4
fix: prevent redirect loop on verify-email page
HarshMN2345 Oct 14, 2025
bafa3c7
Merge pull request #2470 from appwrite/fix-disabled-button-stae
ItzNotABug Oct 14, 2025
0039c38
Merge pull request #2471 from appwrite/fix-redirect-loop-issue
Meldiron Oct 14, 2025
f60a231
Disable email veirifaction on prod, for rolling update
Meldiron Oct 14, 2025
47d697d
Merge pull request #2473 from appwrite/chore-rolling-update-email-ver…
Meldiron Oct 14, 2025
3c434ac
Update src/routes/(console)/project-[region]-[project]/messaging/topi…
HarshMN2345 Oct 15, 2025
48038c9
Merge pull request #2422 from appwrite/fix-SER-416-issues-in-messagin…
Meldiron Oct 15, 2025
bccbf5d
fix: platform created props flow.
ItzNotABug Oct 16, 2025
aa34fce
fix: type.
ItzNotABug Oct 16, 2025
74f168f
Apply suggestion from @ItzNotABug
ItzNotABug Oct 16, 2025
2ad36d4
update: svelte, diff titles, new prop.
ItzNotABug Oct 16, 2025
8cdf6ed
fix: platform type.
ItzNotABug Oct 16, 2025
2748012
fix: param.
ItzNotABug Oct 16, 2025
f350ecb
lint.
ItzNotABug Oct 16, 2025
1590206
Merge pull request #2476 from appwrite/fix-dat-807
ItzNotABug Oct 16, 2025
7a4f9a9
Merge branch 'main' into 'multiple-terminologies'.
ItzNotABug Oct 16, 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
22 changes: 14 additions & 8 deletions src/lib/actions/analytics.ts
Original file line number Diff line number Diff line change
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
37 changes: 37 additions & 0 deletions src/lib/helpers/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,43 @@ 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 (/[sxz]$/.test(lower) || /[cs]h$/.test(lower)) {
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
21 changes: 21 additions & 0 deletions src/lib/stores/navigation.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
import { resolve } from '$app/paths';
import { goto } from '$app/navigation';
import { writable } from 'svelte/store';
import type { Pathname, RouteId, RouteParams } from '$app/types';

export const navigationCancelled = writable(false);

// 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 navigate<T extends RouteId>(
route: T,
params?: Record<string, string>
): Promise<void> {
// type cast is necessary here!
const resolveArgs = params ? ([route, params] as [T, RouteParams<T>]) : [route];
const resolvedPathname = resolve(...(resolveArgs as ResolveArgs<T>));

return goto(resolvedPathname);
}
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,
Databases // DocumentsDB later
} 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 Databases(clientProject), // documentsDB later
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
@@ -0,0 +1,51 @@
import type { Page } from '@sveltejs/kit';
import { page as pageState } from '$app/state';

import { useTerminology } from './terminology';
import { Submit, Click } from '$lib/actions/analytics';
import type { AnalyticsResult, TerminologyResult, TerminologyShape } from './types';

export function useAnalytics(pageOrTerms: Page | TerminologyResult = pageState): AnalyticsResult {
const terminology = 'source' in pageOrTerms ? pageOrTerms : useTerminology(pageOrTerms);

const createSubmitHandler = <TAction extends string>(termType: keyof TerminologyShape) => {
return (action: TAction) => {
const term = terminology.source[termType];
if (!term) {
throw new Error(`No ${termType} terminology found`);
}
const enumKey = `${term.title.singular}${action}`;
return Submit[enumKey as keyof typeof Submit];
};
};

const createClickHandler = <TAction extends string>(termType: keyof TerminologyShape) => {
return (action: TAction) => {
const term = terminology.source[termType];
if (!term) {
throw new Error(`No ${termType} terminology found`);
}
const enumKey = `Database${term.title.singular}${action}`;
return Click[enumKey as keyof typeof Click];
};
};

const result: AnalyticsResult = { submit: {}, click: {} };

if (terminology.entity) {
result.click.entity = createClickHandler('entity');
result.submit.entity = createSubmitHandler('entity');
}

if (terminology.field) {
result.click.field = createClickHandler('field');
result.submit.field = createSubmitHandler('field');
}

if (terminology.record) {
result.click.record = createClickHandler('record');
result.submit.record = createSubmitHandler('record');
}

return result;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Page } from '@sveltejs/kit';
import { page as pageState } from '$app/state';

import { useTerminology } from './terminology';
import { Dependencies } from '$lib/constants';
import type { DependenciesResult, Term, TerminologyResult } from './types';

export function useDependencies(
pageOrTerms: Page | TerminologyResult = pageState
): DependenciesResult {
// source is in `TerminologyResult`.
const terminology = 'source' in pageOrTerms ? pageOrTerms : useTerminology(pageOrTerms);

const getDependencies = (term: { title: Term }) => ({
singular: Dependencies[term.title.singular.toUpperCase() as keyof typeof Dependencies],
plural: Dependencies[term.title.plural.toUpperCase() as keyof typeof Dependencies]
});

return {
entity: terminology.entity ? getDependencies(terminology.entity) : undefined,
field: terminology.field ? getDependencies(terminology.field) : undefined,
record: terminology.record ? getDependencies(terminology.record) : undefined
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './types';
export * from './analytics';
export * from './terminology';
export * from './dependencies';
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import type { Page } from '@sveltejs/kit';
import { page as pageStage } from '$app/state';

import { type Models } from '@appwrite.io/console';
import { capitalize, plural } from '$lib/helpers/string';
import type { Columns } from '$database/table-[table]/store';
import type { Term, TerminologyResult, TerminologyShape } from '$database/(entity)/helpers/types';

export type DatabaseType = 'legacy' | 'tablesdb' | 'documentsdb' | 'vectordb';
export type Entity = Partial<Models.Table>;
export type Field = Partial<Columns>;

export const baseTerminology = {
tablesdb: {
entity: 'table',
field: 'column',
record: 'row'
},
documentsdb: {
entity: 'collection',
record: 'document'
},
legacy: {
entity: 'collection',
field: 'attribute',
record: 'document'
},
vectordb: {}
} as const;

const createTerm = (singular: string, pluralForm: string): Term => {
return { singular, plural: pluralForm };
};

// transforms a base into lower/title variants
const createTermVariants = (baseTerm: string) => ({
lower: createTerm(baseTerm, plural(baseTerm)),
title: createTerm(capitalize(baseTerm), plural(capitalize(baseTerm)))
});

// transforms terminology for a database type
const transformDatabaseTerms = (terms: Partial<TerminologyShape>) =>
Object.fromEntries(
Object.entries(terms).map(([key, term]) => [
key,
term ? createTermVariants(term) : undefined
])
);

// build the terminology data
const terminologyData = Object.fromEntries(
Object.entries(baseTerminology).map(([dbType, terms]) => [
dbType,
transformDatabaseTerms(terms)
])
);

export function useTerminology(page: Page = pageStage): TerminologyResult {
const type = page.data?.database?.type as DatabaseType;
const dbTerminologies = terminologyData[type] || {};
return {
source: dbTerminologies,
field: dbTerminologies.field,
record: dbTerminologies.record,
entity: dbTerminologies.entity
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Click, Submit } from '$lib/actions/analytics';
import type { baseTerminology } from './terminology';
import { Dependencies } from '$lib/constants';

export type TerminologyShape = {
entity: string;
field?: string;
record?: string;
};

export type Term = { singular: string; plural: string };

export type TerminologyResult = {
source: {
entity?: { lower: Term; title: Term };
field?: { lower: Term; title: Term };
record?: { lower: Term; title: Term };
};
entity: { lower: Term; title: Term };
field?: { lower: Term; title: Term };
record?: { lower: Term; title: Term };
};

// for derived analytics!
type ExtractActionsForPrefix<TPrefix extends string> = {
[K in keyof typeof Submit]: K extends `${TPrefix}${infer Action}` ? Action : never;
}[keyof typeof Submit];

type ExtractClickActionsForPrefix<TPrefix extends string> = {
[K in keyof typeof Click]: K extends `Database${TPrefix}${infer Action}` ? Action : never;
}[keyof typeof Click];

type TermValuesForKey<TKey extends keyof TerminologyShape> = {
[K in keyof typeof baseTerminology]: TKey extends keyof (typeof baseTerminology)[K]
? (typeof baseTerminology)[K][TKey]
: never;
}[keyof typeof baseTerminology];

type SubmitActionsFor<TKey extends keyof TerminologyShape> = ExtractActionsForPrefix<
Capitalize<TermValuesForKey<TKey>>
>;

type ClickActionsFor<TKey extends keyof TerminologyShape> = ExtractClickActionsForPrefix<
Capitalize<TermValuesForKey<TKey>>
>;

export type AnalyticsResult = {
submit: {
entity?: (action: SubmitActionsFor<'entity'>) => Submit;
field?: (action: SubmitActionsFor<'field'>) => Submit;
record?: (action: SubmitActionsFor<'record'>) => Submit;
};
click: {
entity?: (action: ClickActionsFor<'entity'>) => Click;
field?: (action: ClickActionsFor<'field'>) => Click;
record?: (action: ClickActionsFor<'record'>) => Click;
};
};

// for derived dependencies!
export type DependenciesResult = {
[K in keyof Omit<TerminologyResult, 'source'>]: {
singular: Dependencies;
plural: Dependencies;
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './helpers';
export * from './settings';
export { default as Usage } from './usage/view.svelte';
export { default as EntityContainer } from './view/container.svelte';
Loading