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

Merge pull request #5216 from thornbill/build-version

Add build and web versions to dashboard
This commit is contained in:
Bill Thornton 2024-02-21 12:02:40 -05:00 committed by GitHub
commit 265afb519b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 95 additions and 39 deletions

View file

@ -261,7 +261,11 @@ module.exports = {
'ServerNotifications': 'writable', 'ServerNotifications': 'writable',
'TaskButton': 'writable', 'TaskButton': 'writable',
'UserParentalControlPage': 'writable', 'UserParentalControlPage': 'writable',
'Windows': 'readonly' 'Windows': 'readonly',
// Build time definitions
__JF_BUILD_VERSION__: 'readonly',
__USE_SYSTEM_FONTS__: 'readonly',
__WEBPACK_SERVE__: 'readonly'
}, },
rules: { rules: {
'@typescript-eslint/prefer-string-starts-ends-with': ['error'] '@typescript-eslint/prefer-string-starts-ends-with': ['error']

View file

@ -3,15 +3,13 @@ import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText'; import ListItemText from '@mui/material/ListItemText';
import React from 'react'; import React from 'react';
import { useApi } from 'hooks/useApi';
import { useSystemInfo } from 'hooks/useSystemInfo'; import { useSystemInfo } from 'hooks/useSystemInfo';
import ListItemLink from 'components/ListItemLink'; import ListItemLink from 'components/ListItemLink';
import appIcon from 'assets/img/icon-transparent.png'; import appIcon from 'assets/img/icon-transparent.png';
const DrawerHeaderLink = () => { const DrawerHeaderLink = () => {
const { api } = useApi(); const { data: systemInfo } = useSystemInfo();
const { data: systemInfo } = useSystemInfo(api);
return ( return (
<ListItemLink to='/'> <ListItemLink to='/'>

View file

@ -8,16 +8,22 @@
<span class="material-icons chevron_right" aria-hidden="true"></span> <span class="material-icons chevron_right" aria-hidden="true"></span>
</a> </a>
<div class="paperList" style="padding: 1em;"> <div class="serverInfo paperList">
<p id="serverName"></p> <div>${LabelServerName}</div>
<p id="versionNumber"></p> <div id="serverName"></div>
<div>${LabelServerVersion}</div>
<div id="versionNumber"></div>
<div>${LabelWebVersion}</div>
<div id="webVersion"></div>
<div>${LabelBuildVersion}</div>
<div id="buildVersion"></div>
</div> </div>
<div class="dashboardActionsContainer"> <div class="dashboardActionsContainer">
<button is="emby-button" type="button" class="raised btnRefresh"> <button is="emby-button" type="button" class="raised btnRefresh">
<span>${ButtonScanAllLibraries}</span> <span>${ButtonScanAllLibraries}</span>
</button> </button>
<button is="emby-button" type="button" id="btnRestartServer" class="raised hide" onclick="DashboardPage.restart(this);"> <button is="emby-button" type="button" id="btnRestartServer" class="raised" onclick="DashboardPage.restart(this);">
<span>${Restart}</span> <span>${Restart}</span>
</button> </button>
<button is="emby-button" type="button" id="btnShutdown" class="raised" onclick="DashboardPage.shutdown(this);"> <button is="emby-button" type="button" id="btnShutdown" class="raised" onclick="DashboardPage.shutdown(this);">

View file

@ -1,4 +1,5 @@
import escapeHtml from 'escape-html'; import escapeHtml from 'escape-html';
import datetime from '../../scripts/datetime'; import datetime from '../../scripts/datetime';
import Events from '../../utils/events.ts'; import Events from '../../utils/events.ts';
import itemHelper from '../../components/itemHelper'; import itemHelper from '../../components/itemHelper';
@ -14,10 +15,6 @@ import imageLoader from '../../components/images/imageLoader';
import ActivityLog from '../../components/activitylog'; import ActivityLog from '../../components/activitylog';
import imageHelper from '../../utils/image'; import imageHelper from '../../utils/image';
import indicators from '../../components/indicators/indicators'; import indicators from '../../components/indicators/indicators';
import '../../components/listview/listview.scss';
import '../../elements/emby-button/emby-button';
import '../../styles/flexstyles.scss';
import '../../elements/emby-itemscontainer/emby-itemscontainer';
import taskButton from '../../scripts/taskbutton'; import taskButton from '../../scripts/taskbutton';
import Dashboard from '../../utils/dashboard'; import Dashboard from '../../utils/dashboard';
import ServerConnections from '../../components/ServerConnections'; import ServerConnections from '../../components/ServerConnections';
@ -25,6 +22,19 @@ import alert from '../../components/alert';
import confirm from '../../components/confirm/confirm'; import confirm from '../../components/confirm/confirm';
import { getDefaultBackgroundClass } from '../../components/cardbuilder/cardBuilderUtils'; import { getDefaultBackgroundClass } from '../../components/cardbuilder/cardBuilderUtils';
import { getSystemInfoQuery } from 'hooks/useSystemInfo';
import { toApi } from 'utils/jellyfin-apiclient/compat';
import { queryClient } from 'utils/query/queryClient';
import { version as WEB_VERSION } from '../../../package.json';
import '../../elements/emby-button/emby-button';
import '../../elements/emby-itemscontainer/emby-itemscontainer';
import '../../components/listview/listview.scss';
import '../../styles/flexstyles.scss';
import './dashboard.scss';
function showPlaybackInfo(btn, session) { function showPlaybackInfo(btn, session) {
let title; let title;
const text = []; const text = [];
@ -199,22 +209,21 @@ function refreshActiveRecordings(view, apiClient) {
} }
function reloadSystemInfo(view, apiClient) { function reloadSystemInfo(view, apiClient) {
apiClient.getSystemInfo().then(function (systemInfo) { view.querySelector('#buildVersion').innerText = __JF_BUILD_VERSION__;
view.querySelector('#serverName').innerText = globalize.translate('DashboardServerName', systemInfo.ServerName); view.querySelector('#webVersion').innerText = WEB_VERSION;
view.querySelector('#versionNumber').innerText = globalize.translate('DashboardVersionNumber', systemInfo.Version);
if (systemInfo.CanSelfRestart) { queryClient
view.querySelector('#btnRestartServer').classList.remove('hide'); .fetchQuery(getSystemInfoQuery(toApi(apiClient)))
} else { .then(systemInfo => {
view.querySelector('#btnRestartServer').classList.add('hide'); view.querySelector('#serverName').innerText = systemInfo.ServerName;
} view.querySelector('#versionNumber').innerText = systemInfo.Version;
view.querySelector('#cachePath').innerText = systemInfo.CachePath; view.querySelector('#cachePath').innerText = systemInfo.CachePath;
view.querySelector('#logPath').innerText = systemInfo.LogPath; view.querySelector('#logPath').innerText = systemInfo.LogPath;
view.querySelector('#transcodePath').innerText = systemInfo.TranscodingTempPath; view.querySelector('#transcodePath').innerText = systemInfo.TranscodingTempPath;
view.querySelector('#metadataPath').innerText = systemInfo.InternalMetadataPath; view.querySelector('#metadataPath').innerText = systemInfo.InternalMetadataPath;
view.querySelector('#webPath').innerText = systemInfo.WebPath; view.querySelector('#webPath').innerText = systemInfo.WebPath;
}); });
} }
function renderInfo(view, sessions) { function renderInfo(view, sessions) {

View file

@ -0,0 +1,17 @@
.serverInfo {
display: flex;
flex-wrap: wrap;
gap: 1em;
padding: 1em;
> *:nth-child(odd) {
flex: 1 0 20%;
min-width: 7.5em;
font-weight: bold;
}
> *:nth-child(even) {
flex: 1 0 70%;
}
}

4
src/global.d.ts vendored
View file

@ -14,4 +14,8 @@ export declare global {
interface DocumentEventMap { interface DocumentEventMap {
'viewshow': CustomEvent; 'viewshow': CustomEvent;
} }
const __JF_BUILD_VERSION__: string;
const __USE_SYSTEM_FONTS__: string;
const __WEBPACK_SERVE__: string;
} }

View file

@ -3,21 +3,34 @@ import type { Api } from '@jellyfin/sdk';
import { getSystemApi } from '@jellyfin/sdk/lib/utils/api/system-api'; import { getSystemApi } from '@jellyfin/sdk/lib/utils/api/system-api';
import type { AxiosRequestConfig } from 'axios'; import type { AxiosRequestConfig } from 'axios';
import { useApi } from './useApi';
import { queryOptions } from 'utils/query/queryOptions';
const fetchSystemInfo = async ( const fetchSystemInfo = async (
api: Api | undefined, api?: Api,
options: AxiosRequestConfig options?: AxiosRequestConfig
) => { ) => {
if (!api) throw new Error('No API instance available'); if (!api) {
console.warn('[fetchSystemInfo] No API instance available');
return;
}
const response = await getSystemApi(api) const response = await getSystemApi(api)
.getSystemInfo(options); .getSystemInfo(options);
return response.data; return response.data;
}; };
export const useSystemInfo = (api: Api | undefined) => { export const getSystemInfoQuery = (
return useQuery({ api?: Api
queryKey: [ 'SystemInfo' ], ) => queryOptions({
queryFn: ({ signal }) => fetchSystemInfo(api, { signal }), queryKey: [ 'SystemInfo' ],
enabled: !!api queryFn: ({ signal }) => fetchSystemInfo(api, { signal }),
}); // Allow for query reuse in legacy javascript.
staleTime: 1000, // 1 second
enabled: !!api
});
export const useSystemInfo = () => {
const { api } = useApi();
return useQuery(getSystemInfoQuery(api));
}; };

View file

@ -94,7 +94,7 @@ function onGlobalizeInit() {
if (browser.tv && !browser.android) { if (browser.tv && !browser.android) {
console.debug('using system fonts with explicit sizes'); console.debug('using system fonts with explicit sizes');
import('./styles/fonts.sized.scss'); import('./styles/fonts.sized.scss');
} else if (__USE_SYSTEM_FONTS__) { // eslint-disable-line no-undef } else if (__USE_SYSTEM_FONTS__) {
console.debug('using system fonts'); console.debug('using system fonts');
import('./styles/fonts.scss'); import('./styles/fonts.scss');
} else { } else {

View file

@ -35,7 +35,7 @@ export function getIncludeCorsCredentials() {
export function getMultiServer() { export function getMultiServer() {
// Enable multi-server support when served by webpack // Enable multi-server support when served by webpack
if (__WEBPACK_SERVE__) { // eslint-disable-line no-undef if (__WEBPACK_SERVE__) {
return Promise.resolve(true); return Promise.resolve(true);
} }

View file

@ -167,8 +167,6 @@
"Cursive": "Cursive", "Cursive": "Cursive",
"CustomDlnaProfilesHelp": "Create a custom profile to target a new device or override a system profile.", "CustomDlnaProfilesHelp": "Create a custom profile to target a new device or override a system profile.",
"DailyAt": "Daily at {0}", "DailyAt": "Daily at {0}",
"DashboardServerName": "Server: {0}",
"DashboardVersionNumber": "Version: {0}",
"Data": "Data", "Data": "Data",
"DateAdded": "Date added", "DateAdded": "Date added",
"DatePlayed": "Date played", "DatePlayed": "Date played",
@ -582,6 +580,7 @@
"LabelBlastMessageInterval": "Alive message interval", "LabelBlastMessageInterval": "Alive message interval",
"LabelBlastMessageIntervalHelp": "Determine the duration in seconds between blast alive messages.", "LabelBlastMessageIntervalHelp": "Determine the duration in seconds between blast alive messages.",
"LabelBlockContentWithTags": "Block items with tags", "LabelBlockContentWithTags": "Block items with tags",
"LabelBuildVersion": "Build version",
"LabelBurnSubtitles": "Burn subtitles", "LabelBurnSubtitles": "Burn subtitles",
"LabelCache": "Cache", "LabelCache": "Cache",
"LabelCachePath": "Cache path", "LabelCachePath": "Cache path",
@ -869,6 +868,7 @@
"LabelServerHostHelp": "192.168.1.100:8096 or https://myserver.com", "LabelServerHostHelp": "192.168.1.100:8096 or https://myserver.com",
"LabelServerName": "Server name", "LabelServerName": "Server name",
"LabelServerNameHelp": "This name will be used to identify the server and will default to the server's hostname.", "LabelServerNameHelp": "This name will be used to identify the server and will default to the server's hostname.",
"LabelServerVersion": "Server version",
"LabelSimultaneousConnectionLimit": "Simultaneous stream limit", "LabelSimultaneousConnectionLimit": "Simultaneous stream limit",
"LabelSize": "Size", "LabelSize": "Size",
"LabelSkipBackLength": "Skip back length", "LabelSkipBackLength": "Skip back length",
@ -989,6 +989,7 @@
"LabelVideoRange": "Video range", "LabelVideoRange": "Video range",
"LabelVideoResolution": "Video resolution", "LabelVideoResolution": "Video resolution",
"LabelWeb": "Web", "LabelWeb": "Web",
"LabelWebVersion": "Web version",
"LabelXDlnaCap": "Device Capability ID", "LabelXDlnaCap": "Device Capability ID",
"LabelXDlnaCapHelp": "Determine the content of the 'X_DLNACAP' element in the 'urn:schemas-dlna-org:device-1-0' namespace.", "LabelXDlnaCapHelp": "Determine the content of the 'X_DLNACAP' element in the 'urn:schemas-dlna-org:device-1-0' namespace.",
"LabelXDlnaDoc": "Device Class ID", "LabelXDlnaDoc": "Device Class ID",

View file

@ -47,6 +47,10 @@ const config = {
}, },
plugins: [ plugins: [
new DefinePlugin({ new DefinePlugin({
__JF_BUILD_VERSION__: JSON.stringify(
process.env.WEBPACK_SERVE ?
'Dev Server' :
process.env.JELLYFIN_VERSION || 'Release'),
__USE_SYSTEM_FONTS__: JSON.stringify(!!process.env.USE_SYSTEM_FONTS), __USE_SYSTEM_FONTS__: JSON.stringify(!!process.env.USE_SYSTEM_FONTS),
__WEBPACK_SERVE__: JSON.stringify(!!process.env.WEBPACK_SERVE) __WEBPACK_SERVE__: JSON.stringify(!!process.env.WEBPACK_SERVE)
}), }),