feat: added a login page with Authentik authentication
This commit is contained in:
@@ -40,7 +40,7 @@ export function EcrImageBrowser({resource, runtimeReachable}: EcrImageBrowserPro
|
||||
{imagesQuery.isLoading && <div className="muted padded">Loading images</div>}
|
||||
{imagesQuery.isSuccess && images.length === 0 && <div className="empty compact"><h3>No images</h3><p>Push an image to this repository to see it here.</p></div>}
|
||||
{images.length > 0 && <div className="cosmos-items-table">
|
||||
<table>
|
||||
<table className="table ecr-images-table">
|
||||
<thead><tr><th>Tags</th><th>Digest</th><th>Pushed</th><th>Size</th><th/></tr></thead>
|
||||
<tbody>{images.map((image) => {
|
||||
const tags = Array.isArray(image.body.imageTags) ? image.body.imageTags.filter((tag): tag is string => typeof tag === 'string') : []
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {NavLink, Outlet, useLocation, useSearchParams} from 'react-router-dom'
|
||||
import {AlertTriangle, ChevronsLeft, ChevronsRight, LayoutDashboard, Moon, Search, Sun} from 'lucide-react'
|
||||
import {AlertTriangle, ChevronsLeft, ChevronsRight, LayoutDashboard, LogOut, Moon, Search, Sun} from 'lucide-react'
|
||||
import {useCallback, useEffect, useRef, useState} from 'react'
|
||||
import theCloud from '../../../../TheCloud.png'
|
||||
import {useTheme} from '@/lib/useTheme'
|
||||
@@ -220,6 +220,9 @@ export function Layout() {
|
||||
</button>
|
||||
<div id="topbar-status" className="topbar-status"/>
|
||||
<AccountSwitcher/>
|
||||
<button className="icon-btn" type="button" title="Sign out" aria-label="Sign out" onClick={() => void signOut()}>
|
||||
<LogOut size={14}/>
|
||||
</button>
|
||||
<div className={`connection ${isConnected ? 'connected' : 'disconnected'}`}>
|
||||
<span className={connectionDotClass(status)} aria-hidden="true"/>
|
||||
<span className="connection-state">{connectionLabel}</span>
|
||||
@@ -234,6 +237,12 @@ export function Layout() {
|
||||
)
|
||||
}
|
||||
|
||||
async function signOut(): Promise<void> {
|
||||
const csrf = document.cookie.split('; ').find((item) => item.startsWith('floci_ui_csrf='))?.split('=')[1]
|
||||
await fetch('/api/auth/logout', {method: 'POST', headers: csrf ? {'X-Floci-CSRF': decodeURIComponent(csrf)} : {}})
|
||||
window.location.assign('/login')
|
||||
}
|
||||
|
||||
/**
|
||||
* Topbar search bar.
|
||||
*
|
||||
|
||||
@@ -98,3 +98,23 @@ test('shows an object extension instead of a generic object type', async () => {
|
||||
|
||||
expect(await screen.findByText('JSON file')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
test('opens the object action with copy selected', async () => {
|
||||
apiMocks.listStorageObjects.mockResolvedValue({prefix: '', objects: [{
|
||||
key: 'orders/order.json', name: 'order.json', type: 'object', size: 10, lastModified: null, metadata: {},
|
||||
}]})
|
||||
apiMocks.listCloudResources.mockResolvedValue([bucket])
|
||||
const user = userEvent.setup()
|
||||
const queryClient = new QueryClient({defaultOptions: {queries: {retry: false}}})
|
||||
|
||||
render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<StorageObjectBrowser cloud="aws" resource={bucket} runtimeReachable capabilities={['copy']} onSelectObject={() => {}}/>
|
||||
</QueryClientProvider>,
|
||||
)
|
||||
|
||||
await user.click(await screen.findByRole('button', {name: 'Copy or move order.json'}))
|
||||
|
||||
const copyTab = screen.getAllByRole('button', {name: 'Copy'}).find((button) => button.classList.contains('drawer-tab'))
|
||||
expect(copyTab).toHaveClass('active')
|
||||
})
|
||||
|
||||
@@ -524,7 +524,7 @@ export function StorageObjectBrowser({cloud, resource, capabilities = [], runtim
|
||||
</a>
|
||||
)}
|
||||
{copyCapability && (
|
||||
<button className="icon-btn" disabled={!canCopy} title={copyCapability.reason ?? `Move / Copy ${object.name}`} onClick={() => setCopyObject(object)}>
|
||||
<button className="icon-btn" disabled={!canCopy} title={copyCapability.reason ?? `Copy or move ${object.name}`} aria-label={`Copy or move ${object.name}`} onClick={() => setCopyObject(object)}>
|
||||
<Copy size={13}/>
|
||||
</button>
|
||||
)}
|
||||
@@ -606,7 +606,7 @@ function MoveOrCopyModal({
|
||||
}) {
|
||||
const qc = useQueryClient()
|
||||
const resourceLabel = cloud === 'azure' ? 'container' : 'bucket'
|
||||
const [mode, setMode] = useState<'move' | 'copy'>('move')
|
||||
const [mode, setMode] = useState<'move' | 'copy'>('copy')
|
||||
const [destKey, setDestKey] = useState(() => {
|
||||
const parts = srcObject.key.split('/')
|
||||
const filename = parts.pop() ?? srcObject.key
|
||||
|
||||
Reference in New Issue
Block a user