Skip to content

Commit

Permalink
WIP for #1676
Browse files Browse the repository at this point in the history
  • Loading branch information
oharsta committed Mar 10, 2025
1 parent 6d854c2 commit dfa39f1
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 76 deletions.
9 changes: 9 additions & 0 deletions client/src/__tests__/utils/CSVParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,12 @@ cumulusgrp,admin,[email protected],301ee8e6-b5d1-40b5-a27e-47611f803371,1743
expect(results.data.length).toEqual(2);
expect(results.errors.length).toEqual(1);
});

test("parseWithDefaults", () => {
const csv = "ai_computing,,\"[email protected],[email protected]\",,,,,";
const results = parseBulkInvitation(csv);
expect(results.data.length).toEqual(1);
expect(results.errors.length).toEqual(0);
});


22 changes: 18 additions & 4 deletions client/src/components/TabularData.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,21 @@ import {isEmpty} from "../utils/Utils";
import {dateColumns, requiredColumns} from "../utils/CSVParser";
import {Tooltip} from "@surfnet/sds";

export default function TabularData({headers = [], data = [], errors = [], showRequiredInfo = true}) {
export default function TabularData({
headers = [],
data = [],
errors = [],
showRequiredInfo = true,
isResultView = false
}) {

const errorTranslation = (row, error) => {
const hasErrorTranslation = I18n.translations[I18n.locale].bulkUpload.errors[error.code];
return I18n.t(`bulkUpload.errors.${hasErrorTranslation ? error.code : "Unknown"}`, {
fields: requiredColumns.filter(field => isEmpty(row[field])).join(", "),
invitee: error.invitee,
shortName: error.shortName
shortName: error.shortName,
message: error.message
});
}

Expand All @@ -35,6 +42,13 @@ export default function TabularData({headers = [], data = [], errors = [], showR
return value || "";
}

const trClassName = (row, index) => {
const resultPart = isResultView ? "results" : "";
const errorPart = errors
.some(error => error.row === index && ((error.message || "").indexOf("existing") === -1 || isEmpty(row.invitees))) ? "error-row" : "";
return `${errorPart} ${resultPart}`
}

return (
<div className="tabular-data">
<table>
Expand All @@ -43,14 +57,14 @@ export default function TabularData({headers = [], data = [], errors = [], showR
{headers.map((header, index) =>
<th key={index} className={header}>
<span dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(displayHeader(header))}}/>
{showRequiredInfo && <Tooltip tip={I18n.t(`bulkUpload.tooltips.${header}`)}/> }
{showRequiredInfo && <Tooltip tip={I18n.t(`bulkUpload.tooltips.${header}`)}/>}
</th>
)}
</tr>
</thead>
<tbody>
{data.map((row, index) => <Fragment key={index}>
<tr className={`${errors.some(error => error.row === index) ? "error-row" : ""}`}>
<tr className={trClassName(row, index)}>
{headers.map((header, innerIndex) =>
<td key={innerIndex}
dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(displayValue(header, row[header]))}}/>
Expand Down
4 changes: 4 additions & 0 deletions client/src/components/TabularData.scss
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@
background-color: #f9f9f9;
}

tr.results:not(.error-row) td {
color: var(--sds--color--green--400);
}

tr.error-row td {
color: var(--sds--color--red--400);
}
Expand Down
11 changes: 9 additions & 2 deletions client/src/locale/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -2749,10 +2749,15 @@ const en = {
errorWrongExtension: "Only CSV files can be uploaded, not {{name}}",
errorFormat: "Error parsing file {{name}}",
successFullyParsed: "Successfully parsed {{fileName}}<br/> <strong>{{invitees}}</strong> invitees will be invited for <strong>{{collaborations}}</strong> collaborations in <strong>{{groups}}</strong> groups.",
errorParsed: "Error in parsing {{fileName}}. See the details below",
successFullyUploaded: "Successfully uploaded <strong>{{nbrInvitations}}</strong> invitations.",
errorParsed: "Error in parsing {{fileName}}. See the details below.",
errorUpload: "Error in uploading. See the results below.",
errorRows: "However there are some rows that will be excluded, because of invalid data. See details below.",
errorUploadDetails: "However there are errors returned from the server. See results below.",
showDetails: "Show details",
hideDetails: "Hide details",
showResults: "Show results",
hideResults: "Hide results",
schema: "Click the button below to download a sample CVS file.",
download: "Download",
exampleInfo: "Example CSV data",
Expand All @@ -2761,7 +2766,9 @@ const en = {
errors: {
TooFewFields: "The row above has missing values for required fields: {{fields}}",
Duplicate: "The row above has contains a duplicate entry for user {{invitee}} and collaboration {{shortName}}",
Unknown: "Invalid CSV row"
Unknown: "Invalid CSV row",
ServerError: "The server reported an error: {{message}}",
ServerWarning: "The server reported an warning: {{message}}"
},
tooltips: {
short_names: "The required comma separated and quoted short names of the collaborations for the invitation",
Expand Down
119 changes: 63 additions & 56 deletions client/src/locale/nl.js
Original file line number Diff line number Diff line change
Expand Up @@ -2697,81 +2697,88 @@ const nl = {
inviteWithEmailInfo: "Verstuur een uitnodiging naar éém of meerder e-mailadressen. Met de link in de e-mail kan een gebruiker direct lid worden.",
},
organisationDetails: {
details: "Organisation details",
details: "Organisatiedetails",
toc: {
about: "About the organisation",
units: "Units",
about: "Over de organisatie",
units: "Eenheden",
labels: "Labels",
messaging: "Messaging",
settings: "Settings"
messaging: "Berichten",
settings: "Instellingen"
},
headers: {
about: "About the organisation",
units: "Manage units",
labels: "Manage labels",
messaging: "Messaging settingss",
settings: "Organisation settings"
about: "Over de organisatie",
units: "Beheer eenheden",
labels: "Beheer labels",
messaging: "Berichtinstellingen",
settings: "Organisatie-instellingen"
},
units: {
info: "Create units to organize departments or projects within your organization. Managers can be assigned to specific units to oversee their activities.",
info: "Maak eenheden om afdelingen of projecten binnen je organisatie te organiseren. Managers kunnen worden toegewezen aan specifieke eenheden om hun activiteiten te beheren.",
},
labels: {
info: "Create labels to define overall properties for collaborations within your organisation. Labels are shared with the connected applications, helping you manage and organize your members.",
name: "Label name",
defaultFor: "Default for",
defaultForPlaceholder: "All co's within all units"
info: "Maak labels om algemene eigenschappen voor samenwerkingen binnen je organisatie te definiëren. Labels worden gedeeld met de gekoppelde applicaties en helpen bij het beheren en organiseren van je leden.",
name: "Labelnaam",
defaultFor: "Standaard voor",
defaultForPlaceholder: "Alle samenwerkingen binnen alle eenheden"
},
messaging: {
newCoMessage: "Message for new collaborations",
newCoMessageInfo: "This message is shown to users from your organisation when they request or create a collaboration",
defaultInviteMessage: "Default message for invites",
defaultInviteMessagePlaceholder: "Please join us, at this new CO",
defaultInviteMessageInfo: "When filled this message is used in all new invitations for the collaborations of this organisation",
defaultSenderName: "Default sender name for invites",
defaultSenderNamePlaceholder: "Organisational department of info mail",
defaultSenderNameInfo: "When filled this name is used as the sender in all new invitations for the collaborations of this organisation",
newCoMessage: "Bericht voor nieuwe samenwerkingen",
newCoMessageInfo: "Dit bericht wordt getoond aan gebruikers van je organisatie wanneer ze een samenwerking aanvragen of aanmaken.",
defaultInviteMessage: "Standaardbericht voor uitnodigingen",
defaultInviteMessagePlaceholder: "Sluit je bij ons aan in deze nieuwe samenwerking",
defaultInviteMessageInfo: "Wanneer ingevuld, wordt dit bericht gebruikt in alle nieuwe uitnodigingen voor de samenwerkingen van deze organisatie.",
defaultSenderName: "Standaard afzendernaam voor uitnodigingen",
defaultSenderNamePlaceholder: "Organisatieafdeling of informatiemail",
defaultSenderNameInfo: "Wanneer ingevuld, wordt deze naam gebruikt als afzender in alle nieuwe uitnodigingen voor de samenwerkingen van deze organisatie.",
},
permissions: "Permissions"
permissions: "Rechten"
},
tags: {
label: "Label name",
add: "+ Add label",
confirmation: "Are you sure you want to remove label {{name}}?",
duplicated: "There is already an label named {{name}} for this organisation"
label: "Labelnaam",
add: "+ Label toevoegen",
confirmation: "Weet je zeker dat je het label {{name}} wilt verwijderen?",
duplicated: "Er bestaat al een label genaamd {{name}} voor deze organisatie"
},
bulkUpload: {
title: "Upload your invitations",
title: "Upload je uitnodigingen",
breadcrumb: "bulk-upload",
main: "Upload",
docs: "Documentation",
dragDrop: "Drag and drop a CSV file or",
click: " click here to upload",
errorWrongExtension: "Only CSV files can be uploaded, not {{name}}",
errorFormat: "Error parsing file {{name}}",
successFullyParsed: "Successfully parsed {{fileName}}<br/> <strong>{{invitees}}</strong> invitees will be invited for <strong>{{collaborations}}</strong> collaborations in <strong>{{groups}}</strong> groups.",
errorParsed: "Error in parsing {{fileName}}. See the details below",
errorRows: "However there are some rows that will be excluded, because of missing required fields. See details below.",
showDetails: "Show details",
hideDetails: "Hide details",
schema: "Click the button below to download a sample CVS file.",
download: "Download",
exampleInfo: "Example CSV data",
requiredInfo: "indicates a required value",
proceed: "Upload & send invitations",
main: "Uploaden",
docs: "Documentatie",
dragDrop: "Sleep een CSV-bestand hierheen of",
click: " klik hier om te uploaden",
errorWrongExtension: "Alleen CSV-bestanden kunnen worden geüpload, niet {{name}}",
errorFormat: "Fout bij het verwerken van bestand {{name}}",
successFullyParsed: "Succesvol verwerkt {{fileName}}<br/> <strong>{{invitees}}</strong> genodigden worden uitgenodigd voor <strong>{{collaborations}}</strong> samenwerkingen in <strong>{{groups}}</strong> groepen.",
successFullyUploaded: "Succesvol <strong>{{nbrInvitations}}</strong> uitnodigingen geüpload.",
errorParsed: "Fout bij het verwerken van {{fileName}}. Zie de details hieronder.",
errorUpload: "Fout bij het uploaden. Zie de resultaten hieronder.",
errorRows: "Er zijn echter enkele rijen die worden uitgesloten vanwege ongeldige gegevens. Zie details hieronder.",
errorUploadDetails: "Er zijn echter fouten teruggestuurd door de server. Zie resultaten hieronder.",
showDetails: "Toon details",
hideDetails: "Verberg details",
showResults: "Toon resultaten",
hideResults: "Verberg resultaten",
schema: "Klik op de onderstaande knop om een voorbeeld-CSV-bestand te downloaden.",
download: "Downloaden",
exampleInfo: "Voorbeeld CSV-gegevens",
requiredInfo: "geeft een verplichte waarde aan",
proceed: "Uploaden & uitnodigingen verzenden",
errors: {
TooFewFields: "The row above has missing values for required fields: {{fields}}",
Duplicate: "The row above has contains a duplicate entry for user {{user}} and collaboration {{collaboration}}",
Unknown: "Invalid CSV row"
TooFewFields: "De bovenstaande rij mist waarden voor verplichte velden: {{fields}}",
Duplicate: "De bovenstaande rij bevat een dubbele invoer voor gebruiker {{invitee}} en samenwerking {{shortName}}",
Unknown: "Ongeldige CSV-rij",
ServerError: "De server heeft een fout gemeld: {{message}}",
ServerWarning: "De server heeft een waarschuwing gemeld: {{message}}"
},
tooltips: {
short_names: "The required comma separated and quoted short names of the collaborations for the invitation",
intended_role: "The optional intended role of the invitees. Two options: either member or admin, if omitted then defaults to member",
invitees: "Email adresses of the invitees of the invitation. If multiple then comma separated and double quoted",
groups: "The optional comma separated identifiers of the collaboration groups for the invitation",
invitation_expiry_date: "The optional expiry date of the invitation. Defaults to 30 days if not specified",
membership_expiry_date: "The optional expiry date of the membership. Defaults to None if not specified",
message: "The optional personal message to be included in the invitation. Defaults to None if not specified",
sender_name: "The optional name of the sender to be included in the invitation. Defaults to name of the current user if not specified"
short_names: "De verplichte, komma-gescheiden en tussen aanhalingstekens geplaatste korte namen van de samenwerkingen voor de uitnodiging",
intended_role: "De optionele beoogde rol van de genodigden. Twee opties: lid of beheerder. Indien weggelaten, wordt standaard lid geselecteerd.",
invitees: "E-mailadressen van de genodigden voor de uitnodiging. Indien meerdere, dan komma-gescheiden en tussen dubbele aanhalingstekens.",
groups: "De optionele, komma-gescheiden identificatoren van de samenwerkingsgroepen voor de uitnodiging",
invitation_expiry_date: "De optionele vervaldatum van de uitnodiging. Standaard 30 dagen indien niet opgegeven",
membership_expiry_date: "De optionele vervaldatum van het lidmaatschap. Standaard geen indien niet opgegeven",
message: "De optionele persoonlijke boodschap die in de uitnodiging wordt opgenomen. Standaard geen indien niet opgegeven",
sender_name: "De optionele naam van de afzender die in de uitnodiging wordt opgenomen. Standaard de naam van de huidige gebruiker indien niet opgegeven"
}
}
};
Expand Down
Loading

0 comments on commit dfa39f1

Please sign in to comment.