Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public/config/*

# misc
.DS_Store
# Local pnpm store / link artifacts (do not commit)
.pnpm-store/
.env.local
.env.development.local
.env.test.local
Expand Down
30 changes: 30 additions & 0 deletions src/App.dark.less
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,36 @@
border: 2px solid @primary-color !important;
}

/**
* Mini-map / scale insets (px). Slim clamp may reinforce these as inline styles
* after DMV render; keep values aligned with OVERVIEW_EDGE_INSET_PX.
*/
.ol-overviewmap {
left: 8px;
bottom: 8px;
margin: 0;
padding: 0;
}

.ol-overviewmap:not(.ol-collapsed) button {
position: absolute;
bottom: 0;
left: 0;
margin: 0;
}

.ol-overviewmap .ol-overviewmap-map {
margin: 0;
padding: 0;
}

.ol-scale-line {
right: 8px;
bottom: 8px;
left: auto;
margin: 0;
}

img {
object-fit: contain;
max-height: 100%;
Expand Down
30 changes: 30 additions & 0 deletions src/App.light.less
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,36 @@
border: 2px solid @primary-color !important;
}

/**
* Mini-map / scale insets (px). Slim clamp may reinforce these as inline styles
* after DMV render; keep values aligned with OVERVIEW_EDGE_INSET_PX.
*/
.ol-overviewmap {
left: 8px;
bottom: 8px;
margin: 0;
padding: 0;
}

.ol-overviewmap:not(.ol-collapsed) button {
position: absolute;
bottom: 0;
left: 0;
margin: 0;
}

.ol-overviewmap .ol-overviewmap-map {
margin: 0;
padding: 0;
}

.ol-scale-line {
right: 8px;
bottom: 8px;
left: auto;
margin: 0;
}

