Skip to content
Snippets Groups Projects
Unverified Commit 295aca0b authored by Oliver Günther's avatar Oliver Günther
Browse files

Add central navigation adapter

parent 4c489ba5
No related branches found
No related tags found
No related merge requests found
Showing
with 510 additions and 0 deletions
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2022 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module Souvap
LinkedApplication = Struct.new(:identifier, :icon, :name, :link, keyword_init: true)
ApplicationGroup = Struct.new(:identifier, :name, :items, keyword_init: true)
end
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2022 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module Souvap
class CentralNavigationService
attr_reader :user
def initialize(user)
@user = user
end
def call
body = make_request
parse_items(JSON.parse(body)).compact
rescue StandardError => e
ServiceResult.failure(message: e.message)
end
private
def make_request
response = RestClient
.get(
Setting.souvap_navigation_url,
{
'Accept' => "application/json",
'Authorization' => "Basic #{credentials}"
}
)
raise "Failed to fetch central navigation data." if response.code >= 400
response.body
end
def credentials
shared_secret = Setting.souvap_navigation_secret
Base64::encode64("#{user.login}:#{shared_secret}")
end
end
end
<%= angular_component_tag 'op-souvap-central-navigation' %>
<ng-container *ngIf="active$ | async">
<ng-container *ngIf="(navigationGroups$ | async) as groups; else loadingTemplate">
<ul
*ngFor="let group of groups"
class="op-souvap-navigation--group"
>
<li
class="op-souvap-navigation--item-header"
[textContent]="group.name"
>
</li>
<li
*ngFor="let item of group.items"
class="op-souvap-navigation--item"
>
<a
class="op-souvap-navigation--item-link op-menu--item-action"
[href]="item.link"
>
<img
*ngIf="item.icon"
class="op-souvap-navigation--item-icon"
[src]="item.icon"/>
<span [textContent]="item.name"></span>
</a>
</li>
</ul>
</ng-container>
</ng-container>
<ng-template #loadingTemplate>
<op-content-loader
class="op-add-existing-pane--loading"
viewBox="0 0 200 70"
>
<svg:rect x="0" y="0" width="100%" height="20" rx="1"/>
<svg:rect x="0" y="24" width="100%" height="20" rx="1"/>
<svg:rect x="0" y="48" width="100%" height="20" rx="1"/>
</op-content-loader>
</ng-template>
.op-souvap-navigation
&--group
margin: 0
list-style: none
&--item-header
padding: 0 10px
font-weight: bold
display: block
height: 32px
line-height: 32px
&--item-icon
flex: 0
width: 24px
height: 24px
&--item-link
display: flex
align-items: center
gap: 0.25rem
import {
ChangeDetectionStrategy,
Component,
ElementRef,
HostBinding,
} from '@angular/core';
import { TopMenuService } from 'core-app/core/top-menu/top-menu.service';
import { map } from 'rxjs/operators';
import { CentralNavigationService } from 'core-app/features/plugins/linked/openproject-souvap/central-navigation/central-navigation.service';
export const souvapCentralNavigationSelector = 'op-souvap-central-navigation';
@Component({
selector: souvapCentralNavigationSelector,
templateUrl: './central-navigation.component.html',
styleUrls: ['./central-navigation.component.sass'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CentralNavigationComponent {
@HostBinding('class.op-souvap-navigation') className = true;
text:string;
active$ = this
.topMenuService
.activeDropdown$()
.pipe(
map((el) => el?.contains(this.elementRef.nativeElement)),
);
navigationGroups$ = this.centralNavigationService.navigationGroups$;
constructor(
private topMenuService:TopMenuService,
private elementRef:ElementRef,
private centralNavigationService:CentralNavigationService,
) {}
}
export interface ILinkedApplication {
identifier:string;
name:string;
icon:string;
link:string;
}
export interface IApplicationGroup {
identifier:string;
name:string;
items:ILinkedApplication[];
}
import { IApplicationGroup } from 'core-app/features/plugins/linked/openproject-souvap/central-navigation/central-navigation.model';
import { shareReplay } from 'rxjs/operators';
import { TopMenuService } from 'core-app/core/top-menu/top-menu.service';
import { Injectable } from '@angular/core';
import { PathHelperService } from 'core-app/core/path-helper/path-helper.service';
import { HttpClient } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class CentralNavigationService {
private url = this.pathHelper.api.v3.apiV3Base + '/linked_applications';
navigationGroups$ = this
.http
.get<IApplicationGroup[]>(this.url)
.pipe(
shareReplay(1),
);
constructor(
private topMenuService:TopMenuService,
private pathHelper:PathHelperService,
private http:HttpClient,
) {}
}
// -- copyright
// OpenProject is an open source project management software.
// Copyright (C) 2012-2022 the OpenProject GmbH
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2013 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See COPYRIGHT and LICENSE files for more details.
import {
Injector,
NgModule,
} from '@angular/core';
import { OPSharedModule } from 'core-app/shared/shared.module';
import {
CentralNavigationComponent,
souvapCentralNavigationSelector,
} from 'core-app/features/plugins/linked/openproject-souvap/central-navigation/central-navigation.component';
import { HookService } from 'core-app/features/plugins/hook-service';
import { ContentLoaderModule } from '@ngneat/content-loader';
@NgModule({
imports: [
OPSharedModule,
ContentLoaderModule,
],
declarations: [
CentralNavigationComponent,
],
exports: [
CentralNavigationComponent,
],
})
export class PluginModule {
constructor(injector:Injector) {
const hookService = injector.get(HookService);
hookService.register('openProjectAngularBootstrap', () => [
{ selector: souvapCentralNavigationSelector, cls: CentralNavigationComponent },
]);
}
}
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2022 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module API
module V3
module LinkedApplications
module Adapters
class Souvap < Base
def self.applicable?
!!(Setting.souvap_navigation_url && Setting.souvap_navigation_secret)
end
protected
def make_request
Rails.cache.fetch("souvap/navigation-items/#{session.id}", expires_in: 5.minutes) do
::Souvap::CentralNavigationService
.new(user.login)
.call
end
end
def transform(json)
json['categories'].map do |group|
next if group['identifier'] == 'ux_management'
items = group['entries'].map { |item| parse_item(item) }
::Souvap::ApplicationGroup.new identifier: group['identifier'],
name: group['display_name'],
items:
end
end
def parse_item(json)
::Souvap::LinkedApplication
.new({
identifier: json['identifier'],
icon: json['icon_url'],
link: json['link'],
name: json['display_name']
})
end
end
end
end
end
end
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2022 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module API
module V3
module LinkedApplications
class LinkedApplicationCollectionRepresenter < ::API::Decorators::UnpaginatedCollection
end
end
end
end
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2022 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module API
module V3
module LinkedApplications
class LinkedApplicationRepresenter < ::API::Decorators::Single
property :identifier
property :icon
property :name
property :name
end
end
end
end
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2022 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module API
module V3
module LinkedApplications
class LinkedApplicationsAPI < ::API::OpenProjectAPI
resource :linked_applications do
helpers do
def adapter
@adapter ||= Adapters::Souvap.new(user: current_user, session: request.session
)
end
end
get do
adapter.fetch_entries
end
end
end
end
end
end
...@@ -17,6 +17,28 @@ module OpenProject::Souvap ...@@ -17,6 +17,28 @@ module OpenProject::Souvap
'openproject-souvap', 'openproject-souvap',
:author_url => 'https://openproject.org', :author_url => 'https://openproject.org',
) do ) do
menu :top_menu,
:central_navigation,
nil,
partial: 'souvap/menu/top_menu_node'
end
add_api_path :linked_applications do
"#{root}/linked_applications"
end
add_api_endpoint 'API::V3::Root' do
mount ::API::V3::LinkedApplications::LinkedApplicationsAPI
end
initializer 'souvap.settings' do
::Settings::Definition.add 'souvap_navigation_url',
default: nil,
format: :string
::Settings::Definition.add 'souvap_navigation_secret',
default: nil,
format: :string
end end
end end
end end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment

Consent

On this website, we use the web analytics service Matomo to analyze and review the use of our website. Through the collected statistics, we can improve our offerings and make them more appealing for you. Here, you can decide whether to allow us to process your data and set corresponding cookies for these purposes, in addition to technically necessary cookies. Further information on data protection—especially regarding "cookies" and "Matomo"—can be found in our privacy policy. You can withdraw your consent at any time.