Skip to content

Commit

Permalink
feat: implement first step of modular (#25)
Browse files Browse the repository at this point in the history
* feat: implement first step of modular

* feat: first step of condition

* feat: set menu config file and block account

* feat: add i18n, config file, improve repsonsive

* feat: add active app url

* feat: add types and update active app scoring

* feat: remove activeApp

* feat: format

* feat: this should work

* feat: remove getActiveTab

* feat: better naming

* feat: ugly but working

* feat: cleaning

* feat: add icons

* feat: format and readme

* feat: add documentation

* feat: add documentation

* feat: better example

* feat: use object assign to keep default values

* fix: build

* fix: reset height

* feat: set leagcy header back to props to avoid import config file

* feat: set leagcy header back to props to avoid import config file

* feat: and logo either

* feat: added logo url doc back

* feat: avoid icons to get on top of text
  • Loading branch information
f-necas authored Jan 23, 2025
1 parent aeea8d9 commit 03ee576
Show file tree
Hide file tree
Showing 12 changed files with 579 additions and 210 deletions.
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"
}
}
}
```
15 changes: 7 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,15 @@ 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 | |
| logo-url | Use this attribute to set the logo for the new header (not legacy one). | `<geor-header logo-url='https://linktomylogo.com'>` | 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>
59 changes: 59 additions & 0 deletions public/sample-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"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"
}
]
}
],
"i18n": {
"en": {
"customi18n": "WMS/WFS service"
},
"fr": {
"customi18n": "Service WMS/WFS"
},
"es": {
"customi18n": "Servicio WMS/WFS"
}
}
}
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[]
}
Loading

0 comments on commit 03ee576

Please sign in to comment.