Skip to content

Commit

Permalink
fix(names, accessibility, collections, user-data): Infrastructure and…
Browse files Browse the repository at this point in the history
… cli command to customize users' name parts; a11y tweaks to detail page; visual tweaks to collection detail page; bug fix preventing user data service from picking up profile changes
  • Loading branch information
monotasker committed Dec 20, 2024
1 parent 81ac78a commit 0d2b2e3
Show file tree
Hide file tree
Showing 17 changed files with 327 additions and 19 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Knowledge Commons Works is a collaborative tool for storing and sharing academic research. It is part of Knowledge Commons and is built on an instance of the InvenioRDM repository system.

Version 0.3.2-beta5
Version 0.3.3-beta6

## Copyright

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { Component } from "react";
import { Button, Header, Icon, Segment } from "semantic-ui-react";
import { withState } from "react-searchkit";
import { i18next } from "@translations/invenio_communities/i18next";
import PropTypes from "prop-types";

const MembersEmptyResultsComponent = ({
resetQuery,
extraContent = null,
queryString,
currentQueryState,
currentResultsState,
}) => {
const isEmptyPageAfterSearch = currentQueryState.page < 0;
const isEmptyPage =
currentQueryState.page === 1 && currentResultsState.data.total === 0;

return (
<Segment placeholder textAlign="center">
<Header icon>
<Icon name={isEmptyPage ? "users" : "search"} />
{isEmptyPage && i18next.t("This collection has no public members.")}
{isEmptyPageAfterSearch && i18next.t("No matching members found.")}
</Header>
{queryString && (
<p>
<em>
{i18next.t("Current search")} "{queryString}"
</em>
</p>
)}
{isEmptyPageAfterSearch && (
<Button primary onClick={() => resetQuery()}>
{i18next.t("Clear query")}
</Button>
)}
{extraContent}
</Segment>
);
};

MembersEmptyResultsComponent.propTypes = {
resetQuery: PropTypes.func.isRequired,
queryString: PropTypes.string.isRequired,
currentQueryState: PropTypes.object.isRequired,
currentResultsState: PropTypes.object.isRequired,
extraContent: PropTypes.node,
};

const MembersEmptyResults = withState(MembersEmptyResultsComponent);

export { MembersEmptyResults };
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { CreatibutorsFieldItem } from "./creatibutors_components/CreatibutorsFie
import { CREATIBUTOR_TYPE } from "./types";
import { FormUIStateContext } from "@js/invenio_modular_deposit_form/InnerDepositForm";
import { i18next } from "@translations/invenio_rdm_records/i18next";
import { getFamilyName, getGivenName } from "../../../kcworks/names";

