1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Merge pull request #6472 from thornbill/refactor-app-type

Refactor app type
This commit is contained in:
Bill Thornton 2025-01-24 00:15:50 -05:00 committed by GitHub
commit 094c0eee8f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 73 additions and 37 deletions

View file

@ -1,16 +1,17 @@
import { AsyncRouteType, type AsyncRoute } from 'components/router/AsyncRoute'; import type { AsyncRoute } from 'components/router/AsyncRoute';
import { AppType } from 'constants/appType';
export const ASYNC_ADMIN_ROUTES: AsyncRoute[] = [ export const ASYNC_ADMIN_ROUTES: AsyncRoute[] = [
{ path: 'activity', type: AsyncRouteType.Dashboard }, { path: 'activity', type: AppType.Dashboard },
{ path: 'branding', type: AsyncRouteType.Dashboard }, { path: 'branding', type: AppType.Dashboard },
{ path: 'keys', type: AsyncRouteType.Dashboard }, { path: 'keys', type: AppType.Dashboard },
{ path: 'logs', type: AsyncRouteType.Dashboard }, { path: 'logs', type: AppType.Dashboard },
{ path: 'playback/trickplay', type: AsyncRouteType.Dashboard }, { path: 'playback/trickplay', type: AppType.Dashboard },
{ path: 'plugins/:pluginId', page: 'plugins/plugin', type: AsyncRouteType.Dashboard }, { path: 'plugins/:pluginId', page: 'plugins/plugin', type: AppType.Dashboard },
{ path: 'users', type: AsyncRouteType.Dashboard }, { path: 'users', type: AppType.Dashboard },
{ path: 'users/access', type: AsyncRouteType.Dashboard }, { path: 'users/access', type: AppType.Dashboard },
{ path: 'users/add', type: AsyncRouteType.Dashboard }, { path: 'users/add', type: AppType.Dashboard },
{ path: 'users/parentalcontrol', type: AsyncRouteType.Dashboard }, { path: 'users/parentalcontrol', type: AppType.Dashboard },
{ path: 'users/password', type: AsyncRouteType.Dashboard }, { path: 'users/password', type: AppType.Dashboard },
{ path: 'users/profile', type: AsyncRouteType.Dashboard } { path: 'users/profile', type: AppType.Dashboard }
]; ];

View file

