mirror of
https://github.com/tutao/tutanota.git
synced 2025-10-19 07:53:47 +00:00
Add quick settings
Searcheable and keyboard-friendly way to navigate and invoke various actions in the app Close #9520
This commit is contained in:
parent
b1133a83b3
commit
7f124116fb
9 changed files with 333 additions and 14 deletions
|
@ -81,7 +81,8 @@ import("../mail-app/translations/en.js")
|
||||||
initCommonLocator(calendarLocator)
|
initCommonLocator(calendarLocator)
|
||||||
|
|
||||||
const { setupNavShortcuts } = await import("../common/misc/NavShortcuts.js")
|
const { setupNavShortcuts } = await import("../common/misc/NavShortcuts.js")
|
||||||
setupNavShortcuts()
|
// FIXME
|
||||||
|
// setupNavShortcuts()
|
||||||
|
|
||||||
// this needs to stay after client.init
|
// this needs to stay after client.init
|
||||||
windowFacade.init(calendarLocator.logins, calendarLocator.connectivityModel, null)
|
windowFacade.init(calendarLocator.logins, calendarLocator.connectivityModel, null)
|
||||||
|
|
|
@ -301,12 +301,12 @@ class KeyManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param key The key to be checked, should correspond to KeyEvent.key
|
* @param keyFromPress The key to be checked, should correspond to KeyEvent.key
|
||||||
* @param keys Keys to be checked against, type of Keys
|
* @param keys Keys to be checked against, type of Keys
|
||||||
*/
|
*/
|
||||||
export function isKeyPressed(key: string | undefined, ...keys: Array<Key>): boolean {
|
export function isKeyPressed(keyFromPress: string | undefined, ...keys: Array<Key>): boolean {
|
||||||
if (key != null) {
|
if (keyFromPress != null) {
|
||||||
return keys.some((k) => k.code === key.toLowerCase())
|
return keys.some((k) => k.code === keyFromPress.toLowerCase())
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,33 @@
|
||||||
import { keyManager } from "./KeyManager.js"
|
import { keyManager } from "./KeyManager.js"
|
||||||
import { FeatureType, Keys } from "../api/common/TutanotaConstants.js"
|
import { FeatureType, Keys } from "../api/common/TutanotaConstants.js"
|
||||||
import { locator } from "../api/main/CommonLocator.js"
|
|
||||||
import m from "mithril"
|
import m from "mithril"
|
||||||
import { CALENDAR_PREFIX, CONTACTS_PREFIX, LogoutUrl, MAIL_PREFIX, SETTINGS_PREFIX } from "./RouteChange.js"
|
import { CALENDAR_PREFIX, CONTACTS_PREFIX, LogoutUrl, MAIL_PREFIX, SETTINGS_PREFIX } from "./RouteChange.js"
|
||||||
|
import { QuickActionsModel, showQuickActionBar } from "./QuickActionBar"
|
||||||
|
import { LoginController } from "../api/main/LoginController"
|
||||||
|
|
||||||
export function setupNavShortcuts() {
|
export function setupNavShortcuts({ quickActionsModel, logins }: { quickActionsModel: () => Promise<QuickActionsModel>; logins: LoginController }) {
|
||||||
keyManager.registerShortcuts([
|
keyManager.registerShortcuts([
|
||||||
{
|
{
|
||||||
key: Keys.M,
|
key: Keys.M,
|
||||||
enabled: () => locator.logins.isUserLoggedIn(),
|
enabled: () => logins.isUserLoggedIn(),
|
||||||
exec: () => m.route.set(MAIL_PREFIX),
|
exec: () => m.route.set(MAIL_PREFIX),
|
||||||
help: "mailView_action",
|
help: "mailView_action",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: Keys.C,
|
key: Keys.C,
|
||||||
enabled: () => locator.logins.isInternalUserLoggedIn() && !locator.logins.isEnabled(FeatureType.DisableContacts),
|
enabled: () => logins.isInternalUserLoggedIn() && !logins.isEnabled(FeatureType.DisableContacts),
|
||||||
exec: () => m.route.set(CONTACTS_PREFIX),
|
exec: () => m.route.set(CONTACTS_PREFIX),
|
||||||
help: "contactView_action",
|
help: "contactView_action",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: Keys.O,
|
key: Keys.O,
|
||||||
enabled: () => locator.logins.isInternalUserLoggedIn(),
|
enabled: () => logins.isInternalUserLoggedIn(),
|
||||||
exec: () => m.route.set(CALENDAR_PREFIX),
|
exec: () => m.route.set(CALENDAR_PREFIX),
|
||||||
help: "calendarView_action",
|
help: "calendarView_action",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: Keys.S,
|
key: Keys.S,
|
||||||
enabled: () => locator.logins.isInternalUserLoggedIn(),
|
enabled: () => logins.isInternalUserLoggedIn(),
|
||||||
exec: () => m.route.set(SETTINGS_PREFIX),
|
exec: () => m.route.set(SETTINGS_PREFIX),
|
||||||
help: "settingsView_action",
|
help: "settingsView_action",
|
||||||
},
|
},
|
||||||
|
@ -34,9 +35,19 @@ export function setupNavShortcuts() {
|
||||||
key: Keys.L,
|
key: Keys.L,
|
||||||
shift: true,
|
shift: true,
|
||||||
ctrlOrCmd: true,
|
ctrlOrCmd: true,
|
||||||
enabled: () => locator.logins.isUserLoggedIn(),
|
enabled: () => logins.isUserLoggedIn(),
|
||||||
exec: (key) => m.route.set(LogoutUrl),
|
exec: (key) => m.route.set(LogoutUrl),
|
||||||
help: "switchAccount_action",
|
help: "switchAccount_action",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: Keys.K,
|
||||||
|
shift: true,
|
||||||
|
ctrlOrCmd: true,
|
||||||
|
exec: () => {
|
||||||
|
quickActionsModel().then(showQuickActionBar)
|
||||||
|
},
|
||||||
|
// FIXME
|
||||||
|
help: "search_label",
|
||||||
|
},
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
204
src/common/misc/QuickActionBar.ts
Normal file
204
src/common/misc/QuickActionBar.ts
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
import m, { Children, Component, Vnode, VnodeDOM } from "mithril"
|
||||||
|
import { px, size } from "../gui/size"
|
||||||
|
import { TextField } from "../gui/base/TextField"
|
||||||
|
import { modal } from "../gui/base/Modal"
|
||||||
|
import { isKeyPressed, Shortcut } from "./KeyManager"
|
||||||
|
import { lastIndex, remove } from "@tutao/tutanota-utils"
|
||||||
|
import { Keys } from "../api/common/TutanotaConstants"
|
||||||
|
import { highlightTextInQueryAsChildren } from "../gui/TextHighlightViewUtils"
|
||||||
|
import { theme } from "../gui/theme"
|
||||||
|
|
||||||
|
export interface QuickAction {
|
||||||
|
readonly description: string
|
||||||
|
readonly exec: () => unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
type LazyActionProvider = () => Promise<readonly QuickAction[]>
|
||||||
|
|
||||||
|
export class QuickActionsModel {
|
||||||
|
private readonly _lastRunActions: QuickAction[] = []
|
||||||
|
private actions: readonly QuickAction[] = []
|
||||||
|
private readonly providers: LazyActionProvider[] = []
|
||||||
|
|
||||||
|
register(actionProvider: LazyActionProvider) {
|
||||||
|
this.providers.push(actionProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateActions(): Promise<void> {
|
||||||
|
const result: QuickAction[] = []
|
||||||
|
for (const actionProvider of this.providers) {
|
||||||
|
const actions = await actionProvider()
|
||||||
|
result.push(...actions)
|
||||||
|
}
|
||||||
|
this.actions = result
|
||||||
|
}
|
||||||
|
|
||||||
|
runAction(action: QuickAction) {
|
||||||
|
remove(this._lastRunActions, action)
|
||||||
|
this._lastRunActions.unshift(action)
|
||||||
|
action.exec()
|
||||||
|
}
|
||||||
|
|
||||||
|
lastActions(): readonly QuickAction[] {
|
||||||
|
return this._lastRunActions
|
||||||
|
}
|
||||||
|
|
||||||
|
getMatchingActions(query: string): readonly QuickAction[] {
|
||||||
|
const lowerQuery = query.toLowerCase()
|
||||||
|
return this.actions.filter((pr) => pr.description.toLowerCase().includes(lowerQuery))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Attrs {
|
||||||
|
runAction: (action: QuickAction) => unknown
|
||||||
|
getInitialActions: () => Promise<readonly QuickAction[]>
|
||||||
|
getMatchingActions: (query: string) => readonly QuickAction[]
|
||||||
|
close: () => unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
class QuickActionBar implements Component<Attrs> {
|
||||||
|
private query = ""
|
||||||
|
private results: readonly QuickAction[] = []
|
||||||
|
private selectedIndex: number = 0
|
||||||
|
private listDom: HTMLElement | null = null
|
||||||
|
|
||||||
|
oninit({ attrs: { getInitialActions, getMatchingActions } }: Vnode<Attrs>) {
|
||||||
|
getInitialActions().then((initialActions) => {
|
||||||
|
this.results = initialActions
|
||||||
|
m.redraw()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
view({ attrs: { close, runAction, getMatchingActions } }: Vnode<Attrs>): Children {
|
||||||
|
return m(
|
||||||
|
".flex.col",
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
maxWidth: "50vw",
|
||||||
|
maxHeight: "80vh",
|
||||||
|
background: "white",
|
||||||
|
borderRadius: px(size.border_radius_large),
|
||||||
|
margin: "10vh auto",
|
||||||
|
padding: px(size.hpad),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[
|
||||||
|
m(TextField, {
|
||||||
|
label: "action_label",
|
||||||
|
value: this.query,
|
||||||
|
class: "flex-no-grow-no-shrink-auto",
|
||||||
|
oninput: (newValue) => {
|
||||||
|
this.query = newValue
|
||||||
|
this.results = getMatchingActions(newValue)
|
||||||
|
this.selectedIndex = 0
|
||||||
|
},
|
||||||
|
onDomInputCreated: (dom) => {
|
||||||
|
setTimeout(() => dom.focus(), 32)
|
||||||
|
},
|
||||||
|
onReturnKeyPressed: () => {
|
||||||
|
const firstResult = this.results.at(this.selectedIndex)
|
||||||
|
if (firstResult) {
|
||||||
|
runAction(firstResult)
|
||||||
|
}
|
||||||
|
close()
|
||||||
|
},
|
||||||
|
keyHandler: (keyPress) => {
|
||||||
|
if (isKeyPressed(keyPress.key, Keys.ESC)) {
|
||||||
|
close()
|
||||||
|
} else if (isKeyPressed(keyPress.key, Keys.UP)) {
|
||||||
|
this.selectedIndex = Math.max(0, this.selectedIndex - 1)
|
||||||
|
this.scrollToIndex()
|
||||||
|
return false
|
||||||
|
} else if (isKeyPressed(keyPress.key, Keys.DOWN)) {
|
||||||
|
this.selectedIndex = Math.min(lastIndex(this.results), this.selectedIndex + 1)
|
||||||
|
this.scrollToIndex()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
m(
|
||||||
|
".flex.col.ul.mt-s.scroll.flex-grow",
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
"list-style": "none",
|
||||||
|
gap: "4px",
|
||||||
|
},
|
||||||
|
oncreate: (vnode: VnodeDOM) => {
|
||||||
|
this.listDom = vnode.dom as HTMLElement
|
||||||
|
},
|
||||||
|
},
|
||||||
|
this.results.map((result, index) =>
|
||||||
|
m(
|
||||||
|
"li.border-radius-small.plr-s.click",
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
padding: "4px",
|
||||||
|
backgroundColor: index === this.selectedIndex ? theme.state_bg_hover : undefined,
|
||||||
|
},
|
||||||
|
onclick: () => {
|
||||||
|
const action = this.results.at(index)
|
||||||
|
if (action) {
|
||||||
|
runAction(action)
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
highlightTextInQueryAsChildren(result.description, [{ token: this.query, exact: false }]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private scrollToIndex() {
|
||||||
|
if (this.listDom) {
|
||||||
|
const child = this.listDom.children.item(this.selectedIndex)
|
||||||
|
child?.scrollIntoView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showQuickActionBar(model: QuickActionsModel) {
|
||||||
|
const activeElement = document.activeElement
|
||||||
|
const modalComponent = {
|
||||||
|
view: () => {
|
||||||
|
return m(QuickActionBar, {
|
||||||
|
getInitialActions: async () => {
|
||||||
|
await model.updateActions()
|
||||||
|
return model.lastActions().concat(model.getMatchingActions(""))
|
||||||
|
},
|
||||||
|
getMatchingActions: (query) => model.getMatchingActions(query),
|
||||||
|
runAction: (action) => model.runAction(action),
|
||||||
|
close: () => modal.remove(modalComponent),
|
||||||
|
} satisfies Attrs)
|
||||||
|
},
|
||||||
|
async hideAnimation(): Promise<void> {},
|
||||||
|
|
||||||
|
onClose(): void {},
|
||||||
|
|
||||||
|
shortcuts(): Shortcut[] {
|
||||||
|
return []
|
||||||
|
},
|
||||||
|
|
||||||
|
backgroundClick(e: MouseEvent): void {
|
||||||
|
modal.remove(modalComponent)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* will be called by the main modal if no other component above this one blocked the event (previous components returned true)
|
||||||
|
* return false if the event was handled and lower components shouldn't be notified, true otherwise
|
||||||
|
* @param e
|
||||||
|
*/
|
||||||
|
popState(e: Event): boolean {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
|
||||||
|
// The element that was interacted with to show the modal.
|
||||||
|
callingElement(): HTMLElement | null {
|
||||||
|
return activeElement as HTMLElement | null
|
||||||
|
},
|
||||||
|
}
|
||||||
|
modal.display(modalComponent)
|
||||||
|
}
|
36
src/common/settings/SettingsQuickActions.ts
Normal file
36
src/common/settings/SettingsQuickActions.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { QuickAction } from "../misc/QuickActionBar"
|
||||||
|
import { lang } from "../misc/LanguageViewModel"
|
||||||
|
import { Router } from "../gui/ScopedRouter"
|
||||||
|
|
||||||
|
export async function quickSettingsActions(router: Router): Promise<readonly QuickAction[]> {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
description: `${lang.get("settings_label")} ${lang.get("login_label")}`,
|
||||||
|
exec: () => router.routeTo("/settings/login", {}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: `${lang.get("settings_label")} ${lang.get("email_label")}`,
|
||||||
|
exec: () => router.routeTo("/settings/mail", {}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: `${lang.get("settings_label")} ${lang.get("email_label")} ${lang.get("defaultSenderMailAddress_label")}`,
|
||||||
|
exec: () => router.routeTo("/settings/mail#defaultSender", {}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: `${lang.get("settings_label")} ${lang.get("appearanceSettings_label")}`,
|
||||||
|
exec: () => router.routeTo("/settings/appearance", {}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: `${lang.get("settings_label")} ${lang.get("appearanceSettings_label")} ${lang.get("language_label")}`,
|
||||||
|
exec: () => router.routeTo("/settings/appearance#label", {}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: `${lang.get("settings_label")} ${lang.get("appearanceSettings_label")} ${lang.get("switchColorTheme_action")}`,
|
||||||
|
exec: () => router.routeTo("/settings/appearance#colorTheme", {}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: `${lang.get("settings_label")} ${lang.get("appearanceSettings_label")} ${lang.get("weekScrollTime_label")}`,
|
||||||
|
exec: () => router.routeTo("/settings/appearance#weekScrollTime", {}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
|
@ -120,7 +120,18 @@ import("./translations/en.js")
|
||||||
initCommonLocator(mailLocator)
|
initCommonLocator(mailLocator)
|
||||||
|
|
||||||
const { setupNavShortcuts } = await import("../common/misc/NavShortcuts.js")
|
const { setupNavShortcuts } = await import("../common/misc/NavShortcuts.js")
|
||||||
setupNavShortcuts()
|
setupNavShortcuts({ quickActionsModel: () => mailLocator.quickActionsModel(), logins: mailLocator.logins })
|
||||||
|
|
||||||
|
mailLocator.quickActionsModel().then((model) => {
|
||||||
|
model.register(async () => {
|
||||||
|
const { quickMailActions } = await import("./mail/model/MailQuickActions.js")
|
||||||
|
return quickMailActions(mailLocator.mailboxModel, mailLocator.mailModel, mailLocator.logins, mailLocator.throttledRouter())
|
||||||
|
})
|
||||||
|
model.register(async () => {
|
||||||
|
const { quickSettingsActions } = await import("../common/settings/SettingsQuickActions.js")
|
||||||
|
return quickSettingsActions(mailLocator.throttledRouter())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
const { BottomNav } = await import("./gui/BottomNav.js")
|
const { BottomNav } = await import("./gui/BottomNav.js")
|
||||||
|
|
||||||
|
|
48
src/mail-app/mail/model/MailQuickActions.ts
Normal file
48
src/mail-app/mail/model/MailQuickActions.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import { MailModel } from "./MailModel"
|
||||||
|
import { QuickAction } from "../../../common/misc/QuickActionBar"
|
||||||
|
import { MailboxDetail, MailboxModel } from "../../../common/mailFunctionality/MailboxModel"
|
||||||
|
import { getMailboxName } from "../../../common/mailFunctionality/SharedMailUtils"
|
||||||
|
import { LoginController } from "../../../common/api/main/LoginController"
|
||||||
|
import { getFolderName } from "./MailUtils"
|
||||||
|
import { Router } from "../../../common/gui/ScopedRouter"
|
||||||
|
import { getElementId } from "../../../common/api/common/utils/EntityUtils"
|
||||||
|
import { lang } from "../../../common/misc/LanguageViewModel"
|
||||||
|
|
||||||
|
export async function quickMailActions(
|
||||||
|
mailboxModel: MailboxModel,
|
||||||
|
mailModel: MailModel,
|
||||||
|
loginController: LoginController,
|
||||||
|
router: Router,
|
||||||
|
): Promise<readonly QuickAction[]> {
|
||||||
|
const mailboxDetails: MailboxDetail[] = await mailboxModel.getMailboxDetails()
|
||||||
|
return mailboxDetails.flatMap((mailboxDetail) => {
|
||||||
|
const mailboxName = getMailboxName(loginController, mailboxDetail)
|
||||||
|
|
||||||
|
const newEmailAction: QuickAction = {
|
||||||
|
description: `${mailboxName} ${lang.get("newMail_action")}`,
|
||||||
|
exec: async () => {
|
||||||
|
const { newMailEditor } = await import("../editor/MailEditor")
|
||||||
|
const dialog = await newMailEditor(mailboxDetail)
|
||||||
|
dialog.show()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const fs = mailModel.getFolderSystemByGroupId(mailboxDetail.mailGroup._id)
|
||||||
|
|
||||||
|
let folderActions: readonly QuickAction[]
|
||||||
|
if (fs == null) {
|
||||||
|
folderActions = []
|
||||||
|
} else {
|
||||||
|
folderActions = fs.getIndentedList().map(({ folder }) => {
|
||||||
|
return {
|
||||||
|
description: `${mailboxName} ${getFolderName(folder)}`,
|
||||||
|
// TODO: this is not ideal as this will forget the selected mail in that folder. We could pull it
|
||||||
|
// up from somewhere.
|
||||||
|
exec: () => router.routeTo("/mail/:folder", { folder: getElementId(folder) }),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return [newEmailAction, ...folderActions]
|
||||||
|
})
|
||||||
|
}
|
|
@ -154,6 +154,7 @@ import { WhitelabelThemeGenerator } from "../common/gui/WhitelabelThemeGenerator
|
||||||
import { UndoModel } from "./UndoModel"
|
import { UndoModel } from "./UndoModel"
|
||||||
import { GroupSettingsModel } from "../common/sharing/model/GroupSettingsModel"
|
import { GroupSettingsModel } from "../common/sharing/model/GroupSettingsModel"
|
||||||
import { AutosaveFacade } from "../common/api/worker/facades/lazy/AutosaveFacade"
|
import { AutosaveFacade } from "../common/api/worker/facades/lazy/AutosaveFacade"
|
||||||
|
import { QuickActionsModel } from "../common/misc/QuickActionBar"
|
||||||
|
|
||||||
assertMainOrNode()
|
assertMainOrNode()
|
||||||
|
|
||||||
|
@ -348,6 +349,11 @@ class MailLocator implements CommonLocator {
|
||||||
: noOp,
|
: noOp,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readonly quickActionsModel: lazyAsync<QuickActionsModel> = lazyMemoized(async () => {
|
||||||
|
const { QuickActionsModel } = await import("../common/misc/QuickActionBar.js")
|
||||||
|
return new QuickActionsModel()
|
||||||
|
})
|
||||||
|
|
||||||
readonly contactViewModel = lazyMemoized(async () => {
|
readonly contactViewModel = lazyMemoized(async () => {
|
||||||
const { ContactViewModel } = await import("../mail-app/contacts/view/ContactViewModel.js")
|
const { ContactViewModel } = await import("../mail-app/contacts/view/ContactViewModel.js")
|
||||||
const router = new ScopedRouter(this.throttledRouter(), "/contact")
|
const router = new ScopedRouter(this.throttledRouter(), "/contact")
|
||||||
|
|
|
@ -667,8 +667,10 @@ export class SettingsView extends BaseTopLevelView implements TopLevelView<Setti
|
||||||
if (!args.folder) {
|
if (!args.folder) {
|
||||||
this._setUrl(this._userFolders[0].url)
|
this._setUrl(this._userFolders[0].url)
|
||||||
} else if (args.folder || !m.route.get().startsWith("/settings")) {
|
} else if (args.folder || !m.route.get().startsWith("/settings")) {
|
||||||
|
// TODO: a bit of a hack, instead of requestedPath we should find the folder by :folder and :id params
|
||||||
|
const requestedPathWithoutHash = requestedPath.split("#")[0]
|
||||||
// ensure that current viewer will be reinitialized
|
// ensure that current viewer will be reinitialized
|
||||||
const folder = this._allSettingsFolders().find((folder) => folder.url === requestedPath)
|
const folder = this._allSettingsFolders().find((folder) => folder.url === requestedPathWithoutHash)
|
||||||
|
|
||||||
if (!folder) {
|
if (!folder) {
|
||||||
this._setUrl(this._userFolders[0].url)
|
this._setUrl(this._userFolders[0].url)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue