diff --git a/src/@noctua.announcement/@noctua.announcement.module.ts b/src/@noctua.announcement/@noctua.announcement.module.ts new file mode 100644 index 00000000..9ce5bb48 --- /dev/null +++ b/src/@noctua.announcement/@noctua.announcement.module.ts @@ -0,0 +1,25 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { AnnouncementPanelComponent } from './components/announcement-panel/announcement-panel.component'; +import { MatIconModule } from '@angular/material/icon'; +import { MatButtonModule } from '@angular/material/button'; +import { MatSidenavModule } from '@angular/material/sidenav'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { NoctuaSharedModule } from '@noctua/shared.module'; + +@NgModule({ + imports: [ + CommonModule, + MatIconModule, + MatButtonModule, + MatSidenavModule, + FlexLayoutModule, + NoctuaSharedModule + ], + exports: [ + AnnouncementPanelComponent + ], + declarations: [ + AnnouncementPanelComponent], +}) +export class NoctuaAnnouncementModule { } diff --git a/src/@noctua.announcement/components/announcement-panel/announcement-panel.component.html b/src/@noctua.announcement/components/announcement-panel/announcement-panel.component.html new file mode 100644 index 00000000..bcb4fee5 --- /dev/null +++ b/src/@noctua.announcement/components/announcement-panel/announcement-panel.component.html @@ -0,0 +1,20 @@ +
+
+ + Announcements + + +
+
+
+ {{announcement.title}}
+ {{announcement.description}} + + More Details + +
+
+
\ No newline at end of file diff --git a/src/@noctua.announcement/components/announcement-panel/announcement-panel.component.scss b/src/@noctua.announcement/components/announcement-panel/announcement-panel.component.scss new file mode 100644 index 00000000..33293d51 --- /dev/null +++ b/src/@noctua.announcement/components/announcement-panel/announcement-panel.component.scss @@ -0,0 +1,46 @@ +@use "@angular/material" as mat; +@import "src/@noctua/scss/noctua"; +@import "src/@noctua.common/scss/noctua.common"; + +:host { + //width: 100%; // display: block; + + background-color: white; + @include mat.elevation(4); + + .noc-cam-form { + @include deep-width(500px); + } + + .noc-header { + @include deep-height(40px); + background-color: #eee; + border-bottom: #ccc solid 1px; + + mat-icon-button { + @include deep-height(40px); + @include deep-width(40px); + line-height: 40px; + } + + .noc-title { + font-size: 10px; + padding: 0 14px; + } + } + + .noc-body { + padding: 0 14px 14px 14px; + } + + .noc-item { + @include deep-width(100%); + font-size: 12px; + + .noc-title { + font-weight: bold; + margin-right: 8px; + color: #999; + } + } +} diff --git a/src/@noctua.announcement/components/announcement-panel/announcement-panel.component.ts b/src/@noctua.announcement/components/announcement-panel/announcement-panel.component.ts new file mode 100644 index 00000000..e6040ea9 --- /dev/null +++ b/src/@noctua.announcement/components/announcement-panel/announcement-panel.component.ts @@ -0,0 +1,54 @@ +import { Component, Input, OnInit, OnDestroy } from '@angular/core'; +import { MatDrawer, MatSidenav } from '@angular/material/sidenav'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { + NoctuaFormMenuService +} from '@geneontology/noctua-form-base'; +import { NoctuaSearchMenuService } from '@noctua.search/services/search-menu.service'; +import { NoctuaAnnouncementService } from '@noctua.announcement/services/cam.service'; +import { Announcement } from '@noctua.announcement/models/announcement'; + + +@Component({ + selector: 'noc-announcement-panel', + templateUrl: './announcement-panel.component.html', + styleUrls: ['./announcement-panel.component.scss'], +}) + +export class AnnouncementPanelComponent implements OnInit, OnDestroy { + + @Input('sidenav') sidenav: MatSidenav; + announcements: Announcement[]; + + private _unsubscribeAll: Subject; + + constructor( + public noctuaSearchMenuService: NoctuaSearchMenuService, + public noctuaFormMenuService: NoctuaFormMenuService, + private noctuaAnnouncementService: NoctuaAnnouncementService, + ) { + this._unsubscribeAll = new Subject(); + } + + ngOnInit(): void { + this.noctuaAnnouncementService.onAnnouncementsChanged.pipe( + takeUntil(this._unsubscribeAll)) + .subscribe((announcements: Announcement[]) => { + if (announcements) { + this.announcements = announcements + } + }); + } + + ngOnDestroy(): void { + this._unsubscribeAll.next(null); + this._unsubscribeAll.complete(); + } + + close() { + this.sidenav.close(); + } + + +} diff --git a/src/@noctua.announcement/models/announcement.ts b/src/@noctua.announcement/models/announcement.ts new file mode 100644 index 00000000..9fb2775c --- /dev/null +++ b/src/@noctua.announcement/models/announcement.ts @@ -0,0 +1,8 @@ +export class Announcement { + type: string; + date: string; + level: string; + title: string; + content: string; + moreContentUrl?: string; +} \ No newline at end of file diff --git a/src/@noctua.announcement/services/cam.service.ts b/src/@noctua.announcement/services/cam.service.ts new file mode 100644 index 00000000..42a3a232 --- /dev/null +++ b/src/@noctua.announcement/services/cam.service.ts @@ -0,0 +1,33 @@ +import { HttpClient } from "@angular/common/http"; +import { Injectable } from "@angular/core"; +import { Announcement } from "@noctua.announcement/models/announcement"; +import { environment } from "environments/environment"; +import { BehaviorSubject } from "rxjs"; + +@Injectable({ + providedIn: 'root' +}) +export class NoctuaAnnouncementService { + cursor = 0; + onAnnouncementsChanged: BehaviorSubject; + onAnnouncementChanged: BehaviorSubject; + + constructor( + private httpClient: HttpClient) { + + this.onAnnouncementsChanged = new BehaviorSubject(null); + this.onAnnouncementChanged = new BehaviorSubject(null); + + } + + getAnnouncement() { + return this.httpClient.get(environment.announcementUrl).subscribe((response: Announcement[]) => { + if (response) { + if (response.length > 0) { + this.onAnnouncementChanged.next(response[this.cursor]); + } + this.onAnnouncementsChanged.next(response); + } + }); + } +} diff --git a/src/@noctua.common/models/menu-panels.ts b/src/@noctua.common/models/menu-panels.ts index cb654493..badddbec 100644 --- a/src/@noctua.common/models/menu-panels.ts +++ b/src/@noctua.common/models/menu-panels.ts @@ -10,6 +10,8 @@ export enum LeftPanel { activityForm = 'activityForm', camForm = 'camForm', copyModel = 'copyModel', + apps = 'apps', + announcement = 'announcement' }; export enum MiddlePanel { diff --git a/src/@noctua.common/services/noctua-common-menu.service.ts b/src/@noctua.common/services/noctua-common-menu.service.ts index dcbf2c29..cb9d8750 100644 --- a/src/@noctua.common/services/noctua-common-menu.service.ts +++ b/src/@noctua.common/services/noctua-common-menu.service.ts @@ -15,6 +15,7 @@ import { WorkbenchId } from '@noctua.common/models/workench-id'; export class NoctuaCommonMenuService { onCamSettingsChanged: BehaviorSubject; + selectedLeftSidenav: LeftPanel = LeftPanel.apps; selectedLeftPanel: LeftPanel; selectedMiddlePanel: MiddlePanel; selectedRightPanel: RightPanel; @@ -64,6 +65,10 @@ export class NoctuaCommonMenuService { return this._leftSidenav.open(); } + selectLeftSidenav(panel: LeftPanel) { + this.selectedLeftSidenav = panel; + } + selectLeftPanel(panel: LeftPanel) { this.selectedLeftPanel = panel; diff --git a/src/@noctua-doctor/data/obsolete.js b/src/@noctua.doctor/data/obsolete.js similarity index 100% rename from src/@noctua-doctor/data/obsolete.js rename to src/@noctua.doctor/data/obsolete.js diff --git a/src/@noctua-doctor/models/menu-panels.ts b/src/@noctua.doctor/models/menu-panels.ts similarity index 100% rename from src/@noctua-doctor/models/menu-panels.ts rename to src/@noctua.doctor/models/menu-panels.ts diff --git a/src/@noctua-doctor/services/doctor-menu.service.ts b/src/@noctua.doctor/services/doctor-menu.service.ts similarity index 95% rename from src/@noctua-doctor/services/doctor-menu.service.ts rename to src/@noctua.doctor/services/doctor-menu.service.ts index 07a6ec25..675823a0 100644 --- a/src/@noctua-doctor/services/doctor-menu.service.ts +++ b/src/@noctua.doctor/services/doctor-menu.service.ts @@ -1,6 +1,5 @@ import { Injectable } from '@angular/core'; import { MatDrawer } from '@angular/material/sidenav'; -import { NoctuaPerfectScrollbarDirective } from '@noctua/directives/noctua-perfect-scrollbar/noctua-perfect-scrollbar.directive'; import { PerfectScrollbarDirective } from 'ngx-perfect-scrollbar'; import { LeftPanel, MiddlePanel, RightPanel } from './../models/menu-panels'; diff --git a/src/@noctua-doctor/services/noctua-doctor.service.ts b/src/@noctua.doctor/services/noctua-doctor.service.ts similarity index 100% rename from src/@noctua-doctor/services/noctua-doctor.service.ts rename to src/@noctua.doctor/services/noctua-doctor.service.ts diff --git a/src/@noctua.editor/inline-editor/editor-dropdown/editor-dropdown.component.ts b/src/@noctua.editor/inline-editor/editor-dropdown/editor-dropdown.component.ts index 7f6a50e8..a9bcc4dc 100644 --- a/src/@noctua.editor/inline-editor/editor-dropdown/editor-dropdown.component.ts +++ b/src/@noctua.editor/inline-editor/editor-dropdown/editor-dropdown.component.ts @@ -132,14 +132,15 @@ export class NoctuaEditorDropdownComponent implements OnInit, OnDestroy { case EditorCategory.evidenceAll: self.noctuaActivityEntityService.addEvidence().then(() => { this.close(); - self.noctuaFormDialogService.openInfoToast('Activity successfully updated.', 'OK'); + self.noctuaFormDialogService.openInfoToast('Evidence successfully updated.', 'OK'); }); break; - default: - self.noctuaActivityEntityService.saveActivity().then(() => { + case EditorCategory.all: + self.noctuaActivityEntityService.addIndividual().then(() => { this.close(); self.noctuaFormDialogService.openInfoToast('Activity successfully updated.', 'OK'); }); + break; } } diff --git a/src/@noctua.form/data/config/shape-definition.ts b/src/@noctua.form/data/config/shape-definition.ts index 17ceca9d..c9100868 100644 --- a/src/@noctua.form/data/config/shape-definition.ts +++ b/src/@noctua.form/data/config/shape-definition.ts @@ -248,7 +248,7 @@ export const canInsertEntity = { label: 'Add Happens During (Biological Phase)', id: ActivityNodeType.GoBiologicalPhase, node: { - category: [EntityDefinition.GoBiologicalPhase], + category: [EntityDefinition.GoBiologicalPhase, EntityDefinition.UberonStage], type: ActivityNodeType.GoBiologicalPhase, label: 'happens during (Biological Phase)', displaySection: noctuaFormConfig.displaySection.fd, diff --git a/src/@noctua.form/models/activity/activity.ts b/src/@noctua.form/models/activity/activity.ts index fb70ef52..82d6d949 100644 --- a/src/@noctua.form/models/activity/activity.ts +++ b/src/@noctua.form/models/activity/activity.ts @@ -634,6 +634,17 @@ export class Activity extends SaeGraph { return saveData; } + createAddIndividual(srcActivity: Activity, predicate: Predicate) { + const self = this; + + const addTriples = self.getEdge(predicate.subjectId, predicate.objectId) + + const saveData = { + addTriples: addTriples, + }; + + return saveData; + } createDelete() { const self = this; diff --git a/src/@noctua.form/models/contributor.ts b/src/@noctua.form/models/contributor.ts index 9713bebc..8a132693 100644 --- a/src/@noctua.form/models/contributor.ts +++ b/src/@noctua.form/models/contributor.ts @@ -24,6 +24,15 @@ export class Contributor { get groups() { return this._groups; } + + static fromResponse(response) { + const user = new Contributor() + user.orcid = response.uri; + user.name = response.nickname; + user.groups = response.groups; + + return user; + } } export function compareContributor(a: Contributor, b: Contributor): number { diff --git a/src/@noctua.form/services/activity-entity.service.ts b/src/@noctua.form/services/activity-entity.service.ts index 8e66be39..e3359423 100644 --- a/src/@noctua.form/services/activity-entity.service.ts +++ b/src/@noctua.form/services/activity-entity.service.ts @@ -102,6 +102,20 @@ export class NoctuaActivityEntityService { saveData.removeIds); } + addIndividual() { + const self = this; + + self.activityEntityFormToActivity(); + + const saveData = self.activity.createAddIndividual(self.currentActivity, self.entity.predicate); + + return self.noctuaGraphService.editActivity(self.cam, + [self.entity], + [saveData.addTriples], + [], + []); + } + saveSearchDatabase() { const self = this; diff --git a/src/@noctua.form/services/cam.service.ts b/src/@noctua.form/services/cam.service.ts index 02c06bd4..a1a2ccb5 100644 --- a/src/@noctua.form/services/cam.service.ts +++ b/src/@noctua.form/services/cam.service.ts @@ -57,7 +57,6 @@ export class CamService { private curieService: CurieService) { this.onCamChanged = new BehaviorSubject(null); - this.curieUtil = this.curieService.getCurieUtil(); this.camFormGroup = new BehaviorSubject(null); this.camFormGroup$ = this.camFormGroup.asObservable(); diff --git a/src/@noctua.form/services/graph.service.ts b/src/@noctua.form/services/graph.service.ts index 6a91336c..d456bbbb 100644 --- a/src/@noctua.form/services/graph.service.ts +++ b/src/@noctua.form/services/graph.service.ts @@ -25,10 +25,11 @@ import { Article } from './../models/article'; import { Contributor, equalContributor } from '../models/contributor'; import * as moment from 'moment'; import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; +import { graph as bbopGraph } from 'bbop-graph-noctua'; declare const require: any; -const model = require('bbop-graph-noctua'); +//const model = require('bbop-graph-noctua'); const barista_client = require('bbop-client-barista'); const amigo = require('amigo2'); const barista_response = require('bbop-response-barista'); @@ -158,10 +159,9 @@ export class NoctuaGraphService { getMetadata(responseData) { const self = this; - const noctua_graph = model.graph; const cam = new Cam() - cam.graph = new noctua_graph(); + cam.graph = new bbopGraph(); cam.graph.load_data_basic(responseData); cam.id = responseData.id; @@ -197,18 +197,17 @@ export class NoctuaGraphService { rebuild(cam: Cam, response) { const self = this; - const noctua_graph = model.graph; // cam.loading.status = true; // cam.loading.message = 'Loading Model Entities Metadata...'; if (cam.graph) { - const inGraph = new noctua_graph(); + const inGraph = new bbopGraph(); inGraph.load_data_basic(response.data()); cam.graph.merge_special(inGraph); } else { - cam.graph = new noctua_graph(); + cam.graph = new bbopGraph(); cam.graph.load_data_basic(response.data()); } @@ -265,9 +264,8 @@ export class NoctuaGraphService { rebuildFromStoredApi(cam: Cam, activeModel) { const self = this; - const noctua_graph = model.graph; - cam.graph = new noctua_graph(); + cam.graph = new bbopGraph(); cam.graph.load_data_basic(activeModel); cam.id = activeModel.id; diff --git a/src/@noctua.form/services/user.service.ts b/src/@noctua.form/services/user.service.ts index 5f3f555e..64268215 100644 --- a/src/@noctua.form/services/user.service.ts +++ b/src/@noctua.form/services/user.service.ts @@ -32,33 +32,36 @@ export class NoctuaUserService { return this._baristaToken; } + /* Pass in the barista token, i.e. from the url params */ getUser(baristaTokenParam?: string) { - const self = this; + + //Check if there is any in the local storage const baristaToken = baristaTokenParam ? baristaTokenParam : localStorage.getItem('barista_token'); if (!baristaToken) { + //Log them out this.baristaToken = null; this.user = null; this.onUserChanged.next(this.user); } else { - return this.httpClient.get(`${self.baristaUrl}/user_info_by_token/${baristaToken}`) + // Check if indeed it is a legit token + return this.httpClient.get(`${this.baristaUrl}/user_info_by_token/${baristaToken}`) .subscribe((response: any) => { if (response) { if (response.token) { - this.user = new Contributor(); - this.user.orcid = response.uri; - this.user.name = response.nickname; - this.user.groups = response.groups; + //add the token on the local storage + this.user = Contributor.fromResponse(response); this.user.token = this.baristaToken = response.token; localStorage.setItem('barista_token', this.baristaToken); - this.onUserChanged.next(this.user); } else { + //log them out this.user = null; this.baristaToken = null; localStorage.removeItem('barista_token'); - this.onUserChanged.next(this.user); - } + } + this.onUserChanged.next(this.user); + // remove the token on the url const url = new URL(window.location.href); url.searchParams.delete('barista_token'); window.history.replaceState(null, null, url.href); diff --git a/src/@noctua.graph/services/graphEditorService.ts b/src/@noctua.graph/services/graph-editor-service.ts similarity index 100% rename from src/@noctua.graph/services/graphEditorService.ts rename to src/@noctua.graph/services/graph-editor-service.ts diff --git a/src/@noctua.search/models/menu-panels.ts b/src/@noctua.search/models/menu-panels.ts index 240b0686..a55ab36f 100644 --- a/src/@noctua.search/models/menu-panels.ts +++ b/src/@noctua.search/models/menu-panels.ts @@ -19,4 +19,5 @@ export enum MiddlePanel { export enum RightPanel { camForm = 'camForm', copyModel = 'copyModel', + announcement = 'announcement', } \ No newline at end of file diff --git a/src/@noctua.search/services/search-menu.service.ts b/src/@noctua.search/services/search-menu.service.ts index c3966882..1455870b 100644 --- a/src/@noctua.search/services/search-menu.service.ts +++ b/src/@noctua.search/services/search-menu.service.ts @@ -1,6 +1,5 @@ import { Injectable } from '@angular/core'; import { MatDrawer } from '@angular/material/sidenav'; -import { NoctuaPerfectScrollbarDirective } from '@noctua/directives/noctua-perfect-scrollbar/noctua-perfect-scrollbar.directive'; import { PerfectScrollbarDirective } from 'ngx-perfect-scrollbar'; import { LeftPanel, MiddlePanel, RightPanel } from './../models/menu-panels'; import { ReviewMode } from './../models/review-mode'; diff --git a/src/@noctua/scss/core.scss b/src/@noctua/scss/core.scss index 25e70a32..fdd43e0f 100644 --- a/src/@noctua/scss/core.scss +++ b/src/@noctua/scss/core.scss @@ -1,5 +1,5 @@ -@use '@angular/material' as mat; -@import '~perfect-scrollbar/css/perfect-scrollbar'; +@use "@angular/material" as mat; +@import "~perfect-scrollbar/css/perfect-scrollbar"; @import "noctua"; @include mat.core(); @include mat.all-component-typographies($typography); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4e3c0d93..c636f017 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -59,7 +59,7 @@ import { faUser, faUsers, } from '@fortawesome/free-solid-svg-icons'; -import { faCheckCircle, faTimesCircle, faTrashAlt, } from '@fortawesome/free-regular-svg-icons'; +import { faBell, faCheckCircle, faTimesCircle, faTrashAlt, } from '@fortawesome/free-regular-svg-icons'; import { faGithub, faFacebook, faTwitter } from '@fortawesome/free-brands-svg-icons'; import { FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { NoctuaDataService } from '@noctua.common/services/noctua-data.service'; @@ -128,6 +128,7 @@ export class AppModule { faAngleLeft, faAngleRight, faBars, + faBell, faCalendarDay, faCalendarWeek, faCaretDown, diff --git a/src/app/layout/components/noctua-apps/noctua-apps.component.ts b/src/app/layout/components/noctua-apps/noctua-apps.component.ts index cf2bc97c..4bfb5919 100644 --- a/src/app/layout/components/noctua-apps/noctua-apps.component.ts +++ b/src/app/layout/components/noctua-apps/noctua-apps.component.ts @@ -15,8 +15,7 @@ import { WorkbenchId } from '@noctua.common/models/workench-id'; }) export class NoctuaAppsComponent implements OnInit, OnDestroy { WorkbenchId = WorkbenchId; - @Input('sidenav') - sidenav: MatSidenav; + @Input('sidenav') sidenav: MatSidenav; public cam: Cam; date: Date; diff --git a/src/app/layout/components/toolbar/toolbar.component.html b/src/app/layout/components/toolbar/toolbar.component.html index 7923cf4b..9a79efeb 100644 --- a/src/app/layout/components/toolbar/toolbar.component.html +++ b/src/app/layout/components/toolbar/toolbar.component.html @@ -1,104 +1,128 @@ - - -
-