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

Merged
merged 26 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e5196b7
feat: implement first step of modular
f-necas Aug 2, 2024
4ebe0c0
feat: first step of condition
f-necas Oct 4, 2024
47aa4a1
feat: set menu config file and block account
f-necas Dec 2, 2024
0a49d94
feat: add i18n, config file, improve repsonsive
f-necas Dec 6, 2024
a42e38b
feat: add active app url
f-necas Dec 9, 2024
f1cd390
feat: add types and update active app scoring
f-necas Dec 9, 2024
da82e95
feat: remove activeApp
f-necas Dec 10, 2024
b27d85d
feat: format
f-necas Dec 10, 2024
8a2ef79
feat: this should work
f-necas Dec 10, 2024
0445430
feat: remove getActiveTab
f-necas Dec 18, 2024
ef47dd2
feat: better naming
f-necas Dec 20, 2024
8e8fbb9
feat: ugly but working
f-necas Dec 23, 2024
eab279f
feat: cleaning
f-necas Dec 23, 2024
3208d92
feat: add icons
f-necas Dec 23, 2024
7847a8c
feat: format and readme
f-necas Dec 23, 2024
eb9b75b
feat: add documentation
f-necas Dec 23, 2024
1734baf
feat: add documentation
f-necas Dec 23, 2024
145e829
feat: better example
f-necas Dec 23, 2024
c3bf847
feat: use object assign to keep default values
f-necas Dec 23, 2024
aaff7fe
fix: build
f-necas Dec 23, 2024
c2446ef
fix: reset height
f-necas Dec 23, 2024
6395a8e
feat: set leagcy header back to props to avoid import config file
f-necas Jan 8, 2025
5063b7b
feat: set leagcy header back to props to avoid import config file
f-necas Jan 8, 2025
f7c06a6
feat: and logo either
f-necas Jan 8, 2025
6aecb92
feat: added logo url doc back
f-necas Jan 22, 2025
0c51023
feat: avoid icons to get on top of text
f-necas Jan 22, 2025
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"]
}
71 changes: 71 additions & 0 deletions CONFIG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# 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": {
"legacyHeader": "false",
"legacyUrl": "/header",
"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"
}
}
}
```
16 changes: 6 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,12 @@ 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 | |
| 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 | |
| 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 |

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>
50 changes: 50 additions & 0 deletions public/sample-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"config": {
"legacyHeader": false,
"legacyUrl": "/header",
"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
51 changes: 51 additions & 0 deletions src/config-interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
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 {
//Display or not the legacy header (an iframe pointing to the legacyUrl)
legacyHeader?: boolean
//Legacy url to display in an iframe
legacyUrl?: string
//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