Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement first step of modular #25

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
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
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module.exports = {
rules: {
'vue/multi-word-component-names': 'off',
'no-undef': 'off',
'vue/require-v-for-key': 'warn',
},
parserOptions: {
ecmaVersion: 'latest',
Expand Down
3 changes: 1 addition & 2 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{
"recommendations": [
"Vue.volar""]
"recommendations": ["Vue.volar"]
}
69 changes: 69 additions & 0 deletions CONFIG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Configuration file

A configuration file can be set to customize the header.

Inside it, you can set the following properties:
```json
{
"config": {},
"menu": [],
"i18n": {}
}
```

## Config

Config can contains old tag attributes :
```json
"config": {
"stylesheet": "https://data.lillemetropole.fr/public/georchestra.css",
"logoUrl": "https://data.lillemetropole.fr/public/logo-mel.jpg",
"hideLogin": false,
"lang": "es"
}
```

Full configuration [is here](./src/config-interfaces.ts#L32-L53).

:warning: You can also define stylesheet in the datadir (`default.properties`) because this file can be used in other georchestra's apps. It will take precedence over the one set in the config file of the header.

## Menu

Menu can contain three type of objects : `link` (by default), `separator` or `dropdown`

There's actually just one level of dropdowns. You cannot have a dropdown inside a dropdown.

To see the actual structure of the menu, you can check the [menu interface](./src/default-config.json)

### Active tab matching

A decision has been made in order to have the best match between the active tab and the current page.

If two conditions can be resolved for a link to be active, the longest one will be used.

URL of tab : /mapstore/#/home

- Condition 1 : activeAppUrl /mapstore
- Condition 2 : activeAppUrl /mapstore/#/home

Condition 2 will be used because /mapstore/#/home = 16 characters.


## i18n

In addition to translations set in [./src/i18n/](./src/i18n/), you can add custom translations :
```json
{
"i18n": {
"en": {
"customi18nkey": "WMS/WFS service"
},
"fr": {
"customi18nkey": "Service WMS/WFS"
},
"es": {
"customi18nkey": "Servicio WMS/WFS"
}
}
}
```
14 changes: 6 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,14 @@ Iframe can still be set with defining `legacy-url` attribute, style can also be

Attributes available :

| Attribute | Description | Example | For host | For legacy |
| ------------- | ---------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | -------- | ---------- |
| hideLogin | Used to hide the login buttton | `<geor-header hide-login='true'>` | v | |
| lang | Used to force header language (default value : en) | `<geor-header lang='de'>` | v | |
| active-app | Use this attribute to set the active class in menu | `<geor-header active-app='console'>` | v | v |
| logo-url | Use this attribute to set the logo for the new header (not legacy one). | `<geor-header logo-url='https://linktomylogo.com'>` | v | |
| Attribute | Description | Example | For new header | For legacy header (iframe) |
|-------------|-------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------| -------------- |----------------------------|
| active-app | Use this attribute to set the active class in menu | `<geor-header active-app='console'>` | | v |
| config-file | Use this attribute to set the config file for the new header (not legacy one). See [CONFIG.md](./CONFIG.md) | `<geor-header config-file="/config.json">` | v | |
| stylesheet | adds this stylesheet to the new header (not legacy one). | `<geor-header stylesheet="mystylesheet.css"></geor-header>` | v | |
| height | sets the height of the header (in pixels) | `<geor-header height="80"></geor-header>` | v | v |
| legacy-header | Use this attribute to enable the legacy header `iframe` tag. Needs `legacy-url`. | `<geor-header legacy-header='true' legacy-url="/header/">` | | v |
| legacy-url | Legacy URL: if set, activates iframe with src attribute pointing to this URL. Needs `legacy-header`. | `<geor-header legacy-header='true' legacy-url="/header/"></geor-header>` | | v |
| style | adds this style to iframe or host tag (if legacy url is not used) | `<geor-header legacy-url="myheader.com" style="width: 100%"></geor-header>` | v | v |
| stylesheet | adds this stylesheet to host tag | `<geor-header stylesheet="mystylesheet.css"></geor-header>` | v | |

3. Provide a custom stylesheet

Expand Down
5 changes: 1 addition & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@
<title>geOrchestra header</title>
</head>
<body style="margin: 0">
<geor-header
logo-url="https://www.georchestra.org/public/georchestra-logo.svg"
active-app="datahub"
></geor-header>
<geor-header config-file="/sample-config.json" stylesheet="" height="80"></geor-header>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
48 changes: 48 additions & 0 deletions public/sample-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"config": {
"stylesheet": "/public/georchestra.css",
"logoUrl": "/public/logo-mel.jpg",
"hideLogin": false,
"iconsUrl": "https://cdn.jsdelivr.net/gh/iconoir-icons/iconoir@main/css/iconoir.css",
"lang": "es"
},
"menu": [
{
"label": "Catalogue",
"i18n": "datahub",
"url": "/datahub/",
"activeAppUrl": "/datahub"
},
{
"label": "WMS/WFS",
"i18n": "customi18n",
"url": "/geoserver/web",
"activeAppUrl": "includes:/geoserver",
"icon": "iconoir-map"
},
{
"type": "separator"
},
{
"type": "dropdown",
"label": "A dropdown",
"items": [
{
"label": "Console",
"i18n": "users",
"url": "/console/manager/home",
"activeAppUrl": "/console",
"icon": "iconoir-globe"
},
{
"label": "Geonetwork",
"i18n": "catalogue",
"url": "/geonetwork/srv/:lang3/catalog.edit#/board",
"activeAppUrl": "/geonetwork",
"hasRole": "ROLE_GN_EDITOR",
"blockedRole": "ROLE_SUPERUSER,ROLE_GN_REVIEWER,ROLE_GN_ADMIN"
}
]
}
]
}
55 changes: 5 additions & 50 deletions src/auth.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,9 @@
const AUTH_API_URL = '/whoami'
const CONSOLE_PLATFORM_API_URL = '/console/private/platform/infos'

type KNOWN_ROLES =
| 'ROLE_SUPERUSER'
| 'ROLE_ORGADMIN'
| 'ROLE_MAPSTORE_ADMIN'
| 'ROLE_USER'
| 'ROLE_ADMINISTRATOR'
| 'ROLE_EXTRACTORAPP'
| 'ROLE_GN_REVIEWER'
| 'ROLE_GN_EDITOR'
| 'ROLE_GN_ADMIN'
| 'ROLE_EMAILPROXY'
| 'ROLE_ANONYMOUS'
| 'ROLE_IMPORT'

interface WhoAmIResponse {
GeorchestraUser: {
roles: KNOWN_ROLES[]
roles: string[]
username: string
firstName: string
lastName: string
Expand All @@ -33,17 +19,7 @@ export interface User {
anonymous: boolean
warned: boolean
remainingDays: string
adminRoles: AdminRoles | null
}

export interface AdminRoles {
superUser: boolean
admin: boolean
console: boolean
catalog: boolean
catalogAdmin: boolean
viewer: boolean
import: boolean
roles: string[]
}

export async function getUserDetails(): Promise<User> {
Expand All @@ -57,42 +33,21 @@ export async function getUserDetails(): Promise<User> {
warned: false,
remainingDays: '0',
anonymous: true,
adminRoles: null,
roles: ['ROLE_ANONYMOUS'],
}
}
const roles = user.roles
return {
username: user.username,
firstname: user.firstName,
lastname: user.lastName,
warned: user.ldapWarn,
remainingDays: user.ldapRemainingDays,
anonymous: roles.indexOf('ROLE_ANONYMOUS') > -1,
adminRoles: getAdminRoles(roles),
anonymous: user.roles.indexOf('ROLE_ANONYMOUS') > -1,
roles: user.roles,
}
})
}

export function getAdminRoles(roles: KNOWN_ROLES[]): AdminRoles | null {
const superUser = roles.indexOf('ROLE_SUPERUSER') > -1
const console = superUser || roles.indexOf('ROLE_ORGADMIN') > -1
const catalogAdmin = superUser || roles.indexOf('ROLE_GN_ADMIN') > -1
const catalog = !catalogAdmin && (roles.indexOf('ROLE_GN_EDITOR') > -1 || roles.indexOf('ROLE_GN_REVIEWER') > -1)
const viewer = superUser || roles.indexOf('ROLE_MAPSTORE_ADMIN') > -1
const admin =
superUser || console || catalog || viewer || catalogAdmin
if (!admin && roles.indexOf('ROLE_IMPORT') === -1) return null
return {
superUser,
admin,
console,
catalog,
catalogAdmin,
viewer,
import: superUser || roles.indexOf('ROLE_IMPORT') > -1,
}
}

export interface PlatformInfos {
analyticsEnabled: boolean
extractorappEnabled: boolean
Expand Down
47 changes: 47 additions & 0 deletions src/config-interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
interface MenuItem {
type?: string
//Role required to display the item
hasRole?: string
//Role which hides the item
blockedRole?: string
}

export interface Link extends MenuItem {
label: string
//URL to redirect to
url: string
//i18n key to display the label
i18n?: string
//to trigger the active tab (underline). By default, it triggers on start with e.g /console (start:/console) will trigger on /console** pages
// Values can be 'start', 'exact', 'includes', 'end'
activeAppUrl?: string
//Icon to display next to the label
icon?: string
}

export interface Dropdown extends MenuItem {
label: string
//i18n key to display the label
i18n?: string
//List of items to display in the dropdown
items?: Array<Link>
}

export interface Separator extends MenuItem {}

export interface Config {
//Logo url to display in the header
logoUrl?: string
//Title to the logo displayed in the header
logoTitle?: string
//Whether to hide the login button
hideLogin?: boolean
//Custom stylesheet to apply to the header
stylesheet?: string
//Link to icons url. Tested with https://cdn.jsdelivr.net/gh/iconoir-icons/iconoir@main/css/iconoir.css
iconsUrl?: string
//Force header's language
lang?: string
//List of roles considered as admin roles, if admin, triggers a request to /console/private/platform/infos
adminRoles: string[]
}
87 changes: 87 additions & 0 deletions src/default-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"defaultConfig": {
"hideLogin": false,
"adminRoles": [
"ROLE_SUPERUSER",
"ROLE_ORGADMIN",
"ROLE_GN_ADMIN",
"ROLE_GN_REVIEWER",
"ROLE_GN_EDITOR",
"ROLE_MAPSTORE_ADMIN"
]
},
"defaultMenu": [
{
"label": "Catalogue",
"i18n": "catalogue",
"url": "/datahub/",
"activeAppUrl": "/datahub"
},
{
"label": "Mapstore viewer",
"i18n": "viewer",
"url": "/mapstore",
"activeAppUrl": "/mapstore"
},
{
"label": "Maps",
"i18n": "maps",
"url": "/mapstore/#/home",
"activeAppUrl": "/mapstore/#/home"
},
{
"label": "Services",
"i18n": "services",
"url": "/geoserver/web",
"activeAppUrl": "/geoserver"
},
{
"label": "Datafeeder",
"i18n": "datafeeder",
"url": "/import",
"activeAppUrl": "/import",
"hasRole": "ROLE_SUPERUSER,ROLE_IMPORT"
},
{
"hasRole": "ROLE_SUPERUSER,ROLE_GN_EDITOR,ROLE_GN_ADMIN,ROLE_MAPSTORE_ADMIN",
"type": "separator"
},
{
"type": "dropdown",
"label": "Administration",
"i18n": "admin",
"hasRole": "ROLE_SUPERUSER,ROLE_GN_EDITOR,ROLE_GN_ADMIN,ROLE_MAPSTORE_ADMIN",
"items": [
{
"label": "Geonetwork",
"i18n": "catalogue",
"url": "/geonetwork/srv/:lang3/catalog.edit#/board",
"activeAppUrl": "/geonetwork",
"hasRole": "ROLE_GN_EDITOR",
"blockedRole": "ROLE_SUPERUSER,ROLE_GN_REVIEWER,ROLE_GN_ADMIN"
},
{
"label": "Geonetwork",
"i18n": "catalogue",
"url": "/geonetwork/srv/:lang3/admin.console",
"activeAppUrl": "/geonetwork",
"hasRole": "ROLE_SUPERUSER,ROLE_GN_REVIEWER,ROLE_GN_ADMIN"
},
{
"label": "Viewer",
"i18n": "viewer",
"url": "/mapstore/#/admin",
"activeAppUrl": "/mapstore/#/admin",
"hasRole": "ROLE_SUPERUSER,ROLE_MAPSTORE_ADMIN"
},
{
"label": "Console",
"i18n": "users",
"url": "/console/manager/home",
"activeAppUrl": "/console/manager",
"hasRole": "ROLE_SUPERUSER"
}
]
}
]
}
Loading