/**
* Sort a list of string values (options).
Expand Down Expand Up @@ -114,11 +115,15 @@ const makeSelfCreatibutor = (currentUserprofile) => {

let myNameParts = {};
if (
!!currentUserprofile?.name_parts &&
currentUserprofile?.name_parts !== ""
!!currentUserprofile?.name_parts_local &&
currentUserprofile?.name_parts_local !== ""
) {
myNameParts = JSON.parse(currentUserprofile.name_parts_local);
} else if (!!currentUserprofile?.name_parts && currentUserprofile?.name_parts !== "") {
myNameParts = JSON.parse(currentUserprofile.name_parts);
}
const part1 = [myNameParts?.given, myNameParts?.first, myNameParts?.middle, myNameParts?.nickname].filter(Boolean).join(" ");
const part2 = [myNameParts?.family_prefix, myNameParts?.family_prefix_fixed, myNameParts?.spousal, myNameParts?.parental, myNameParts?.family, myNameParts?.last, ].filter(Boolean).join(" ");

let myIdentifiers = undefined;
const rawIdentifiers = Object.fromEntries(
Expand All @@ -136,8 +141,14 @@ const makeSelfCreatibutor = (currentUserprofile) => {

let selfCreatibutor = {
person_or_org: {
family_name: myNameParts?.last || currentUserprofile?.full_name || "",
given_name: myNameParts?.first || "",
family_name:
getFamilyName(myNameParts) ||
currentUserprofile?.full_name ||
"",
given_name:
getGivenName(myNameParts) ||
myNameParts?.first ||
"",
name: currentUserprofile?.full_name || "",
type: "personal",
identifiers: myIdentifiers?.length > 0 ? myIdentifiers : [],
Expand Down
4 changes: 4 additions & 0 deletions assets/js/invenio_app_rdm/overridableRegistry/mapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { InvitationResultItemWithConfig } from "./collections/invitations/Invita
import { LicenseField } from "./fields/LicenseField";
import { LogoUploader } from "./collections/settings/profile/LogoUploader";
import { ManagerMembersResultItemWithConfig } from "./collections/members/manager_view/ManagerMembersResultItem";
import { MembersEmptyResults } from "./collections/members/components/MembersEmptyResults";
import { MembersSearchBarElement } from "./collections/members/components/MembersSearchBarElement";
import { MetadataOnlyToggle } from "./fields/MetadataOnlyToggle";
import Pagination from "./search/Pagination";
Expand Down Expand Up @@ -120,12 +121,15 @@ export const overriddenComponents = {
"InvenioCommunities.RequestSearch.ResultsList.item": RequestsResultsItemTemplateWithCommunity,
"InvenioCommunities.RequestSearch.SearchApp.layout": CommunityRequestsSearchLayoutWithApp,
"InvenioCommunities.InvitationsSearch.ResultsList.item": InvitationResultItemWithConfig,
"InvenioCommunities.ManagerSearch.EmptyResults.element": MembersEmptyResults,
"InvenioCommunities.ManagerSearch.ResultsList.item": ManagerMembersResultItemWithConfig,
"InvenioCommunities.ManagerSearch.SearchBar.element": MembersSearchBarElement,
"InvenioCommunities.MemberSearch.ResultsList.item": ManagerMembersResultItemWithConfig,
"InvenioCommunities.MemberSearch.EmptyResults.element": MembersEmptyResults,
"InvenioCommunities.MemberSearch.SearchBar.element": MembersSearchBarElement,
"InvenioCommunities.PublicSearch.ResultsList.item": PublicMembersResultsItemWithCommunity,
"InvenioCommunities.PublicSearch.SearchBar.element": MembersSearchBarElement,
"InvenioCommunities.PublicSearch.EmptyResults.element": MembersEmptyResults,
"InvenioModularDetailPage.MobileActionMenu.container": MobileActionMenu,
// "InvenioAppRdm.Deposit.ResourceTypeField.container": ResourceTypeField
// InvenioCommunities.Search.SearchApp.layout: CommunityRecordsSearchAppLayout,
Expand Down
2 changes: 1 addition & 1 deletion assets/less/site/collections/grid.overrides
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
width: 1.5rem;
height: 1.5rem;
background-color: @white;
padding-left: 1px;
padding-left: 1.5px;
padding-bottom: 2px;
}
}
Expand Down
1 change: 1 addition & 0 deletions invenio.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5744,6 +5744,7 @@ class CustomUserProfileSchema(Schema):
full_name = fields.String()
affiliations = fields.String()
name_parts = fields.String()
name_parts_local = fields.String()
identifier_email = fields.String()
identifier_orcid = fields.String()
identifier_kc_username = fields.String()
Expand Down
17 changes: 17 additions & 0 deletions site/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@

# Changes

## 0.3.3-beta6 (2024-12-18)

- Names
- Added the infrastructure to customize the division of users' names into parts so that it can be divided as desired when, e.g., the user's name is being auto-filled in the name fields of the upload form. This involves
- a new "name_parts_local" field to the user profile schema. This field contains the user's name parts if they have been modified within the KCWorks system. This is sometimes necessary when the user data synced from the remote user data service does not divide the user's name correctly.
- a cli command to update the user's name parts.
- a new "names" js module that contains functions to get the user's full name, full name in inverted order, family name, and given name from the user's name parts.
- updates to the CreatibutorsField component to use the new "names" js module and the customized name parts if they are present in a user's profile.
- Detail page
- Added missing aria-label properties for accessibility
- Collections
- Fixed wording of empty results message for collection members search
- Previously, the empty results message used "community" instead of "collection".
- Tweaks to layout of collection detail page header
- Remote user data service
- Fixed bug where user profile data was not being updated because comparison with initial data was not being made correctly. This means that, among other things, ORCID ids will now be added correctly when the user chooses "add self" on the upload form.

## 0.3.2-beta5 (2024-12-11)

- Added Bluesky sharing option to detail page
Expand Down
2 changes: 1 addition & 1 deletion site/kcworks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@

"""KCWorks customizations to InvenioRDM."""

__version__ = "0.3.2-beta5"
__version__ = "0.3.3-beta6"
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const CommunityRecordsSearchAppLayout = ({ config, appName }) => {
aria-label={i18next.t("Filter results")}
/>
</Grid.Column>
<Grid.Column mobile={10} tablet={8} computer={8}>
<Grid.Column mobile={10} tablet={6} computer={4}>
<Sort
values={config.sortOptions}
label={(cmp) => (
Expand All @@ -45,7 +45,7 @@ export const CommunityRecordsSearchAppLayout = ({ config, appName }) => {
)}
/>
</Grid.Column>
<Grid.Column width={4} tablet={7} computer={4} mobile={4} textAlign="right">
<Grid.Column width={4} tablet={7} computer={8} mobile={6} textAlign="right">
<Count
label={(cmp) => (
<Trans key="communityRecordsSearch" count={cmp}>
Expand Down
55 changes: 55 additions & 0 deletions site/kcworks/assets/semantic-ui/js/kcworks/names.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
function getFullName(nameParts) {
let fullName = [
getGivenName(nameParts),
nameParts?.family_prefix,
getFamilyName(nameParts),
]
.filter(Boolean)
.join(" ");
if (nameParts?.suffix) {
fullName += ", " + nameParts?.suffix;
}
return fullName;
}

function getFullNameInverted(nameParts) {
const beforeComma = [
getFamilyName(nameParts),
]
const afterComma = [
getGivenName(nameParts),
nameParts?.family_prefix,
]
.filter(Boolean)
.join(" ");
let fullNameInverted = `${beforeComma}, ${afterComma}`;
if (nameParts?.suffix) {
fullNameInverted += ", " + nameParts?.suffix;
}
return fullNameInverted;
}

function getFamilyName(nameParts) {
return [
nameParts?.family_prefix_fixed,
nameParts?.parental,
nameParts?.spousal,
nameParts?.family,
nameParts?.last,
]
.filter(Boolean)
.join(" ");
}

function getGivenName(nameParts) {
return [
nameParts?.given,
nameParts?.first,
nameParts?.middle,
nameParts?.nickname,
]
.filter(Boolean)
.join(" ");
}

export { getFullName, getFullNameInverted, getFamilyName, getGivenName };
19 changes: 15 additions & 4 deletions site/kcworks/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
from kcworks.services.search.indices import delete_index
import sys

from kcworks.services.users.cli import name_parts as name_parts_command

UNMANAGED_INDICES = [
"kcworks-stats-record-view",
"kcworks-stats-file-download",
Expand All @@ -37,12 +39,21 @@


@click.group()
def index():
"""Utility commands for search index management."""
def kcworks_users():
"""Utility commands for Knowledge Commons Works."""
pass


kcworks_users.add_command(name_parts_command)


@click.group()
def kcworks_index():
"""KCWorks utility commands for search index management."""
pass


@index.command("destroy-indices")
@kcworks_index.command("destroy-indices")
@click.option(
"--yes-i-know",
is_flag=True,
Expand All @@ -53,7 +64,7 @@ def index():
@click.option("--force", is_flag=True, default=False)
@with_appcontext
@search_version_check
def destroy(force):
def destroy_indices(force):
"""Destroy all indices that are not destroyed by invenio_search
THIS COMMAND WILL WIPE ALL DATA ON USAGE STATS. ONLY RUN THIS WHEN YOU KNOW
Expand Down
Loading

0 comments on commit 0d2b2e3

Please sign in to comment.