Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ To add new static pages go to **Admin Console** --> **Settings** --> **Static

- **Page section**: Section of the page to display the link. Currently implemented sections are `TOP` (top menu of the main page), `FOOTER` (footer of the main page), and `RECORD_VIEW_MENU` (toolbar shown on the record view page).

- **Workflow visibility (`RECORD_VIEW_MENU` only)**: Controls whether a page is shown for each workflow state.

- `showWhenWorkflowDisabled`
- `showOnApproved`
- `showOnNonApproved`

These options default to `true` (backward compatible).

- **Status**: Defines which users can see the link.

- **Visible only to the administrator**
Expand Down Expand Up @@ -123,4 +131,3 @@ As with the top toolbar, insert a page as a simple menu using the page identifie
## Change the static pages order in the footer

The order of the footer pages can be configured in **Admin Console** --> **Settings** --> **User interface**, in the **Footer custom menu items** section.

30 changes: 30 additions & 0 deletions domain/src/main/java/org/fao/geonet/domain/page/Page.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ public class Page extends GeonetEntity implements Serializable {

private String label;
private String icon;
private boolean showOnNonApproved = true;
private boolean showOnApproved = true;
private boolean showWhenWorkflowDisabled = true;

public Page() {

Expand Down Expand Up @@ -155,6 +158,33 @@ public String getIcon() {
return icon;
}

@Column(nullable = false, columnDefinition = "boolean default true")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When using db.migration_onstartup=false which sets hibernate.hbm2ddl.auto=validate, the new columns will not be created, probably better to add the new columns in the migration scripts.

On upgrade, Hibernate will find the entity declaring the new columns that don't exist in the DB and fail startup.

With the default db.migration_onstartup=true this problem will not happen.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in latest push

public boolean isShowOnNonApproved() {
return showOnNonApproved;
}

public void setShowOnNonApproved(boolean showOnNonApproved) {
this.showOnNonApproved = showOnNonApproved;
}

@Column(nullable = false, columnDefinition = "boolean default true")
public boolean isShowOnApproved() {
return showOnApproved;
}

public void setShowOnApproved(boolean showOnApproved) {
this.showOnApproved = showOnApproved;
}

@Column(nullable = false, columnDefinition = "boolean default true")
public boolean isShowWhenWorkflowDisabled() {
return showWhenWorkflowDisabled;
}

public void setShowWhenWorkflowDisabled(boolean showWhenWorkflowDisabled) {
this.showWhenWorkflowDisabled = showWhenWorkflowDisabled;
}

/**
* Get all the page's groups.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public class PageProperties implements Serializable {
private String icon;
private Page.PageFormat format;
private List<String> groups;
private boolean showOnNonApproved = true;
private boolean showOnApproved = true;
private boolean showWhenWorkflowDisabled = true;
private Page page;

public PageProperties() {
Expand All @@ -40,6 +43,9 @@ public PageProperties(Page p) {
status = p.getStatus();
label = p.getLabel();
icon = p.getIcon();
showOnNonApproved = p.isShowOnNonApproved();
showOnApproved = p.isShowOnApproved();
showWhenWorkflowDisabled = p.isShowWhenWorkflowDisabled();
if (CollectionUtils.isNotEmpty(p.getGroups())) {
groups = new ArrayList<>();
for (Group g : p.getGroups()) {
Expand Down Expand Up @@ -132,4 +138,28 @@ public List<String> getGroups() {
public void setGroups(List<String> groups) {
this.groups = groups;
}

public boolean isShowOnNonApproved() {
return showOnNonApproved;
}

public void setShowOnNonApproved(boolean showOnNonApproved) {
this.showOnNonApproved = showOnNonApproved;
}

public boolean isShowOnApproved() {
return showOnApproved;
}

public void setShowOnApproved(boolean showOnApproved) {
this.showOnApproved = showOnApproved;
}

public boolean isShowWhenWorkflowDisabled() {
return showWhenWorkflowDisabled;
}

public void setShowWhenWorkflowDisabled(boolean showWhenWorkflowDisabled) {
this.showWhenWorkflowDisabled = showWhenWorkflowDisabled;
}
}
10 changes: 10 additions & 0 deletions services/src/main/java/org/fao/geonet/api/pages/PagesAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ private ResponseEntity<String> createPage(PageProperties pageProperties,
}
}

newPage.setShowOnNonApproved(pageProperties.isShowOnNonApproved());
newPage.setShowOnApproved(pageProperties.isShowOnApproved());
newPage.setShowWhenWorkflowDisabled(pageProperties.isShowWhenWorkflowDisabled());

pageRepository.save(newPage);
return ResponseEntity.status(HttpStatus.CREATED).body("{}");
} else {
Expand Down Expand Up @@ -296,6 +300,9 @@ private ResponseEntity<Void> updatePageInternal(@NotNull String language,
newIcon != null ? newIcon : pageToUpdate.getIcon(),
CollectionUtils.isNotEmpty(_groups)? _groups: null);

pageCopy.setShowOnNonApproved(pageProperties.isShowOnNonApproved());
pageCopy.setShowOnApproved(pageProperties.isShowOnApproved());
pageCopy.setShowWhenWorkflowDisabled(pageProperties.isShowWhenWorkflowDisabled());
pageRepository.save(pageCopy);
pageRepository.delete(pageToUpdate);
} else {
Expand All @@ -305,6 +312,9 @@ private ResponseEntity<Void> updatePageInternal(@NotNull String language,
pageToUpdate.setStatus(pageProperties.getStatus() != null ? pageProperties.getStatus() : pageToUpdate.getStatus());
pageToUpdate.setLabel(newLabel);
pageToUpdate.setIcon(newIcon);
pageToUpdate.setShowOnNonApproved(pageProperties.isShowOnNonApproved());
pageToUpdate.setShowOnApproved(pageProperties.isShowOnApproved());
pageToUpdate.setShowWhenWorkflowDisabled(pageProperties.isShowWhenWorkflowDisabled());

pageToUpdate.getGroups().clear();
if (pageToUpdate.getStatus() == Page.PageStatus.GROUPS || pageToUpdate.getStatus() == Page.PageStatus.GROUPS_AND_ADMIN) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@
}
]);

/**
* Render static page menu entries for a configured section.
*
* Accepts a page id, an array of page ids, or nested submenu config through
* `gn-static-page-menu`.
*/
module.directive("gnStaticPageMenu", [
"gnStaticPagesService",
"gnGlobalSettings",
Expand Down Expand Up @@ -140,6 +146,120 @@
// Set button style based on explicit parameter (defaults to false)
$scope.renderAsButton = $scope.renderAsButton === "true";

/**
* Apply runtime visibility rules for a page.
*
* In `record_view_menu`, visibility depends on workflow state and
* metadata approval status from the current record context.
*/
function shouldShowPage(page) {
if (!page) return false;
if ($scope.section === "record_view_menu" && $scope.context) {
if (!$scope.context.isWorkflowEnabled)
return page.showWhenWorkflowDisabled === true;
if ($scope.context.mdStatus == 2) return page.showOnApproved === true;
return page.showOnNonApproved === true;
}
return true;
}

/**
* Recursively build a display-ready menu from `pagesConfig`.
*
* `pagesConfig` may contain page ids (strings) and submenu descriptors.
* Unknown page ids are ignored and logged to help diagnose UI config issues.
*/
function buildMenu(pagesMenu, staticPages, pagesConfig) {
pagesConfig.forEach(function (menu) {
if (typeof menu === "string") {
if (staticPages[menu]) {
if (shouldShowPage(staticPages[menu])) {
pagesMenu.push(staticPages[menu]);
}
} else {
console.warn(
menu +
" not found in pages configuration." +
" Check your UI configuration."
);
}
} else if (angular.isObject(menu)) {
var key = Object.keys(menu)[0];
var value = menu[key];

var submenu = {
label: key,
icon: undefined,
type: "submenu",
pages: []
};

var menuItems;

// If the submenu is using the legacy array format
if (angular.isArray(value)) {
menuItems = value;
// If the submenu is using the new object format with an items array and optional icon
} else if (angular.isObject(value)) {
if (angular.isArray(value.items)) {
menuItems = value.items;
}
if (angular.isDefined(value.icon)) {
submenu.icon = value.icon;
}
} else {
console.warn(
"Invalid menu configuration for " +
key +
". Expected an array of page identifiers or an object with an items array."
);
return;
}

buildMenu(submenu.pages, staticPages, menuItems);

if (submenu.pages.length > 0) {
pagesMenu.push(submenu);
}
}
});
return pagesMenu;
}

/**
* Recompute rendered menu items from loaded pages and current config.
*
* When a single item is produced, expose it as `$scope.page` for
* simplified template handling; otherwise keep list rendering mode.
*/
function rebuildMenu() {
if (!$scope.pages) {
return;
}

$scope.pagesMenu = [];
buildMenu($scope.pagesMenu, $scope.pages, $scope.pagesConfig);

if ($scope.pagesMenu.length === 1) {
$scope.page = $scope.pagesMenu[0];
$scope.isSubmenu = $scope.page.type === "submenu";
$scope.isExternalLink =
$scope.page.format === "LINK" ||
$scope.page.format === "EMAILLINK" ||
$scope.page.format === "HTMLPAGE";

if (
$scope.page.format === "EMAILLINK" &&
$scope.page.link &&
!$scope.page.link.startsWith("mailto:")
) {
$scope.page.link = "mailto:" + $scope.page.link;
}
} else {
$scope.page = null;
}
}

if ($scope.pagesConfig.length > 0) {
gnStaticPagesService.loadPages($scope.language, $scope.section).then(
function (response) {
Expand All @@ -149,28 +269,21 @@
$scope.pages[page.pageId] = page;
});

gnStaticPagesService.buildMenu(
$scope.pagesMenu,
$scope.pages,
$scope.pagesConfig
);
if ($scope.pagesMenu.length === 1) {
$scope.page = $scope.pagesMenu[0];
$scope.isSubmenu = $scope.page.type === "submenu";
$scope.isExternalLink =
$scope.page.format === "LINK" ||
$scope.page.format === "EMAILLINK" ||
$scope.page.format === "HTMLPAGE";

if ($scope.page.format === "EMAILLINK") {
$scope.page.link = "mailto:" + $scope.page.link;
}
}
rebuildMenu();
},
function (response) {
$scope.pagesList = null;
}
);

// Rebuild menu when any context field changes.
$scope.$watch(
"context",
function () {
rebuildMenu();
},
true
);
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,61 +39,8 @@
});
};

