diff --git a/.changeset/early-oranges-flash.md b/.changeset/early-oranges-flash.md new file mode 100644 index 0000000..e9d7472 --- /dev/null +++ b/.changeset/early-oranges-flash.md @@ -0,0 +1,11 @@ +--- +"specif-ai": patch +--- + +Remove in-app footer and add it to a new settings modal + +- Deleted FooterComponent and its related files +- Updated Header component to remove logout button and company logo +- Refactored Settings component with improved UI and added logout functionality +- Updated color scheme from secondary to slate in various components +- Added company logo color configuration in environment files diff --git a/ui/src/app/app.component.html b/ui/src/app/app.component.html index d332851..301346f 100644 --- a/ui/src/app/app.component.html +++ b/ui/src/app/app.component.html @@ -10,6 +10,5 @@ - diff --git a/ui/src/app/app.module.ts b/ui/src/app/app.module.ts index 50556a3..be5d84b 100644 --- a/ui/src/app/app.module.ts +++ b/ui/src/app/app.module.ts @@ -22,7 +22,6 @@ import { ProjectsState } from './store/projects/projects.state'; import { UserStoriesState } from './store/user-stories/user-stories.state'; import { LoadingInterceptor } from './interceptor/http.interceptor'; import { BreadcrumbState } from './store/breadcrumb/breadcrumb.state'; -import { FooterComponent } from './components/layout/footer/footer.component'; import { BusinessProcessState } from './store/business-process/business-process.state'; import { MatDialogModule } from '@angular/material/dialog'; import * as Sentry from '@sentry/angular'; @@ -39,7 +38,10 @@ import { environment } from '../environments/environment'; import { MatSelectModule } from '@angular/material/select'; import { MatBadgeModule } from '@angular/material/badge'; import { MatSnackBarModule } from '@angular/material/snack-bar'; -import { MAT_TOOLTIP_DEFAULT_OPTIONS, MatTooltipDefaultOptions } from '@angular/material/tooltip'; +import { + MAT_TOOLTIP_DEFAULT_OPTIONS, + MatTooltipDefaultOptions, +} from '@angular/material/tooltip'; import { ChatSettingsState } from './store/chat-settings/chat-settings.state'; import { Title } from '@angular/platform-browser'; import { InputFieldComponent } from './components/core/input-field/input-field.component'; @@ -94,7 +96,6 @@ import { AuthStateService } from './services/auth/auth-state.service'; NgIconsModule, NgOptimizedImage, ToasterComponent, - FooterComponent, HeaderComponent, LoadingComponent, AlertComponent, @@ -108,8 +109,8 @@ import { AuthStateService } from './services/auth/auth-state.service'; useValue: { position: 'below', showDelay: 500, - hideDelay: 500 - } as MatTooltipDefaultOptions + hideDelay: 500, + } as MatTooltipDefaultOptions, }, AuthStateService, AuthService, @@ -129,8 +130,8 @@ import { AuthStateService } from './services/auth/auth-state.service'; provide: APP_INITIALIZER, deps: [Sentry.TraceService], multi: true, - useFactory: () => () => {} - } + useFactory: () => () => {}, + }, ], bootstrap: [AppComponent], }) diff --git a/ui/src/app/components/layout/footer/footer.component.html b/ui/src/app/components/layout/footer/footer.component.html deleted file mode 100644 index 349e138..0000000 --- a/ui/src/app/components/layout/footer/footer.component.html +++ /dev/null @@ -1,12 +0,0 @@ -
-
-
- - Accelerate SDLC process with {{ themeConfiguration.companyName }} - - {{ version }} -
-
-
diff --git a/ui/src/app/components/layout/footer/footer.component.ts b/ui/src/app/components/layout/footer/footer.component.ts deleted file mode 100644 index 05f5b10..0000000 --- a/ui/src/app/components/layout/footer/footer.component.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Component, inject } from '@angular/core'; -import { environment } from '../../../../environments/environment'; -import { AuthService } from '../../../services/auth/auth.service'; -import { AsyncPipe, NgIf } from '@angular/common'; - -@Component({ - selector: 'app-footer', - templateUrl: './footer.component.html', - styleUrls: ['./footer.component.scss'], - standalone: true, - imports: [NgIf, AsyncPipe], -}) -export class FooterComponent { - protected themeConfiguration = environment.ThemeConfiguration; - - authService = inject(AuthService); - version: string = environment.APP_VERSION; - currentYear = new Date().getFullYear(); -} diff --git a/ui/src/app/components/layout/header/header.component.html b/ui/src/app/components/layout/header/header.component.html index 2eb9353..ac91bb9 100644 --- a/ui/src/app/components/layout/header/header.component.html +++ b/ui/src/app/components/layout/header/header.component.html @@ -1,72 +1,54 @@
-
+
- -
- -
- -
- -
- -
- -
-
- -
- +
+
+
+ +
- +
diff --git a/ui/src/app/components/layout/header/header.component.ts b/ui/src/app/components/layout/header/header.component.ts index d453a4e..cf8e855 100644 --- a/ui/src/app/components/layout/header/header.component.ts +++ b/ui/src/app/components/layout/header/header.component.ts @@ -5,7 +5,7 @@ import { MatDialog } from '@angular/material/dialog'; import { ElectronService } from '../../../services/electron/electron.service'; import { NGXLogger } from 'ngx-logger'; import { Router, RouterLink } from '@angular/router'; -import { LlmSettingsComponent } from '../../llm-settings/llm-settings.component'; +import { SettingsComponent } from '../../settings/settings.component'; import { AuthService } from '../../../services/auth/auth.service'; import { environment } from '../../../../environments/environment'; import { NgIconComponent, provideIcons } from '@ng-icons/core'; @@ -17,8 +17,6 @@ import { heroCog8Tooth, heroFolder, } from '@ng-icons/heroicons/outline'; -import { ConfirmationDialogComponent } from '../../../components/confirmation-dialog/confirmation-dialog.component'; -import { CONFIRMATION_DIALOG } from '../../../constants/app.constants'; @Component({ selector: 'app-header', @@ -57,9 +55,10 @@ export class HeaderComponent { this.logger.debug(response); if (response.length > 0) { localStorage.setItem(APP_CONSTANTS.WORKING_DIR, response[0]); - const currentConfig = await this.electronService.getStoreValue("APP_CONFIG") || {}; + const currentConfig = + (await this.electronService.getStoreValue('APP_CONFIG')) || {}; const updatedConfig = { ...currentConfig, directoryPath: response[0] }; - await this.electronService.setStoreValue("APP_CONFIG", updatedConfig); + await this.electronService.setStoreValue('APP_CONFIG', updatedConfig); this.logger.debug('===>', this.router.url); if (this.router.url === '/apps') { @@ -83,24 +82,8 @@ export class HeaderComponent { } openSettingsModal() { - this.dialog.open(LlmSettingsComponent, { + this.dialog.open(SettingsComponent, { disableClose: true, }); } - - logout() { - const dialogRef = this.dialog.open(ConfirmationDialogComponent, { - width: '500px', - data: { - title: CONFIRMATION_DIALOG.LOGOUT.TITLE, - description: CONFIRMATION_DIALOG.LOGOUT.DESCRIPTION, - cancelButtonText: CONFIRMATION_DIALOG.LOGOUT.CANCEL_BUTTON_TEXT, - proceedButtonText: CONFIRMATION_DIALOG.LOGOUT.PROCEED_BUTTON_TEXT, - }, - }); - - dialogRef.afterClosed().subscribe((res) => { - if (!res) this.authService.logout(); - }); - } } diff --git a/ui/src/app/components/llm-settings/llm-settings.component.html b/ui/src/app/components/llm-settings/llm-settings.component.html deleted file mode 100644 index 39a8b59..0000000 --- a/ui/src/app/components/llm-settings/llm-settings.component.html +++ /dev/null @@ -1,76 +0,0 @@ - \ No newline at end of file diff --git a/ui/src/app/components/llm-settings/llm-settings.component.scss b/ui/src/app/components/llm-settings/llm-settings.component.scss deleted file mode 100644 index e69de29..0000000 diff --git a/ui/src/app/components/llm-settings/llm-settings.component.spec.ts b/ui/src/app/components/llm-settings/llm-settings.component.spec.ts deleted file mode 100644 index 438c9e6..0000000 --- a/ui/src/app/components/llm-settings/llm-settings.component.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { LlmSettingsComponent } from './llm-settings.component'; - -describe('LlmSettingsComponent', () => { - let component: LlmSettingsComponent; - let fixture: ComponentFixture; - - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [LlmSettingsComponent] - }); - fixture = TestBed.createComponent(LlmSettingsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/ui/src/app/components/settings/settings.component.html b/ui/src/app/components/settings/settings.component.html new file mode 100644 index 0000000..30a927a --- /dev/null +++ b/ui/src/app/components/settings/settings.component.html @@ -0,0 +1,160 @@ + diff --git a/ui/src/app/components/layout/footer/footer.component.scss b/ui/src/app/components/settings/settings.component.scss similarity index 100% rename from ui/src/app/components/layout/footer/footer.component.scss rename to ui/src/app/components/settings/settings.component.scss diff --git a/ui/src/app/components/layout/footer/footer.component.spec.ts b/ui/src/app/components/settings/settings.component.spec.ts similarity index 50% rename from ui/src/app/components/layout/footer/footer.component.spec.ts rename to ui/src/app/components/settings/settings.component.spec.ts index 832b03a..c2333ad 100644 --- a/ui/src/app/components/layout/footer/footer.component.spec.ts +++ b/ui/src/app/components/settings/settings.component.spec.ts @@ -1,16 +1,16 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FooterComponent } from './footer.component'; +import { SettingsComponent } from './settings.component'; -describe('FooterComponent', () => { - let component: FooterComponent; - let fixture: ComponentFixture; +describe('SettingsComponent', () => { + let component: SettingsComponent; + let fixture: ComponentFixture; beforeEach(() => { TestBed.configureTestingModule({ - declarations: [FooterComponent] + declarations: [SettingsComponent] }); - fixture = TestBed.createComponent(FooterComponent); + fixture = TestBed.createComponent(SettingsComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/ui/src/app/components/llm-settings/llm-settings.component.ts b/ui/src/app/components/settings/settings.component.ts similarity index 58% rename from ui/src/app/components/llm-settings/llm-settings.component.ts rename to ui/src/app/components/settings/settings.component.ts index 2a3a6a3..1733d33 100644 --- a/ui/src/app/components/llm-settings/llm-settings.component.ts +++ b/ui/src/app/components/settings/settings.component.ts @@ -1,26 +1,47 @@ -import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core'; +import { + Component, + OnInit, + OnDestroy, + ChangeDetectorRef, + inject, +} from '@angular/core'; import { LLMConfigState } from 'src/app/store/llm-config/llm-config.state'; import { distinctUntilChanged, Observable, Subscription } from 'rxjs'; import { LLMConfigModel } from '../../model/interfaces/ILLMConfig'; import { Store } from '@ngxs/store'; -import { AvailableProviders, ProviderModelMap } from '../../constants/llm.models.constants'; -import { SetLLMConfig, SyncLLMConfig } from '../../store/llm-config/llm-config.actions'; -import { MatDialogRef } from '@angular/material/dialog'; +import { + AvailableProviders, + ProviderModelMap, +} from '../../constants/llm.models.constants'; +import { + SetLLMConfig, + SyncLLMConfig, +} from '../../store/llm-config/llm-config.actions'; +import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { NgIconComponent } from '@ng-icons/core'; import { NgForOf, NgIf } from '@angular/common'; import { AuthService } from '../../services/auth/auth.service'; import { ToasterService } from '../../services/toaster/toaster.service'; import { ButtonComponent } from '../core/button/button.component'; +import { ConfirmationDialogComponent } from '../../components/confirmation-dialog/confirmation-dialog.component'; +import { CONFIRMATION_DIALOG } from '../../constants/app.constants'; +import { environment } from 'src/environments/environment'; @Component({ - selector: 'app-llm-settings', - templateUrl: './llm-settings.component.html', - styleUrls: ['./llm-settings.component.scss'], + selector: 'app-settings', + templateUrl: './settings.component.html', + styleUrls: ['./settings.component.scss'], standalone: true, - imports: [ReactiveFormsModule, NgIconComponent, NgForOf, NgIf, ButtonComponent], + imports: [ + ReactiveFormsModule, + NgIconComponent, + NgForOf, + NgIf, + ButtonComponent, + ], }) -export class LlmSettingsComponent implements OnInit, OnDestroy { +export class SettingsComponent implements OnInit, OnDestroy { llmConfig$: Observable = this.store.select( LLMConfigState.getConfig, ); @@ -34,13 +55,18 @@ export class LlmSettingsComponent implements OnInit, OnDestroy { private subscriptions: Subscription = new Subscription(); private initialModel: string = ''; private initialProvider: string = ''; + protected themeConfiguration = environment.ThemeConfiguration; + + dialog = inject(MatDialog); + version: string = environment.APP_VERSION; + currentYear = new Date().getFullYear(); constructor( - private modalRef: MatDialogRef, + private modalRef: MatDialogRef, private store: Store, private authService: AuthService, private toasterService: ToasterService, - private cdr: ChangeDetectorRef + private cdr: ChangeDetectorRef, ) {} ngOnInit(): void { @@ -53,7 +79,7 @@ export class LlmSettingsComponent implements OnInit, OnDestroy { this.initialModel = config.model; this.initialProvider = config.provider; this.hasChanges = false; - }) + }), ); this.onModelChange(); this.onProviderChange(); @@ -66,11 +92,11 @@ export class LlmSettingsComponent implements OnInit, OnDestroy { .subscribe((res) => { this.updateFilteredModels(this.selectedProvider.value); this.errorMessage = ''; - this.hasChanges = - this.selectedModel.value !== this.initialModel || + this.hasChanges = + this.selectedModel.value !== this.initialModel || this.selectedProvider.value !== this.initialProvider; this.cdr.markForCheck(); - }) + }), ); } @@ -82,11 +108,11 @@ export class LlmSettingsComponent implements OnInit, OnDestroy { this.updateFilteredModels(res); this.selectedModel.setValue(ProviderModelMap[res][0]); this.errorMessage = ''; - this.hasChanges = - this.selectedModel.value !== this.initialModel || + this.hasChanges = + this.selectedModel.value !== this.initialModel || this.selectedProvider.value !== this.initialProvider; this.cdr.detectChanges(); - }) + }), ); } @@ -100,7 +126,7 @@ export class LlmSettingsComponent implements OnInit, OnDestroy { ...this.currentLLMConfig, model: this.initialModel, provider: this.initialProvider, - }) + }), ); this.modalRef.close(false); } @@ -111,7 +137,7 @@ export class LlmSettingsComponent implements OnInit, OnDestroy { this.authService.verifyProviderConfig(provider, model).subscribe({ next: (response) => { - if (response.status === "success") { + if (response.status === 'success') { const newConfig = { ...this.currentLLMConfig, model: model, @@ -119,20 +145,45 @@ export class LlmSettingsComponent implements OnInit, OnDestroy { }; this.store.dispatch(new SetLLMConfig(newConfig)).subscribe(() => { this.store.dispatch(new SyncLLMConfig()).subscribe(() => { - const providerDisplayName = this.availableProviders.find(p => p.key === provider)?.displayName || provider; - this.toasterService.showSuccess(`${providerDisplayName} : ${model} is configured successfully.`); + const providerDisplayName = + this.availableProviders.find((p) => p.key === provider) + ?.displayName || provider; + this.toasterService.showSuccess( + `${providerDisplayName} : ${model} is configured successfully.`, + ); this.modalRef.close(true); }); }); } else { - this.errorMessage = "Connection Failed! Please verify your model credentials in the backend configuration."; + this.errorMessage = + 'Connection Failed! Please verify your model credentials in the backend configuration.'; this.cdr.markForCheck(); } }, error: (error) => { - this.errorMessage = error.error?.message || 'Failed to verify provider configuration'; + this.errorMessage = + error.error?.message || 'Failed to verify provider configuration'; this.cdr.markForCheck(); - } + }, + }); + } + + logout() { + // Close the settings modal and open the logout confirmation dialog + this.modalRef.close(true); + + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + width: '500px', + data: { + title: CONFIRMATION_DIALOG.LOGOUT.TITLE, + description: CONFIRMATION_DIALOG.LOGOUT.DESCRIPTION, + cancelButtonText: CONFIRMATION_DIALOG.LOGOUT.CANCEL_BUTTON_TEXT, + proceedButtonText: CONFIRMATION_DIALOG.LOGOUT.PROCEED_BUTTON_TEXT, + }, + }); + + dialogRef.afterClosed().subscribe((res) => { + if (!res) this.authService.logout(); }); } diff --git a/ui/src/assets/img/presidio-blue.svg b/ui/src/assets/img/presidio-blue.svg new file mode 100644 index 0000000..3aa9011 --- /dev/null +++ b/ui/src/assets/img/presidio-blue.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/ui/src/environments/environment.development.ts b/ui/src/environments/environment.development.ts index 5a02c0c..3b7f58e 100644 --- a/ui/src/environments/environment.development.ts +++ b/ui/src/environments/environment.development.ts @@ -14,6 +14,7 @@ export const environment = { appDescription: 'Get started to accelerate SDLC Process', companyName: 'Presidio', companyLogo: 'assets/img/presidio-white.svg', + companyLogoColor: 'assets/img/presidio-blue.svg', appIcons: { mac: 'assets/icons/mac_icon.icns', win: 'assets/icons/win_icon.ico', diff --git a/ui/src/environments/environment.prod.ts b/ui/src/environments/environment.prod.ts index 7df3c89..b996b87 100644 --- a/ui/src/environments/environment.prod.ts +++ b/ui/src/environments/environment.prod.ts @@ -14,6 +14,7 @@ export const environment = { appDescription: 'Get started to accelerate SDLC Process', companyName: 'Presidio', companyLogo: 'assets/img/presidio-white.svg', + companyLogoColor: 'assets/img/presidio-blue.svg', appIcons: { mac: 'assets/icons/mac_icon.icns', win: 'assets/icons/win_icon.ico', diff --git a/ui/src/environments/environment.ts b/ui/src/environments/environment.ts index afebb9d..e8561c7 100644 --- a/ui/src/environments/environment.ts +++ b/ui/src/environments/environment.ts @@ -14,6 +14,7 @@ export const environment = { appDescription: 'Get started to accelerate SDLC Process', companyName: 'Presidio', companyLogo: 'assets/img/presidio-white.svg', + companyLogoColor: 'assets/img/presidio-blue.svg', appIcons: { mac: 'assets/icons/mac_icon.icns', win: 'assets/icons/win_icon.ico',