img {
object-fit: contain;
max-height: 100%;
Expand Down
180 changes: 95 additions & 85 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ import type AppConfig from './AppConfig'
import type { ErrorMessageSettings, ServerSettings } from './AppConfig'
import type { AuthManager, User } from './auth'
import OidcManager from './auth/OidcManager'
import AppShell from './components/AppShell'
import CaseViewer from './components/CaseViewer'
import Header from './components/Header'
import InfoPage from './components/InfoPage'
import MemoryFooter from './components/MemoryFooter'
import Worklist from './components/Worklist'
import { SettingsProvider } from './contexts/SettingsContext'
import { ValidationProvider } from './contexts/ValidationContext'
Expand Down Expand Up @@ -503,8 +503,20 @@ class App extends React.Component<AppProps, AppState> {
isLogoutPossible = false
}

const layoutStyle = { height: '100vh' }
const layoutContentStyle = { height: '100%' }
/**
* Fill AppShell's main pane. flex + minHeight:0 keeps ant-layout from
* sizing to content and spilling into the in-flow MemoryFooter.
*/
const layoutStyle: React.CSSProperties = {
flex: '1 1 0%',
minHeight: 0,
overflow: 'hidden',
}
const layoutContentStyle: React.CSSProperties = {
flex: 1,
minHeight: 0,
overflow: 'hidden',
}

if (this.state.redirectTo !== undefined) {
return (
Expand All @@ -515,20 +527,22 @@ class App extends React.Component<AppProps, AppState> {
} else if (this.state.isLoading) {
return (
<BrowserRouter basename={this.props.config.path}>
<Layout style={layoutStyle}>
<Header
app={appInfo}
user={this.state.user}
showWorklistButton={false}
onServerSelection={this.handleServerSelection}
showServerSelectionButton={false}
clients={this.state.clients}
defaultClients={this.state.defaultClients}
/>
<Layout.Content style={layoutContentStyle}>
<FaSpinner />
</Layout.Content>
</Layout>
<AppShell enableMemoryMonitoring={false}>
<Layout style={layoutStyle}>
<Header
app={appInfo}
user={this.state.user}
showWorklistButton={false}
onServerSelection={this.handleServerSelection}
showServerSelectionButton={false}
clients={this.state.clients}
defaultClients={this.state.defaultClients}
/>
<Layout.Content style={layoutContentStyle}>
<FaSpinner />
</Layout.Content>
</Layout>
</AppShell>
</BrowserRouter>
)
} else if (!this.state.wasAuthSuccessful) {
Expand All @@ -542,107 +556,103 @@ class App extends React.Component<AppProps, AppState> {
<Route
path="/"
element={
<Layout style={layoutStyle}>
<Header
app={appInfo}
user={this.state.user}
showWorklistButton={false}
onServerSelection={this.handleServerSelection}
onUserLogout={isLogoutPossible ? onLogout : undefined}
showServerSelectionButton={enableServerSelection}
clients={this.state.clients}
defaultClients={this.state.defaultClients}
/>
<Layout.Content style={layoutContentStyle}>
{worklist}
</Layout.Content>
{enableMemoryMonitoring && (
<MemoryFooter enabled={enableMemoryMonitoring} />
)}
</Layout>
}
/>
<Route
path="/studies/:studyInstanceUID/*"
element={
<SettingsProvider>
<AppShell enableMemoryMonitoring={enableMemoryMonitoring}>
<Layout style={layoutStyle}>
<Header
app={appInfo}
user={this.state.user}
showWorklistButton={enableWorklist}
showWorklistButton={false}
onServerSelection={this.handleServerSelection}
onUserLogout={isLogoutPossible ? onLogout : undefined}
showServerSelectionButton={enableServerSelection}
clients={this.state.clients}
defaultClients={this.state.defaultClients}
/>
<Layout.Content style={layoutContentStyle}>
<ParametrizedCaseViewer
clients={this.state.clients}
user={this.state.user}
config={this.props.config}
app={appInfo}
/>
{worklist}
</Layout.Content>
{enableMemoryMonitoring && (
<MemoryFooter enabled={enableMemoryMonitoring} />
)}
</Layout>
</AppShell>
}
/>
<Route
path="/studies/:studyInstanceUID/*"
element={
<SettingsProvider>
<AppShell enableMemoryMonitoring={enableMemoryMonitoring}>
<Layout style={layoutStyle}>
<Header
app={appInfo}
user={this.state.user}
showWorklistButton={enableWorklist}
onServerSelection={this.handleServerSelection}
onUserLogout={isLogoutPossible ? onLogout : undefined}
showServerSelectionButton={enableServerSelection}
clients={this.state.clients}
defaultClients={this.state.defaultClients}
/>
<Layout.Content style={layoutContentStyle}>
<ParametrizedCaseViewer
clients={this.state.clients}
user={this.state.user}
config={this.props.config}
app={appInfo}
/>
</Layout.Content>
</Layout>
</AppShell>
</SettingsProvider>
}
/>
<Route
path="/projects/:project/locations/:location/datasets/:dataset/dicomStores/:dicomStore/study/:studyInstanceUID/*"
element={
<SettingsProvider>
<AppShell enableMemoryMonitoring={enableMemoryMonitoring}>
<Layout style={layoutStyle}>
<Header
app={appInfo}
user={this.state.user}
showWorklistButton={enableWorklist}
onServerSelection={this.handleServerSelection}
onUserLogout={isLogoutPossible ? onLogout : undefined}
showServerSelectionButton={enableServerSelection}
clients={this.state.clients}
defaultClients={this.state.defaultClients}
/>
<Layout.Content style={layoutContentStyle}>
<ParametrizedCaseViewer
clients={this.state.clients}
user={this.state.user}
config={this.props.config}
app={appInfo}
/>
</Layout.Content>
</Layout>
</AppShell>
</SettingsProvider>
}
/>
<Route
path="/logout"
element={
<AppShell enableMemoryMonitoring={enableMemoryMonitoring}>
<Layout style={layoutStyle}>
<Header
app={appInfo}
user={this.state.user}
showWorklistButton={enableWorklist}
showWorklistButton={false}
onServerSelection={this.handleServerSelection}
onUserLogout={isLogoutPossible ? onLogout : undefined}
showServerSelectionButton={enableServerSelection}
clients={this.state.clients}
defaultClients={this.state.defaultClients}
/>
<Layout.Content style={layoutContentStyle}>
<ParametrizedCaseViewer
clients={this.state.clients}
user={this.state.user}
config={this.props.config}
app={appInfo}
/>
Logged out
</Layout.Content>
{enableMemoryMonitoring && (
<MemoryFooter enabled={enableMemoryMonitoring} />
)}
</Layout>
</SettingsProvider>
}
/>
<Route
path="/logout"
element={
<Layout style={layoutStyle}>
<Header
app={appInfo}
user={this.state.user}
showWorklistButton={false}
onServerSelection={this.handleServerSelection}
onUserLogout={isLogoutPossible ? onLogout : undefined}
showServerSelectionButton={enableServerSelection}
clients={this.state.clients}
defaultClients={this.state.defaultClients}
/>
<Layout.Content style={layoutContentStyle}>
Logged out
</Layout.Content>
{enableMemoryMonitoring && (
<MemoryFooter enabled={enableMemoryMonitoring} />
)}
</Layout>
</AppShell>
}
/>
</Routes>
Expand Down
40 changes: 40 additions & 0 deletions src/components/AppShell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type React from 'react'
import MemoryFooter from './MemoryFooter'

const shellStyle: React.CSSProperties = {
height: '100vh',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
}

const mainStyle: React.CSSProperties = {
flex: '1 1 0%',
minHeight: 0,
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
}

interface AppShellProps {
children: React.ReactNode
enableMemoryMonitoring: boolean
}

/**
* Column shell: main pane fills leftover height; MemoryFooter stays in normal
* document flow underneath so the map cannot extend under the bar.
*/
const AppShell: React.FC<AppShellProps> = ({
children,
enableMemoryMonitoring,
}) => {
return (
<div style={shellStyle}>
<div style={mainStyle}>{children}</div>
<MemoryFooter enabled={enableMemoryMonitoring} />
</div>
)
}

export default AppShell
Loading