function buildMenu(pagesMenu, staticPages, pagesConfig) {
pagesConfig.forEach(function (menu) {
if (typeof menu === "string") {
if (staticPages[menu]) {
pagesMenu.push(staticPages[menu]);
} else {
console.warn(
menu +
" not found in pages configuration." +
" Check your UI configuration."
);
}
} else if (angular.isObject(menu)) {
var key = Object.keys(menu)[0];
var value = menu[key];

var submenu = {
label: key,
icon: undefined,
type: "submenu",
pages: []
};

var menuItems;

// If the submenu is using the legacy array format
if (angular.isArray(value)) {
menuItems = value;
// If the submenu is using the new object format with an items array and optional icon
} else if (angular.isObject(value)) {
if (angular.isArray(value.items)) {
menuItems = value.items;
}
if (angular.isDefined(value.icon)) {
submenu.icon = value.icon;
}
} else {
console.warn(
"Invalid menu configuration for " +
key +
". Expected an array of page identifiers or an object with an items array."
);
return;
}

buildMenu(submenu.pages, staticPages, menuItems);
pagesMenu.push(submenu);
}
});
return pagesMenu;
}

return {
loadPages: loadPages,
buildMenu: buildMenu
loadPages: loadPages
};
}
]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
<li
data-ng-class="{'dropdown': isSubmenu, 'btn-group': renderAsButton}"
role="menuitem"
data-ng-hide="isSubmenu && page.pages.length < 1"
>
<li data-ng-class="{'dropdown': isSubmenu, 'btn-group': renderAsButton}" role="menuitem">
<!-- Submenu dropdown toggle -->
<a
data-ng-if="isSubmenu"
Expand Down
Loading
Loading