Skip to content
Open
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
5 changes: 5 additions & 0 deletions medcat-trainer/webapp/frontend/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ declare module 'tiny-emitter/instance' {
const emitter: TinyEmitterInstance
export default emitter
}

declare module '@mctee/enterprise' {
const plugin: unknown
export default plugin
}
1 change: 1 addition & 0 deletions medcat-trainer/webapp/frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

<!-- Action Buttons -->
<div class="action-buttons">
<plugin-slot name="nav:actions" />
<router-link v-if="isAdmin" to="/project-admin" class="admin-cog-link" title="Project Admin">
<font-awesome-icon icon="cog"></font-awesome-icon>
</router-link>
Expand Down
2 changes: 2 additions & 0 deletions medcat-trainer/webapp/frontend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {authPlugin} from "./auth";
import { loadRuntimeConfig, isOidcEnabled } from './runtimeConfig';
import { registerUnauthorizedInterceptor } from './httpAuth'
import { initPluginBootstrap } from './plugins/bootstrap'
import { loadEnterprisePlugin } from './plugins/enterprise'
import PluginSlot from '@/components/plugins/PluginSlot.vue'

const theme ={
Expand All @@ -52,6 +53,7 @@ const vuetify = createVuetify({

async function bootstrap() {
await loadRuntimeConfig();
await loadEnterprisePlugin()

const app = createApp(App)
app.config.globalProperties.$http = axios
Expand Down
17 changes: 17 additions & 0 deletions medcat-trainer/webapp/frontend/src/plugins/enterprise.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Load the MedCAT Trainer Enterprise frontend plugin when VITE_MCT_EE=1.
*
* Local dev: set MCT_EE_ROOT to the ``medcat-trainer-ee/frontend/src`` folder and
* run the OSS frontend with ``VITE_MCT_EE=1 npm run dev``.
*/
export async function loadEnterprisePlugin(): Promise<void> {
if (import.meta.env.VITE_MCT_EE !== '1') {
return
}
try {
await import('@mctee/enterprise')
console.info('[Bootstrap] Enterprise plugin loaded')
} catch (error) {
console.warn('[Bootstrap] Enterprise plugin not loaded:', error)
}
}
31 changes: 30 additions & 1 deletion medcat-trainer/webapp/frontend/src/views/ProjectAdmin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,10 @@

<!-- Model Packs Tab -->
<div v-if="activeTab === 'modelpacks'" class="tab-content admin-section">
<plugin-slot name="project-admin:modelpacks" />
<plugin-slot
name="project-admin:modelpacks"
@model-service-linked="onMedcatteryModelLinked"
/>
<model-packs-list
v-if="!showModelPackForm && !editingModelPack"
:model-packs="modelPacks"
Expand Down Expand Up @@ -699,6 +702,32 @@ export default {
const response = await this.$http.get('/api/modelpacks/')
this.modelPacks = response.data.results || response.data
},
async onMedcatteryModelLinked(payload) {
if (payload?.modelServiceUrl) {
this.formData.use_model_service = true
this.formData.model_service_url = payload.modelServiceUrl
this.formData.model_pack = null
this.formData.concept_db = null
this.formData.vocab = null
if (this.validationErrors.model_pack) {
delete this.validationErrors.model_pack
}
if (this.validationErrors.concept_db) {
delete this.validationErrors.concept_db
}
if (this.validationErrors.vocab) {
delete this.validationErrors.vocab
}
if (this.validationErrors.model_config) {
delete this.validationErrors.model_config
}
if (this.validationErrors.model_service_url) {
delete this.validationErrors.model_service_url
}
}
const label = payload?.label || 'model'
this.$toast?.success(`Linked ${label} via MedCAT Service`)
},
async fetchUsers() {
const response = await this.$http.get('/api/users/')
this.users = response.data.results || response.data
Expand Down
107 changes: 59 additions & 48 deletions medcat-trainer/webapp/frontend/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,74 @@
import { fileURLToPath, URL } from 'node:url'
import path from 'node:path'

import { defineConfig } from 'vite'
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
],
resolve: {
alias: {
vue: 'vue/dist/vue.esm-bundler.js',
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
build: {
sourcemap: true,
assetsDir: 'static',
chunkSizeWarningLimit: 1000,
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router'],
'vuetify-vendor': ['vuetify'],
'plotly-vendor': ['plotly.js-dist']
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '')
const mctEeRoot = env.MCT_EE_ROOT || path.resolve(
fileURLToPath(new URL('../../../../cogstack-private/medcat-trainer-ee/frontend/src', import.meta.url))
)

return {
plugins: [
vue(),
],
resolve: {
alias: {
vue: 'vue/dist/vue.esm-bundler.js',
'@': fileURLToPath(new URL('./src', import.meta.url)),
...(env.VITE_MCT_EE === '1'
? { '@mctee/enterprise': path.join(mctEeRoot, 'index.ts') }
: {}),
}
},
build: {
sourcemap: true,
assetsDir: 'static',
chunkSizeWarningLimit: 1000,
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router'],
'vuetify-vendor': ['vuetify'],
'plotly-vendor': ['plotly.js-dist']
}
}
}
}
},
server: {
host: '127.0.0.1',
proxy: {
'^/api/concepts/*': {
target: 'http://127.0.0.1:8983/solr',
changeOrigin: true,
secure: false,
rewrite: (path: string) => path.replace(/\/api\/concepts/, '/')
},
'^/api/*': {
target: 'http://127.0.0.1:8001'
},
server: {
host: '127.0.0.1',
proxy: {
'^/api/concepts/*': {
target: 'http://127.0.0.1:8983/solr',
changeOrigin: true,
secure: false,
rewrite: (path: string) => path.replace(/\/api\/concepts/, '/')
},
'^/api/*': {
target: 'http://127.0.0.1:8001'
}
}
}
},
css: {
preprocessorOptions: {
scss: {
// Bootstrap 5.x still uses deprecated Sass color/import builtins; harmless until v6.
// https://getbootstrap.com/docs/5.3/customize/sass/#sass-deprecation-warnings
silenceDeprecations: [
'color-functions',
'global-builtin',
'import',
'if-function'
],
additionalData: `
},
css: {
preprocessorOptions: {
scss: {
// Bootstrap 5.x still uses deprecated Sass color/import builtins; harmless until v6.
// https://getbootstrap.com/docs/5.3/customize/sass/#sass-deprecation-warnings
silenceDeprecations: [
'color-functions',
'global-builtin',
'import',
'if-function'
],
additionalData: `
@import "@/styles/_variables.scss";
@import "@/styles/_common.scss";
@import "@/styles/_tabs.scss";
`
}
}
}
}
Expand Down
Loading