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
6 changes: 0 additions & 6 deletions medcat-trainer/webapp/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

229 changes: 202 additions & 27 deletions medcat-trainer/webapp/frontend/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,23 +1,46 @@
<template>
<div class="full-height">
<nav class="navbar">
<router-link class="app-name" to="/">Med<img class="icon" src="./assets/cat-logo.png" >AT</router-link>
<router-link class="navbar-brand" to="/">Projects</router-link>
<router-link class="navbar-brand" to="/metrics-reports">Metrics</router-link>
<router-link class="navbar-brand" to="/model-explore">Concepts</router-link>
<router-link class="navbar-brand" to="/demo">Try Model</router-link>
<span class="version-id">{{ version }}</span>
<a class="navbar-brand ml-auto small">
<span v-if="!uname" class="link" @click="openLogin">Login</span>
<span v-else>
<span class="link">
({{ uname }}) <font-awesome-icon icon="user"></font-awesome-icon>
</span>
<span class="link logout" @click="logout">logout</span>
</span>
</a>
</nav>
<router-view/>
<header class="header-gradient">
<div class="header-container">
<div class="header-content">
<!-- CogStack Branding and App Name -->
<div class="branding-section">
<div class="logo-container">
<img src="./assets/brand-logo.png" alt="CogStack Logo" class="brand-logo" />
</div>
<div class="divider"></div>
<h1 class="app-title" @click="navigateToHome">
Med<img src="./assets/cat-logo.png" alt="MedCAT Logo" class="cat-logo" />AT
</h1>
<span class="version-id">{{ version }}</span>

<!-- Navigation Links -->
<div class="navigation-links">
<router-link class="nav-link" to="/">Projects</router-link>
<router-link class="nav-link" to="/metrics-reports">Metrics</router-link>
<router-link class="nav-link" to="/model-explore">Concepts</router-link>
<router-link class="nav-link" to="/demo">Try Model</router-link>
</div>
</div>



<!-- Action Buttons -->
<div class="action-buttons">
<div class="user-section">
<span v-if="!uname" class="login-link" @click="openLogin">Login</span>
<span v-else class="user-info">
<span class="username">({{ uname }}) <font-awesome-icon icon="user"></font-awesome-icon></span>
<span class="logout-link" @click="logout">logout</span>
</span>
</div>
</div>
</div>
</div>
</header>
<main class="main-content">
<router-view/>
</main>
<login v-if="!useOidc && loginModal"
@login:success="loginSuccessful"
:closable="true"
Expand All @@ -43,6 +66,10 @@ export default {
}
},
methods: {
navigateToHome () {
this.$router.push('/')
},

openLogin () {
if (!this.useOidc) {
this.loginModal = true
Expand Down Expand Up @@ -115,6 +142,162 @@ export default {
</script>

<style scoped lang="scss">
.full-height {
min-height: 100vh;
}

.header-gradient {
background: linear-gradient(135deg, #126cad 0%, #3d0372 50%, #8e1b73 100%);
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 50;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.header-container {
width: 100%;
padding: 0 24px;
}

.header-content {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 0;
min-height: 60px;
}

.main-content {
padding-top: 81px;
height: 100vh; /* Account for header height (60px + 32px padding) */
}

.branding-section {
display: flex;
align-items: center;
gap: 16px;
}

.logo-container {
display: flex;
align-items: center;
}

.brand-logo {
height: 48px;
width: auto;
}

.divider {
height: 24px;
width: 1px;
background-color: rgba(255, 255, 255, 0.3);
}

.app-title {
font-size: 24px;
font-weight: bold;
color: white;
display: flex;
align-items: center;
gap: 4px;
cursor: pointer;
margin: 0;
text-decoration: none;

&:hover {
color: white;
text-decoration: none;
}
}

.cat-logo {
height: 32px;
width: 32px;
}

.navigation-links {
display: flex;
gap: 20px;
}

.nav-link {
color: white;
text-decoration: none;
padding: 8px 0;
border-bottom: 1px solid transparent;
transition: all 0.2s ease;

&:hover {
color: white;
border-bottom: 1px solid white;
text-decoration: none;
}

&:focus {
color: white
}

&.router-link-active {
border-bottom: 1px solid white;
}
}

.action-buttons {
display: flex;
gap: 8px;
align-items: center;
}

.user-section {
display: flex;
align-items: center;
gap: 16px;
margin-left: 16px;
}

.login-link {
color: white;
cursor: pointer;
font-size: 14px;

&:hover {
opacity: 0.8;
}
}

.user-info {
display: flex;
align-items: center;
gap: 16px;
color: white;
font-size: 14px;
}

.username {
display: flex;
align-items: center;
gap: 4px;
}

.logout-link {
cursor: pointer;

&:hover {
opacity: 0.8;
}
}

.version-id {
font-size: 10px;
color: rgba(255, 255, 255, 0.7);
margin-left: 16px;
}

// Legacy styles for backward compatibility
.right {
float: right;
}
Expand Down Expand Up @@ -160,7 +343,7 @@ export default {
}

.link {
display:inline-block;
display: inline-block;
height: 25px;
cursor: pointer;

Expand All @@ -179,12 +362,4 @@ export default {
bottom: 7px;
}

.version-id {
display: inline-block;
float: right;
font-size: 10px;
padding: 0 20px;
color: $color-2;
}

</style>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 11 additions & 12 deletions medcat-trainer/webapp/frontend/src/tests/App.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('App.vue', () => {
$cookies: {
get: vi.fn((key) => key === 'username' ? 'testUser' : null),
remove: vi.fn()
}
}
},
stubs: ['login', 'font-awesome-icon', 'router-view']
}
Expand All @@ -49,12 +49,11 @@ describe('App.vue', () => {

// Check that router-link stubs exist with correct props
const links = wrapper.findAllComponents({ name: 'RouterLink' })
expect(links.length).toBeGreaterThanOrEqual(5)
expect(links.length).toBeGreaterThanOrEqual(4)
expect(links[0].props('to')).toBe('/')
expect(links[1].props('to')).toBe('/')
expect(links[2].props('to')).toBe('/metrics-reports')
expect(links[3].props('to')).toBe('/model-explore')
expect(links[4].props('to')).toBe('/demo')
expect(links[1].props('to')).toBe('/metrics-reports')
expect(links[2].props('to')).toBe('/model-explore')
expect(links[3].props('to')).toBe('/demo')
})


Expand Down Expand Up @@ -84,9 +83,9 @@ describe('App.vue', () => {
mocks: {
$http: { get: mockGet },
$cookies: {
get: vi.fn((key) => key === 'username' ? 'testUser' : null),
remove: vi.fn()
}
get: vi.fn((key) => key === 'username' ? 'testUser' : null),
remove: vi.fn()
}
},
stubs: ['login', 'font-awesome-icon', 'router-link', 'router-view']
},
Expand All @@ -102,6 +101,6 @@ describe('App.vue', () => {
await flushPromises()

expect(wrapper.text()).toContain('testUser');
expect(wrapper.find('.logout').exists()).toBe(true);
});
});
expect(wrapper.find('.logout-link').exists()).toBe(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,7 @@ $app-header-height: 60px;

.app-container {
display: flex;
height: calc(100% - #{$app-header-height});
height: 100%;
flex-direction: column;
padding: 5px;
}
Expand Down