mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge pull request #897 from appwrite/fix-command-center
chore: add missing commands
This commit is contained in:
@@ -5,6 +5,7 @@ import { onMount } from 'svelte';
|
||||
import { derived, writable } from 'svelte/store';
|
||||
import { nanoid } from 'nanoid/non-secure';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
import { omit } from '$lib/helpers/omit';
|
||||
|
||||
const groups = [
|
||||
'ungrouped',
|
||||
@@ -18,6 +19,9 @@ const groups = [
|
||||
'databases',
|
||||
'functions',
|
||||
'messaging',
|
||||
'messages',
|
||||
'providers',
|
||||
'topics',
|
||||
'storage',
|
||||
'domains',
|
||||
'webhooks',
|
||||
@@ -45,6 +49,7 @@ type BaseCommand = {
|
||||
forceEnable?: boolean;
|
||||
group?: CommandGroup;
|
||||
icon?: string;
|
||||
image?: string;
|
||||
rank?: number;
|
||||
nested?: boolean;
|
||||
keepOpen?: boolean;
|
||||
@@ -70,7 +75,23 @@ export const disabledMap = writable<Map<string, boolean>>(new Map());
|
||||
|
||||
// Derived stores
|
||||
export const commands = derived(commandMap, ($commandMap) => {
|
||||
return Array.from($commandMap.values()).flat();
|
||||
const res: Command[] = [];
|
||||
const keys = new Set<string>();
|
||||
|
||||
const allCommands = Array.from($commandMap.values()).flat().toReversed();
|
||||
|
||||
for (const command of allCommands) {
|
||||
if (isKeyedCommand(command) && !command.disabled) {
|
||||
const keysString = command.keys.join('+');
|
||||
if (keys.has(keysString)) {
|
||||
res.push(omit(command, 'keys'));
|
||||
continue;
|
||||
}
|
||||
keys.add(keysString);
|
||||
}
|
||||
res.push(command);
|
||||
}
|
||||
return res;
|
||||
});
|
||||
|
||||
const commandsEnabled = derived(disabledMap, ($disabledMap) => {
|
||||
@@ -110,9 +131,9 @@ function hasDisputing(command: KeyedCommand, allCommands: Command[]) {
|
||||
}
|
||||
|
||||
export const commandCenterKeyDownHandler = derived(
|
||||
[commandMap, commandsEnabled, wizard],
|
||||
([$commandMap, enabled, $wizard]) => {
|
||||
const commandsArr = Array.from($commandMap.values()).flat();
|
||||
[commands, commandsEnabled, wizard],
|
||||
([$commands, enabled, $wizard]) => {
|
||||
const commandsArr = $commands;
|
||||
let recentKeyCodes: number[] = [];
|
||||
let validCommands: KeyedCommand[] = [];
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
<script lang="ts">
|
||||
import { providers } from '$routes/console/project-[project]/messaging/providers/store';
|
||||
import {
|
||||
messageParams,
|
||||
providerType,
|
||||
targetsById
|
||||
} from '$routes/console/project-[project]/messaging/wizard/store';
|
||||
import { MessagingProviderType } from '@appwrite.io/console';
|
||||
import Template from './template.svelte';
|
||||
import { wizard } from '$lib/stores/wizard';
|
||||
import Create from '$routes/console/project-[project]/messaging/create.svelte';
|
||||
import { topicsById } from '$routes/console/project-[project]/messaging/store';
|
||||
|
||||
let search = '';
|
||||
|
||||
let options = Object.entries(providers).map(([type, option]) => {
|
||||
return {
|
||||
label: option.name,
|
||||
icon: option.icon,
|
||||
callback() {
|
||||
if (
|
||||
type !== MessagingProviderType.Email &&
|
||||
type !== MessagingProviderType.Sms &&
|
||||
type !== MessagingProviderType.Push
|
||||
)
|
||||
return;
|
||||
$providerType = type;
|
||||
$topicsById = {};
|
||||
$targetsById = {};
|
||||
const common = {
|
||||
topics: [],
|
||||
users: [],
|
||||
targets: []
|
||||
};
|
||||
switch (type) {
|
||||
case MessagingProviderType.Email:
|
||||
$messageParams[$providerType] = {
|
||||
...common,
|
||||
subject: '',
|
||||
content: ''
|
||||
};
|
||||
break;
|
||||
case MessagingProviderType.Sms:
|
||||
$messageParams[$providerType] = {
|
||||
...common,
|
||||
content: ''
|
||||
};
|
||||
break;
|
||||
case MessagingProviderType.Push:
|
||||
$messageParams[$providerType] = {
|
||||
...common,
|
||||
title: '',
|
||||
body: '',
|
||||
data: [['', '']]
|
||||
};
|
||||
break;
|
||||
}
|
||||
wizard.start(Create);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
$: filteredOptions = options.filter((option) => {
|
||||
return option.label.toLowerCase().includes(search.toLowerCase());
|
||||
});
|
||||
</script>
|
||||
|
||||
<Template options={filteredOptions} bind:search>
|
||||
<div class="u-flex u-cross-center u-gap-8" slot="option" let:option>
|
||||
<i class="icon-{option.icon}" />
|
||||
<span>{option.label}</span>
|
||||
</div>
|
||||
</Template>
|
||||
@@ -78,3 +78,9 @@ export const FilesPanel: SubPanel = {
|
||||
name: 'Files',
|
||||
component: Files
|
||||
};
|
||||
|
||||
import CreateMessage from './createMessage.svelte';
|
||||
export const CreateMessagePanel: SubPanel = {
|
||||
name: 'Create Message',
|
||||
component: CreateMessage
|
||||
};
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
This is the root command panel. It precedes all other command panels.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { app } from '$lib/stores/app';
|
||||
import { debounce } from '$lib/helpers/debounce';
|
||||
import { isMac } from '$lib/helpers/platform';
|
||||
import { commands, searchers, type Command, isKeyedCommand } from '../commands';
|
||||
@@ -54,7 +56,13 @@
|
||||
<Template options={results} bind:search searchPlaceholder="Search for commands or content...">
|
||||
<div slot="option" class="u-flex u-main-space-between content" let:option={command}>
|
||||
<div class="u-flex u-gap-8 u-cross-center">
|
||||
<i class="icon-{command.icon ?? 'arrow-sm-right'}" />
|
||||
{#if command.image}
|
||||
<img
|
||||
src={`${base}/icons/${$app.themeInUse}/color/${command.image}.svg`}
|
||||
alt={command.label} />
|
||||
{:else}
|
||||
<i class="icon-{command.icon ?? 'arrow-sm-right'}" />
|
||||
{/if}
|
||||
<span>
|
||||
{command.label}
|
||||
</span>
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { project } from '$routes/console/project-[project]/store';
|
||||
import { get } from 'svelte/store';
|
||||
import { type Searcher } from '../commands';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { MessagingProviderType } from '@appwrite.io/console';
|
||||
|
||||
const getLabel = (message) => {
|
||||
switch (message.providerType) {
|
||||
case MessagingProviderType.Push:
|
||||
return message.data.title;
|
||||
case MessagingProviderType.Sms:
|
||||
return message.data.content;
|
||||
case MessagingProviderType.Email:
|
||||
return message.data.subject;
|
||||
default:
|
||||
return 'null';
|
||||
}
|
||||
};
|
||||
|
||||
const getIcon = (message) => {
|
||||
switch (message.providerType) {
|
||||
case MessagingProviderType.Push:
|
||||
return 'device-mobile';
|
||||
case MessagingProviderType.Sms:
|
||||
return 'annotation';
|
||||
case MessagingProviderType.Email:
|
||||
return 'mail';
|
||||
default:
|
||||
return 'send';
|
||||
}
|
||||
};
|
||||
|
||||
export const messagesSearcher = (async (query: string) => {
|
||||
const { messages } = await sdk.forProject.messaging.listMessages([], query || undefined);
|
||||
|
||||
const projectId = get(project).$id;
|
||||
|
||||
return messages
|
||||
.filter((message) => getLabel(message).toLowerCase().includes(query.toLowerCase()))
|
||||
.map(
|
||||
(message) =>
|
||||
({
|
||||
group: 'messages',
|
||||
label: getLabel(message),
|
||||
callback: () => {
|
||||
goto(`/console/project-${projectId}/messaging/message-${message.$id}`);
|
||||
},
|
||||
icon: getIcon(message)
|
||||
}) as const
|
||||
);
|
||||
}) satisfies Searcher;
|
||||
@@ -0,0 +1,33 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { project } from '$routes/console/project-[project]/store';
|
||||
import { get } from 'svelte/store';
|
||||
import type { Searcher } from '../commands';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { getProviderDisplayNameAndIcon } from '$routes/console/project-[project]/messaging/provider.svelte';
|
||||
|
||||
const getIcon = (provider: string) => {
|
||||
const { icon } = getProviderDisplayNameAndIcon(provider);
|
||||
return icon;
|
||||
};
|
||||
|
||||
export const providersSearcher = (async (query: string) => {
|
||||
const { providers } = await sdk.forProject.messaging.listProviders([], query || undefined);
|
||||
|
||||
const projectId = get(project).$id;
|
||||
|
||||
return providers
|
||||
.filter((provider) => provider.name.toLowerCase().includes(query.toLowerCase()))
|
||||
.map(
|
||||
(provider) =>
|
||||
({
|
||||
group: 'providers',
|
||||
label: provider.name,
|
||||
callback: () => {
|
||||
goto(
|
||||
`/console/project-${projectId}/messaging/providers/provider-${provider.$id}`
|
||||
);
|
||||
},
|
||||
image: getIcon(provider.provider)
|
||||
}) as const
|
||||
);
|
||||
}) satisfies Searcher;
|
||||
@@ -0,0 +1,25 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { project } from '$routes/console/project-[project]/store';
|
||||
import { get } from 'svelte/store';
|
||||
import type { Searcher } from '../commands';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
|
||||
export const topicsSearcher = (async (query: string) => {
|
||||
const { topics } = await sdk.forProject.messaging.listTopics([], query || undefined);
|
||||
|
||||
const projectId = get(project).$id;
|
||||
|
||||
return topics
|
||||
.filter((topic) => topic.name.toLowerCase().includes(query.toLowerCase()))
|
||||
.map(
|
||||
(topic) =>
|
||||
({
|
||||
group: 'topics',
|
||||
label: topic.name,
|
||||
callback: () => {
|
||||
goto(`/console/project-${projectId}/messaging/topics/topic-${topic.$id}`);
|
||||
},
|
||||
icon: 'send'
|
||||
}) as const
|
||||
);
|
||||
}) satisfies Searcher;
|
||||
@@ -0,0 +1,7 @@
|
||||
export function omit<T, K extends keyof T>(obj: T, ...keys: K[]): Omit<T, K> {
|
||||
const ret = { ...obj };
|
||||
for (const key of keys) {
|
||||
delete ret[key];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -1,29 +1,8 @@
|
||||
<script>
|
||||
import { addSubPanel, registerCommands } from '$lib/commandCenter';
|
||||
import { TeamsPanel, UsersPanel } from '$lib/commandCenter/panels';
|
||||
import { Container } from '$lib/layout';
|
||||
import { loading } from '../store';
|
||||
|
||||
loading.set(false);
|
||||
|
||||
$registerCommands([
|
||||
{
|
||||
label: 'Find users',
|
||||
callback: () => {
|
||||
addSubPanel(UsersPanel);
|
||||
},
|
||||
group: 'users',
|
||||
rank: -1
|
||||
},
|
||||
{
|
||||
label: 'Find teams',
|
||||
callback: () => {
|
||||
addSubPanel(TeamsPanel);
|
||||
},
|
||||
group: 'teams',
|
||||
rank: -1
|
||||
}
|
||||
]);
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
$: $registerCommands([
|
||||
{
|
||||
label: 'Go to projects',
|
||||
label: 'Go to Projects',
|
||||
callback: () => {
|
||||
goto('/console');
|
||||
},
|
||||
@@ -77,15 +77,6 @@
|
||||
icon: 'sparkles',
|
||||
disabled: !isAssistantEnabled
|
||||
},
|
||||
{
|
||||
label: 'Go to account',
|
||||
callback: () => {
|
||||
goto('/console/account');
|
||||
},
|
||||
keys: ['i'],
|
||||
group: 'navigation',
|
||||
rank: -2
|
||||
},
|
||||
{
|
||||
label: 'Create new organization',
|
||||
callback: () => {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
userSearcher
|
||||
} from '$lib/commandCenter/searchers';
|
||||
import { MigrationBox } from '$lib/components';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
onMount(() => {
|
||||
return sdk.forConsole.client.subscribe(['project', 'console'], (response) => {
|
||||
@@ -27,20 +28,20 @@
|
||||
});
|
||||
|
||||
$: $registerCommands([
|
||||
{
|
||||
label: 'Go to Databases',
|
||||
callback: () => {
|
||||
goto(`/console/project-${$project.$id}/databases`);
|
||||
},
|
||||
keys: ['d'],
|
||||
group: 'navigation'
|
||||
},
|
||||
{
|
||||
label: 'Go to Auth',
|
||||
callback: () => {
|
||||
goto(`/console/project-${$project.$id}/auth`);
|
||||
},
|
||||
keys: ['a'],
|
||||
keys: ['g', 'a'],
|
||||
group: 'navigation'
|
||||
},
|
||||
{
|
||||
label: 'Go to Databases',
|
||||
callback: () => {
|
||||
goto(`/console/project-${$project.$id}/databases`);
|
||||
},
|
||||
keys: ['g', 'd'],
|
||||
group: 'navigation'
|
||||
},
|
||||
{
|
||||
@@ -48,7 +49,16 @@
|
||||
callback: () => {
|
||||
goto(`/console/project-${$project.$id}/functions`);
|
||||
},
|
||||
keys: ['f'],
|
||||
keys: ['g', 'f'],
|
||||
group: 'navigation'
|
||||
},
|
||||
{
|
||||
label: 'Go to Messaging',
|
||||
callback: () => {
|
||||
goto(`/console/project-${$project.$id}/messaging`);
|
||||
},
|
||||
keys: ['g', 'm'],
|
||||
disabled: $page.url.pathname.endsWith('messaging'),
|
||||
group: 'navigation'
|
||||
},
|
||||
{
|
||||
@@ -56,23 +66,23 @@
|
||||
callback: () => {
|
||||
goto(`/console/project-${$project.$id}/storage`);
|
||||
},
|
||||
keys: ['s'],
|
||||
keys: ['g', 's'],
|
||||
group: 'navigation'
|
||||
},
|
||||
{
|
||||
label: 'Go to settings',
|
||||
label: 'Go to Settings',
|
||||
callback: () => {
|
||||
goto(`/console/project-${$project.$id}/settings`);
|
||||
},
|
||||
keys: ['p'],
|
||||
keys: ['g', 'e'],
|
||||
group: 'navigation'
|
||||
},
|
||||
{
|
||||
label: 'Go to overview',
|
||||
label: 'Go to Overview',
|
||||
callback: () => {
|
||||
goto(`/console/project-${$project.$id}`);
|
||||
},
|
||||
keys: ['o'],
|
||||
keys: ['g', 'o'],
|
||||
group: 'navigation'
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import { registerCommands, updateCommandGroupRanks } from '$lib/commandCenter';
|
||||
import { addSubPanel, registerCommands, updateCommandGroupRanks } from '$lib/commandCenter';
|
||||
import { TeamsPanel, UsersPanel } from '$lib/commandCenter/panels';
|
||||
import { readOnly } from '$lib/stores/billing';
|
||||
import { GRACE_PERIOD_OVERRIDE } from '$lib/system';
|
||||
import { project } from '../store';
|
||||
@@ -77,6 +78,22 @@
|
||||
group: 'navigation',
|
||||
rank: 1,
|
||||
disabled: $page.url.pathname.endsWith('settings')
|
||||
},
|
||||
{
|
||||
label: 'Find users',
|
||||
callback: () => {
|
||||
addSubPanel(UsersPanel);
|
||||
},
|
||||
group: 'users',
|
||||
rank: -1
|
||||
},
|
||||
{
|
||||
label: 'Find teams',
|
||||
callback: () => {
|
||||
addSubPanel(TeamsPanel);
|
||||
},
|
||||
group: 'teams',
|
||||
rank: -1
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
+39
@@ -136,6 +136,45 @@
|
||||
disabled: $page.url.pathname.endsWith('settings'),
|
||||
group: 'collections'
|
||||
},
|
||||
{
|
||||
label: 'Display Name',
|
||||
async callback() {
|
||||
await goto(
|
||||
`/console/project-${$project.$id}/databases/database-${$database.$id}/collection-${$collection.$id}/settings#display-name`
|
||||
);
|
||||
},
|
||||
group: 'collections',
|
||||
disabled:
|
||||
$page.url.pathname.endsWith('display-name') ||
|
||||
$page.url.pathname.endsWith('settings'),
|
||||
icon: 'eye'
|
||||
},
|
||||
{
|
||||
label: 'Permissions',
|
||||
async callback() {
|
||||
await goto(
|
||||
`/console/project-${$project.$id}/databases/database-${$database.$id}/collection-${$collection.$id}/settings#permissions`
|
||||
);
|
||||
},
|
||||
group: 'collections',
|
||||
disabled:
|
||||
$page.url.pathname.endsWith('permissions') ||
|
||||
$page.url.pathname.endsWith('settings'),
|
||||
icon: 'puzzle'
|
||||
},
|
||||
{
|
||||
label: 'Document security',
|
||||
async callback() {
|
||||
await goto(
|
||||
`/console/project-${$project.$id}/databases/database-${$database.$id}/collection-${$collection.$id}/settings#document-security`
|
||||
);
|
||||
},
|
||||
group: 'collections',
|
||||
disabled:
|
||||
$page.url.pathname.endsWith('document-security') ||
|
||||
$page.url.pathname.endsWith('settings'),
|
||||
icon: 'lock-closed'
|
||||
},
|
||||
{
|
||||
label: 'Create index',
|
||||
keys: $page.url.pathname.endsWith('indexes') ? ['c'] : ['c', 'i'],
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@
|
||||
|
||||
<Form onSubmit={updateDisplayName}>
|
||||
<CardGrid>
|
||||
<Heading tag="h6" size="7">Display name</Heading>
|
||||
<Heading tag="h6" size="7" id="display-name">Display name</Heading>
|
||||
<p class="text">
|
||||
Select string attributes as display names for your documents. The selected names will be
|
||||
used as short forms to identify documents in the Appwrite console, like when creating
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@
|
||||
</script>
|
||||
|
||||
<CardGrid>
|
||||
<Heading tag="h6" size="7">Permissions</Heading>
|
||||
<Heading tag="h6" size="7" id="permissions">Permissions</Heading>
|
||||
<p class="text">
|
||||
Choose who can access your collection and documents. For more about <a
|
||||
href="https://appwrite.io/docs/products/databases/permissions"
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@
|
||||
</script>
|
||||
|
||||
<CardGrid>
|
||||
<Heading tag="h6" size="7">Document security</Heading>
|
||||
<Heading tag="h6" size="7" id="document-security">Document security</Heading>
|
||||
<svelte:fragment slot="aside">
|
||||
<FormList>
|
||||
<InputSwitch
|
||||
|
||||
@@ -1,58 +1,55 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import { registerCommands, updateCommandGroupRanks } from '$lib/commandCenter';
|
||||
import {
|
||||
addSubPanel,
|
||||
registerCommands,
|
||||
registerSearchers,
|
||||
updateCommandGroupRanks
|
||||
} from '$lib/commandCenter';
|
||||
import { CreateMessagePanel } from '$lib/commandCenter/panels';
|
||||
import { messagesSearcher } from '$lib/commandCenter/searchers/messages';
|
||||
import { providersSearcher } from '$lib/commandCenter/searchers/providers';
|
||||
import { topicsSearcher } from '$lib/commandCenter/searchers/topics';
|
||||
import { project } from '../store';
|
||||
import { showCreate } from './store';
|
||||
|
||||
// TODO: finalize the commands
|
||||
|
||||
$: $registerCommands([
|
||||
{
|
||||
label: 'Create message',
|
||||
callback: () => {
|
||||
if (!$page.url.pathname.endsWith('messaging')) {
|
||||
goto(`/console/project-${$project.$id}/messaging`);
|
||||
}
|
||||
$showCreate = true;
|
||||
},
|
||||
keys: $page.url.pathname.endsWith('messaging') ? ['c'] : ['c', 'm'],
|
||||
callback() {
|
||||
addSubPanel(CreateMessagePanel);
|
||||
},
|
||||
icon: 'plus',
|
||||
group: 'messaging'
|
||||
},
|
||||
{
|
||||
label: 'Go to topics',
|
||||
label: 'Go to Topics',
|
||||
keys: ['g', 't'],
|
||||
callback() {
|
||||
goto(`/console/project-${$project.$id}/messaging/topics`);
|
||||
},
|
||||
keys: ['g', 't'],
|
||||
disabled:
|
||||
$page.url.pathname.endsWith('topics') || $page.url.pathname.includes('message-'),
|
||||
group: 'navigation',
|
||||
rank: 10
|
||||
group: 'messaging',
|
||||
rank: 1
|
||||
},
|
||||
{
|
||||
label: 'Go to providers',
|
||||
label: 'Go to Providers',
|
||||
keys: ['g', 'p'],
|
||||
callback() {
|
||||
goto(`/console/project-${$project.$id}/messaging/providers`);
|
||||
},
|
||||
keys: ['g', 'p'],
|
||||
disabled:
|
||||
$page.url.pathname.endsWith('topics') || $page.url.pathname.includes('message-'),
|
||||
group: 'navigation',
|
||||
rank: 10
|
||||
$page.url.pathname.endsWith('providers') || $page.url.pathname.includes('message-'),
|
||||
group: 'messaging',
|
||||
rank: 2
|
||||
}
|
||||
// {
|
||||
// label: 'Find messages',
|
||||
// callback: () => {
|
||||
// addSubPanel(BucketsPanel);
|
||||
// },
|
||||
// group: 'messaging',
|
||||
// rank: -1
|
||||
// }
|
||||
]);
|
||||
|
||||
$: $updateCommandGroupRanks({ messaging: 200, navigation: 100 });
|
||||
$registerSearchers(messagesSearcher, providersSearcher, topicsSearcher);
|
||||
|
||||
$: $updateCommandGroupRanks({ messaging: 400, providers: 300, topics: 200, navigation: 100 });
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
||||
@@ -1,3 +1,47 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import { registerCommands } from '$lib/commandCenter';
|
||||
import { project } from '$routes/console/project-[project]/store';
|
||||
|
||||
const topicId = $page.params.topic;
|
||||
|
||||
$: $registerCommands([
|
||||
{
|
||||
label: 'Go to Subscribers',
|
||||
callback() {
|
||||
goto(
|
||||
`/console/project-${$project.$id}/messaging/topics/topic-${topicId}/subscribers`
|
||||
);
|
||||
},
|
||||
keys: ['g', 's'],
|
||||
disabled: $page.url.pathname.endsWith('subscribers'),
|
||||
group: 'topics',
|
||||
rank: 1
|
||||
},
|
||||
{
|
||||
label: 'Go to Activity',
|
||||
callback() {
|
||||
goto(`/console/project-${$project.$id}/messaging/topics/topic-${topicId}/activity`);
|
||||
},
|
||||
keys: ['g', 'a'],
|
||||
disabled: $page.url.pathname.endsWith('activity'),
|
||||
group: 'topics',
|
||||
rank: 1
|
||||
},
|
||||
{
|
||||
label: 'Go to Overview',
|
||||
callback() {
|
||||
goto(`/console/project-${$project.$id}/messaging/topics/topic-${topicId}`);
|
||||
},
|
||||
keys: ['g', 'o'],
|
||||
disabled: $page.url.pathname.endsWith(`topic-${topicId}`),
|
||||
group: 'topics',
|
||||
rank: 1
|
||||
}
|
||||
]);
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Topic - Appwrite</title>
|
||||
</svelte:head>
|
||||
|
||||
Reference in New Issue
Block a user