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: 1 addition & 1 deletion docker-compose/compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,4 @@ services:
limits:
memory: 4G
extra_hosts:
- "host.docker.internal:host-gateway"
- "host.docker.internal:host-gateway"
1 change: 1 addition & 0 deletions structures-frontend-next/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ declare module 'vue' {
RadioButton: typeof import('primevue/radiobutton')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
ScalarOpenAPI: typeof import('./src/components/ScalarOpenAPI.vue')['default']
Select: typeof import('primevue/select')['default']
SelectButton: typeof import('primevue/selectbutton')['default']
SideBar: typeof import('./src/components/SideBar.vue')['default']
Expand Down
16 changes: 12 additions & 4 deletions structures-frontend-next/src/components/ProjectList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,19 @@ export default class ProjectList extends Vue {
this.$router.push(`${this.$route.path}/edit/${item.id}`)
}

toProjectPage(item: Identifiable<string>): void {
async toProjectPage(item: Identifiable<string>): Promise<void> {
if (!item.id) return
const appId = this.applicationId
const projectId = item.id
this.$router.push(`/application/${encodeURIComponent(appId)}/project/${encodeURIComponent(projectId)}/structures`)

try {
const appId = this.applicationId
const projectId = item.id

console.log('ProjectList: Navigating to project:', (item as any).name, 'ID:', projectId, 'App ID:', appId)

await this.$router.push(`/application/${encodeURIComponent(appId)}/project/${encodeURIComponent(projectId)}/structures`)
} catch (error) {
console.error('[ProjectList] Failed to navigate to project page:', error)
}
}

clearSelectedProject() {
Expand Down
30 changes: 9 additions & 21 deletions structures-frontend-next/src/components/modals/OpenAPIModal.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<template>
<transition name="fade">
<div
v-if="visible"
class="fixed inset-0 bg-white z-50 flex flex-col"
>
<div
v-if="visible"
class="fixed inset-0 bg-white z-50 flex flex-col"
style="background-color: white !important;"
>
<div class="flex justify-between items-center p-4 border-b border-gray-200">
<div class="flex justify-center items-center gap-3">
<img src="@/assets/scalar.svg" />
Expand All @@ -14,10 +15,11 @@
<div class="flex-1 overflow-hidden">
<iframe
ref="iframeRef"
src="/scalar-ui.html"
:src="scalarUrl"
width="100%"
height="100%"
frameborder="0"
class="w-full h-full"
></iframe>
</div>
</div>
Expand All @@ -26,7 +28,6 @@

<script lang="ts">
import { Component, Vue, Prop, Emit, Ref } from 'vue-facing-decorator'
import Cookies from 'js-cookie'
import { APPLICATION_STATE } from '@/states/IApplicationState'

@Component({})
Expand All @@ -35,22 +36,9 @@ export default class OpenAPIModal extends Vue {
@Emit('close') close(): void {}
@Ref('iframeRef') iframeRef!: HTMLIFrameElement

onMounted() {
this.setupIframe()
}

private setupIframe() {
get scalarUrl() {
const namespace = APPLICATION_STATE.currentApplication?.id || 'default'
const token = Cookies.get('token')

if (!token) {
console.warn('No token found in cookie')
return
}

this.iframeRef?.addEventListener('load', () => {
this.iframeRef.contentWindow?.postMessage({ namespace, token }, '*')
})
return `/scalar-ui.html?namespace=${encodeURIComponent(namespace)}`
}
}
</script>
Expand Down
108 changes: 89 additions & 19 deletions structures-frontend-next/src/layouts/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,14 @@
</IconField>
</div>
<div v-for="app in filteredApplications" :key="app.id" @click="selectApp(app)"
class="px-4 py-2 hover:bg-gray-100 cursor-pointer text-surface-950 text-sm rounded">
{{ app.id }}
:class="[
'px-4 py-2 cursor-pointer text-sm rounded flex items-center justify-between',
currentApp?.id === app.id
? 'bg-blue-100 text-blue-700 font-medium'
: 'hover:bg-gray-100 text-surface-950'
]">
<span>{{ app.id }}</span>
<i v-if="currentApp?.id === app.id" class="pi pi-check text-blue-600"></i>
</div>
</div>
</div>
Expand All @@ -52,8 +58,14 @@
</IconField>
</div>
<div v-for="proj in filteredProjects" :key="proj.id ?? ''" @click="selectProject(proj)"
class="px-4 py-2 hover:bg-gray-100 cursor-pointer text-surface-950 text-sm rounded">
{{ proj.name }}
:class="[
'px-4 py-2 cursor-pointer text-sm rounded flex items-center justify-between',
currentProject?.id === proj.id
? 'bg-blue-100 text-blue-700 font-medium'
: 'hover:bg-gray-100 text-surface-950'
]">
<span>{{ proj.name }}</span>
<i v-if="currentProject?.id === proj.id" class="pi pi-check text-blue-600"></i>
</div>
</div>
</div>
Expand Down Expand Up @@ -151,6 +163,7 @@ export default class Header extends Vue {

@Watch('$route.fullPath', { immediate: true })
onRouteChange() {
console.log('Header: Route changed to:', this.$route.fullPath);
this.updateRouteState();
if (!APPLICATION_STATE.currentApplication) {
this.tryAutoSelectAppAndProject();
Expand All @@ -167,8 +180,26 @@ export default class Header extends Vue {

updateRouteState() {
const path = this.$route.path;
this.isApplicationDetailsPage = /^\/application\/[^/]+/.test(path);
this.isApplicationDetailsPage = /^\/application\/[^/]+$/.test(path);
this.isProjectStructuresPage = /^\/application\/[^/]+\/project\/[^/]+\/structures$/.test(path);

console.log('Header: updateRouteState - path:', path);
console.log('Header: isApplicationDetailsPage:', this.isApplicationDetailsPage);
console.log('Header: isProjectStructuresPage:', this.isProjectStructuresPage);

if (this.isApplicationDetailsPage && !this.isProjectStructuresPage) {
console.log('Header: On ApplicationDetails page - clearing project selection');
this.currentProject = null;
}
else if (this.isProjectStructuresPage) {
const projectId = this.$route.params.projectId as string;
console.log('Header: ProjectStructures page - projectId:', projectId);
console.log('Header: Current project:', this.currentProject?.id);
if (projectId && this.currentProject?.id !== projectId) {
console.log('Header: Detected project ID from URL:', projectId);
this.setCurrentProjectById(projectId);
}
}
}

loadApplicationsIfNeeded() {
Expand Down Expand Up @@ -216,6 +247,14 @@ export default class Header extends Vue {
const pageable = { pageNumber: 0, pageSize: 100 } as any;
const result = await Structures.getProjectService().findAllForApplication(this.currentApp.id, pageable);
this.projectsForCurrentApp = result.content ?? [];

if (this.isProjectStructuresPage) {
const projectId = this.$route.params.projectId as string;
if (projectId && this.currentProject?.id !== projectId) {
console.log('Header: Setting current project from URL after loading projects:', projectId);
this.setCurrentProjectById(projectId);
}
}
} catch (e) {
console.error('[Header] Failed to load projects:', e);
}
Expand All @@ -232,11 +271,8 @@ export default class Header extends Vue {

await this.loadProjectsForCurrentApp();

if (this.isProjectStructuresPage && this.projectsForCurrentApp.length > 0) {
const firstProject = this.projectsForCurrentApp[0];
console.log('Header: Auto-selecting first project for ProjectStructures page:', firstProject.name);
this.selectProject(firstProject);
}
console.log('Header: Redirecting to application details page for:', app.id);
await this.$router.push(`/application/${encodeURIComponent(app.id)}`);

this.$emit('application-changed', app);
}
Expand All @@ -260,20 +296,54 @@ export default class Header extends Vue {
}
}

async setActiveProjectById(applicationId: string, projectId: string) {
const app = this.allApplications.find(a => a.id === applicationId);
if (app) {
this.currentApp = app;
APPLICATION_STATE.currentApplication = app;

const pageable = { pageNumber: 0, pageSize: 100 } as any;
const result = await Structures.getProjectService().findAllForApplication(applicationId, pageable);
this.projectsForCurrentApp = result.content ?? [];
async setActiveProjectById(applicationId: string, projectId: string): Promise<void> {
try {
const app = this.allApplications.find(a => a.id === applicationId);
if (app) {
this.currentApp = app;
APPLICATION_STATE.currentApplication = app;

const pageable = { pageNumber: 0, pageSize: 100 } as any;
const result = await Structures.getProjectService().findAllForApplication(applicationId, pageable);
this.projectsForCurrentApp = result.content ?? [];

const proj = this.projectsForCurrentApp.find(p => p.id === projectId);
if (proj) {
this.currentProject = proj;
console.log('Header: Set active project to:', proj.name, 'ID:', proj.id);
console.log('Header: Current project after setting:', this.currentProject);
} else {
console.warn('Header: Project not found:', projectId);
console.log('Header: Available projects:', this.projectsForCurrentApp.map(p => ({ id: p.id, name: p.name })));
}
} else {
console.warn('Header: Application not found:', applicationId);
}
} catch (error) {
console.error('Header: Error setting active project:', error);
}
}

setCurrentProjectById(projectId: string): void {
console.log('Header: setCurrentProjectById called with projectId:', projectId);
console.log('Header: projectsForCurrentApp length:', this.projectsForCurrentApp.length);

if (this.projectsForCurrentApp.length > 0) {
const proj = this.projectsForCurrentApp.find(p => p.id === projectId);
if (proj) {
this.currentProject = proj;
console.log('Header: Set current project from URL to:', proj.name, 'ID:', proj.id);
console.log('Header: Current project after setting:', this.currentProject);
} else {
console.warn('Header: Project not found in current projects:', projectId);
console.log('Header: Available projects:', this.projectsForCurrentApp.map(p => ({ id: p.id, name: p.name })));
}
} else {
console.warn('Header: No projects loaded yet, cannot set current project');
this.loadProjectsForCurrentApp().then(() => {
console.log('Header: Projects loaded, retrying setCurrentProjectById');
this.setCurrentProjectById(projectId);
});
}
}

Expand Down