@ -1,129 +1,151 @@
import type { LegacyRoute } from 'components/router/LegacyRoute'; import type { LegacyRoute } from 'components/router/LegacyRoute';
import { AppType } from 'constants/appType';
export const LEGACY_ADMIN_ROUTES: LegacyRoute[] = [ export const LEGACY_ADMIN_ROUTES: LegacyRoute[] = [
{ {
path: '/dashboard', path: '/dashboard',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/dashboard', controller: 'dashboard/dashboard',
view: 'dashboard/dashboard.html' view: 'dashboard/dashboard.html'
} }
}, { }, {
path: 'settings', path: 'settings',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/general', controller: 'dashboard/general',
view: 'dashboard/general.html' view: 'dashboard/general.html'
} }
}, { }, {
path: 'networking', path: 'networking',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/networking', controller: 'dashboard/networking',
view: 'dashboard/networking.html' view: 'dashboard/networking.html'
} }
}, { }, {
path: 'devices', path: 'devices',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/devices/devices', controller: 'dashboard/devices/devices',
view: 'dashboard/devices/devices.html' view: 'dashboard/devices/devices.html'
} }
}, { }, {
path: 'devices/edit', path: 'devices/edit',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/devices/device', controller: 'dashboard/devices/device',
view: 'dashboard/devices/device.html' view: 'dashboard/devices/device.html'
} }
}, { }, {
path: 'libraries', path: 'libraries',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/library', controller: 'dashboard/library',
view: 'dashboard/library.html' view: 'dashboard/library.html'
} }
}, { }, {
path: 'libraries/display', path: 'libraries/display',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/librarydisplay', controller: 'dashboard/librarydisplay',
view: 'dashboard/librarydisplay.html' view: 'dashboard/librarydisplay.html'
} }
}, { }, {
path: 'playback/transcoding', path: 'playback/transcoding',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/encodingsettings', controller: 'dashboard/encodingsettings',
view: 'dashboard/encodingsettings.html' view: 'dashboard/encodingsettings.html'
} }
}, { }, {
path: 'libraries/metadata', path: 'libraries/metadata',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/metadataImages', controller: 'dashboard/metadataImages',
view: 'dashboard/metadataimages.html' view: 'dashboard/metadataimages.html'
} }
}, { }, {
path: 'libraries/nfo', path: 'libraries/nfo',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/metadatanfo', controller: 'dashboard/metadatanfo',
view: 'dashboard/metadatanfo.html' view: 'dashboard/metadatanfo.html'
} }
}, { }, {
path: 'playback/resume', path: 'playback/resume',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/playback', controller: 'dashboard/playback',
view: 'dashboard/playback.html' view: 'dashboard/playback.html'
} }
}, { }, {
path: 'plugins/catalog', path: 'plugins/catalog',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/plugins/available/index', controller: 'dashboard/plugins/available/index',
view: 'dashboard/plugins/available/index.html' view: 'dashboard/plugins/available/index.html'
} }
}, { }, {
path: 'plugins/repositories', path: 'plugins/repositories',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/plugins/repositories/index', controller: 'dashboard/plugins/repositories/index',
view: 'dashboard/plugins/repositories/index.html' view: 'dashboard/plugins/repositories/index.html'
} }
}, { }, {
path: 'livetv/guide', path: 'livetv/guide',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'livetvguideprovider', controller: 'livetvguideprovider',
view: 'livetvguideprovider.html' view: 'livetvguideprovider.html'
} }
}, { }, {
path: 'recordings', path: 'recordings',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'livetvsettings', controller: 'livetvsettings',
view: 'livetvsettings.html' view: 'livetvsettings.html'
} }
}, { }, {
path: 'livetv', path: 'livetv',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'livetvstatus', controller: 'livetvstatus',
view: 'livetvstatus.html' view: 'livetvstatus.html'
} }
}, { }, {
path: 'livetv/tuner', path: 'livetv/tuner',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'livetvtuner', controller: 'livetvtuner',
view: 'livetvtuner.html' view: 'livetvtuner.html'
} }
}, { }, {
path: 'plugins', path: 'plugins',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/plugins/installed/index', controller: 'dashboard/plugins/installed/index',
view: 'dashboard/plugins/installed/index.html' view: 'dashboard/plugins/installed/index.html'
} }
}, { }, {
path: 'tasks/edit', path: 'tasks/edit',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/scheduledtasks/scheduledtask', controller: 'dashboard/scheduledtasks/scheduledtask',
view: 'dashboard/scheduledtasks/scheduledtask.html' view: 'dashboard/scheduledtasks/scheduledtask.html'
} }
}, { }, {
path: 'tasks', path: 'tasks',
pageProps: { pageProps: {
appType: AppType.Dashboard,
controller: 'dashboard/scheduledtasks/scheduledtasks', controller: 'dashboard/scheduledtasks/scheduledtasks',
view: 'dashboard/scheduledtasks/scheduledtasks.html' view: 'dashboard/scheduledtasks/scheduledtasks.html'
} }
}, { }, {
path: 'playback/streaming', path: 'playback/streaming',
pageProps: { pageProps: {
appType: AppType.Dashboard,
view: 'dashboard/streaming.html', view: 'dashboard/streaming.html',
controller: 'dashboard/streaming' controller: 'dashboard/streaming'
} }

View file

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { RouteObject } from 'react-router-dom'; import { RouteObject } from 'react-router-dom';
import ConnectionRequired from 'components/ConnectionRequired'; import ConnectionRequired from 'components/ConnectionRequired';
import { ASYNC_ADMIN_ROUTES } from './_asyncRoutes'; import { ASYNC_ADMIN_ROUTES } from './_asyncRoutes';
import { toAsyncPageRoute } from 'components/router/AsyncRoute'; import { toAsyncPageRoute } from 'components/router/AsyncRoute';

View file

@ -1,15 +1,15 @@
import { AsyncRoute, AsyncRouteType } from '../../../../components/router/AsyncRoute'; import { AsyncRoute } from 'components/router/AsyncRoute';
import { AppType } from 'constants/appType';
export const ASYNC_USER_ROUTES: AsyncRoute[] = [ export const ASYNC_USER_ROUTES: AsyncRoute[] = [
{ path: 'home.html', page: 'home', type: AsyncRouteType.Experimental }, { path: 'home.html', page: 'home', type: AppType.Experimental },
{ path: 'quickconnect', page: 'quickConnect' }, { path: 'quickconnect', page: 'quickConnect' },
{ path: 'search.html', page: 'search' }, { path: 'search.html', page: 'search' },
{ path: 'userprofile.html', page: 'user/userprofile' }, { path: 'userprofile.html', page: 'user/userprofile' },
{ path: 'movies.html', page: 'movies', type: AsyncRouteType.Experimental }, { path: 'movies.html', page: 'movies', type: AppType.Experimental },
{ path: 'tv.html', page: 'shows', type: AsyncRouteType.Experimental }, { path: 'tv.html', page: 'shows', type: AppType.Experimental },
{ path: 'music.html', page: 'music', type: AsyncRouteType.Experimental }, { path: 'music.html', page: 'music', type: AppType.Experimental },
{ path: 'livetv.html', page: 'livetv', type: AsyncRouteType.Experimental }, { path: 'livetv.html', page: 'livetv', type: AppType.Experimental },
{ path: 'mypreferencesdisplay.html', page: 'user/display', type: AsyncRouteType.Experimental }, { path: 'mypreferencesdisplay.html', page: 'user/display', type: AppType.Experimental },
{ path: 'homevideos.html', page: 'homevideos', type: AppType.Experimental }
{ path: 'homevideos.html', page: 'homevideos', type: AsyncRouteType.Experimental }
]; ];

View file

@ -1,10 +1,6 @@
import type { RouteObject } from 'react-router-dom'; import type { RouteObject } from 'react-router-dom';
export enum AsyncRouteType { import { AppType } from 'constants/appType';
Stable,
Experimental,
Dashboard
}
export interface AsyncRoute { export interface AsyncRoute {
/** The URL path for this route. */ /** The URL path for this route. */
@ -14,17 +10,17 @@ export interface AsyncRoute {
* Will fallback to using the `path` value if not specified. * Will fallback to using the `path` value if not specified.
*/ */
page?: string page?: string
/** The page type used to load the correct page element. */ /** The app that this page is part of. */
type?: AsyncRouteType type?: AppType
} }
const importRoute = (page: string, type: AsyncRouteType) => { const importRoute = (page: string, type: AppType) => {
switch (type) { switch (type) {
case AsyncRouteType.Dashboard: case AppType.Dashboard:
return import(/* webpackChunkName: "[request]" */ `../../apps/dashboard/routes/${page}`); return import(/* webpackChunkName: "[request]" */ `../../apps/dashboard/routes/${page}`);
case AsyncRouteType.Experimental: case AppType.Experimental:
return import(/* webpackChunkName: "[request]" */ `../../apps/experimental/routes/${page}`); return import(/* webpackChunkName: "[request]" */ `../../apps/experimental/routes/${page}`);
case AsyncRouteType.Stable: case AppType.Stable:
return import(/* webpackChunkName: "[request]" */ `../../apps/stable/routes/${page}`); return import(/* webpackChunkName: "[request]" */ `../../apps/stable/routes/${page}`);
} }
}; };
@ -32,7 +28,7 @@ const importRoute = (page: string, type: AsyncRouteType) => {
export const toAsyncPageRoute = ({ export const toAsyncPageRoute = ({
path, path,
page, page,
type = AsyncRouteType.Stable type = AppType.Stable
}: AsyncRoute): RouteObject => { }: AsyncRoute): RouteObject => {
return { return {
path, path,

View file

@ -6,8 +6,10 @@ import globalize from 'lib/globalize';
import type { RestoreViewFailResponse } from 'types/viewManager'; import type { RestoreViewFailResponse } from 'types/viewManager';
import viewManager from './viewManager'; import viewManager from './viewManager';
import { AppType } from 'constants/appType';
export interface ViewManagerPageProps { export interface ViewManagerPageProps {
appType?: AppType
controller: string controller: string
view: string view: string
type?: string type?: string
@ -31,7 +33,12 @@ interface ViewOptions {
} }
} }
const loadView = async (controller: string, view: string, viewOptions: ViewOptions) => { const loadView = async (
appType: AppType,
controller: string,
view: string,
viewOptions: ViewOptions
) => {
const [ controllerFactory, viewHtml ] = await Promise.all([ const [ controllerFactory, viewHtml ] = await Promise.all([
import(/* webpackChunkName: "[request]" */ `../../controllers/${controller}`), import(/* webpackChunkName: "[request]" */ `../../controllers/${controller}`),
import(/* webpackChunkName: "[request]" */ `../../controllers/${view}`) import(/* webpackChunkName: "[request]" */ `../../controllers/${view}`)
@ -50,6 +57,7 @@ const loadView = async (controller: string, view: string, viewOptions: ViewOptio
* NOTE: Any new pages should use the generic Page component instead. * NOTE: Any new pages should use the generic Page component instead.
*/ */
const ViewManagerPage: FunctionComponent<ViewManagerPageProps> = ({ const ViewManagerPage: FunctionComponent<ViewManagerPageProps> = ({
appType = AppType.Stable,
controller, controller,
view, view,
type, type,
@ -78,7 +86,7 @@ const ViewManagerPage: FunctionComponent<ViewManagerPageProps> = ({
if (navigationType !== Action.Pop) { if (navigationType !== Action.Pop) {
console.debug('[ViewManagerPage] loading view [%s]', view); console.debug('[ViewManagerPage] loading view [%s]', view);
return loadView(controller, view, viewOptions); return loadView(appType, controller, view, viewOptions);
} }
console.debug('[ViewManagerPage] restoring view [%s]', view); console.debug('[ViewManagerPage] restoring view [%s]', view);
@ -86,7 +94,7 @@ const ViewManagerPage: FunctionComponent<ViewManagerPageProps> = ({
.catch(async (result?: RestoreViewFailResponse) => { .catch(async (result?: RestoreViewFailResponse) => {
if (!result?.cancelled) { if (!result?.cancelled) {
console.debug('[ViewManagerPage] restore failed; loading view [%s]', view); console.debug('[ViewManagerPage] restore failed; loading view [%s]', view);
return loadView(controller, view, viewOptions); return loadView(appType, controller, view, viewOptions);
} }
}); });
}; };

8
src/constants/appType.ts Normal file
View file

@ -0,0 +1,8 @@
/**
* App types represented in src/apps.
*/
export enum AppType {
Dashboard = 'dashboard',
Experimental = 'experimental',
Stable = 'stable'
}