diff --git a/docs/usage/search-results/layouts/details-list.md b/docs/usage/search-results/layouts/details-list.md index 05a83889..426b75e9 100644 --- a/docs/usage/search-results/layouts/details-list.md +++ b/docs/usage/search-results/layouts/details-list.md @@ -7,6 +7,6 @@ The 'details list' layout allows you to display items as a structured list, the | **Manage columns** | Allows you to build you own table view by adding or removing columns dynamically. For each column, you get the following options:

[!["Manage columns"](../../../assets/webparts/search-results/layouts/details_list_fields.png)](../../../assets/webparts/search-results/layouts/details_list_fields.png)

| **Show file icon** | Hide or display the file icon in the first column. | **Compact mode** | Display the details list in compact mode. -| **Enable grouping** | Display a grouped list, grouped by the specified column. +| **Enable grouping** | Display a grouped list, grouped by the specified column. You may also specify a list of additional columns to group by in a hierarchy of groups. | **Enable sticky header** | Display the details list with a sticky header that will stay in place when scrolling. Specify the desired height for the view (in pixels) and then specify the desired items per page in _Number of items per page_ under _Paging options_ and all items on the page will be scrollable within the view. | **Enable download** | Enable download of selected files. Requires _Allow items selection_ to be enabled and supports both single and multiple selection. If single selection is enabled the selected file will be downloaded as is. If multiple selection is enabled the selected files and folders will be downloaded in a single zip file like in SharePoint document libraries. Requires _SPWebUrl_, _ContentTypeId_, _NormListID_ and _NormUniqueID_ to be selected in _Selected properties_. \ No newline at end of file diff --git a/search-parts/src/components/DetailsListComponent.tsx b/search-parts/src/components/DetailsListComponent.tsx index 15202093..ef4d84fe 100644 --- a/search-parts/src/components/DetailsListComponent.tsx +++ b/search-parts/src/components/DetailsListComponent.tsx @@ -157,6 +157,11 @@ export interface IDetailsListComponentProps { */ groupBy?: string; + /** + * Additional fields to group items in the list + */ + additionalGroupBy?: IDetailsListColumnConfiguration[]; + /** * Show groups as collapsed by default if true. Expanded otherwise */ @@ -260,7 +265,15 @@ export class DetailsListComponent extends React.Component field.value) : []; + this._allItems = sortBy(this.props.items, [this.props.groupBy, ...additionalGroupBy]); + } + else { + this._allItems = this.props.items ? this.props.items : []; + } if (!isEmpty(this.props.context)) { @@ -479,15 +492,10 @@ export class DetailsListComponent extends React.Component field.value) : []; + const groups = this._buildGroups(this.state.items, [this.props.groupBy, ...additionalGroupBy], 0, 0); - // Because groups are determined by a start index and a count, we need to sort items to regroup them in the collection before processing. - const items = sortBy(this.state.items, this.props.groupBy); - const groups = this._buildGroups(items, this.props.groupBy); - - this.setState({ - groups: groups, - items: items - }); + this.setState({groups: groups}); } // Manually select the items in the list @@ -668,10 +676,10 @@ export class DetailsListComponent extends React.Component { - return ObjectHelper.byPath(i, groupByField); + return ObjectHelper.byPath(i, groupByFields[level]); }); let groups: IGroup[] = []; @@ -683,18 +691,22 @@ export class DetailsListComponent extends React.Component { + return this.props.selectedKeys.includes(value.key); + }), + level: level, + children: level < groupByFields.length - 1 ? this._buildGroups(groupedItems[group], groupByFields, level + 1, currentIndex + idx) : [] }; groups.push(groupProps); diff --git a/search-parts/src/layouts/results/detailsList/DetailListLayout.ts b/search-parts/src/layouts/results/detailsList/DetailListLayout.ts index 4f1cf27a..6e9487d4 100644 --- a/search-parts/src/layouts/results/detailsList/DetailListLayout.ts +++ b/search-parts/src/layouts/results/detailsList/DetailListLayout.ts @@ -8,6 +8,7 @@ import { TemplateValueFieldEditor, ITemplateValueFieldEditorProps } from '../../ import { AsyncCombo } from "../../../controls/PropertyPaneAsyncCombo/components/AsyncCombo"; import { IAsyncComboProps } from "../../../controls/PropertyPaneAsyncCombo/components/IAsyncComboProps"; import { PropertyFieldNumber } from "@pnp/spfx-property-controls/lib/PropertyFieldNumber"; +import commonStyles from './DetailsListLayout.module.scss'; /** * Details List Builtin Layout @@ -44,6 +45,11 @@ export interface IDetailsListLayoutProperties { */ groupByField: string; + /** + * Additional fields to group items in the list + */ + additionalGroupByFields: IDetailsListColumnConfiguration[]; + /** * If groups should collapsed by default */ @@ -116,6 +122,7 @@ export class DetailsListLayout extends BaseLayout this.properties.fieldIconExtension = this.properties.fieldIconExtension ? this.properties.fieldIconExtension : 'FileType'; this.properties.enableGrouping = this.properties.enableGrouping !== null && this.properties.enableGrouping !== undefined ? this.properties.enableGrouping : false; this.properties.groupByField = this.properties.groupByField ? this.properties.groupByField : ''; + this.properties.additionalGroupByFields = this.properties.additionalGroupByFields ? this.properties.additionalGroupByFields : []; this.properties.groupsCollapsed = this.properties.groupsCollapsed !== null && this.properties.groupsCollapsed !== undefined ? this.properties.groupsCollapsed : true; const { PropertyFieldCollectionData, CustomCollectionFieldType } = await import( @@ -312,7 +319,38 @@ export class DetailsListLayout extends BaseLayout description: `${strings.Layouts.DetailsList.GroupingDescription}`, key: 'queryText' }), - PropertyPaneToggle('layoutProperties.groupsCollapsed', { + this._propertyFieldCollectionData('layoutProperties.additionalGroupByFields', { + manageBtnLabel: strings.Layouts.DetailsList.AdditionalGroupByButtonLabel, + key: 'layoutProperties.additionalGroupByFields', + panelHeader: strings.Layouts.DetailsList.AdditionalGroupByFieldsLabel, + panelDescription: strings.Layouts.DetailsList.AdditionalGroupByFieldsDescription, + enableSorting: true, + tableClassName: commonStyles.additionalGroupByFieldsTable, + label: strings.Layouts.DetailsList.AdditionalGroupByFieldsLabel, + value: this.properties.additionalGroupByFields, + disabled: !this.properties.enableGrouping || !this.properties.groupByField || this.properties.groupByField.length === 0, + fields: [ + { + id: 'value', + title: strings.Layouts.DetailsList.ValueColumnLabel, + type: this._customCollectionFieldType.custom, + required: true, + onCustomRender: (field, value, onUpdate, item, itemId, onCustomFieldValidation) => { + return React.createElement("div", { key: `${field.id}-${itemId}` }, + React.createElement(TemplateValueFieldEditor, { + currentItem: item, + field: field, + useHandlebarsExpr: false, + onUpdate: onUpdate, + value: value, + availableProperties: availableOptions, + } as ITemplateValueFieldEditorProps) + ); + } + }, + ] + }), + PropertyPaneToggle('layoutProperties.groupsCollapsed', { label: strings.Layouts.DetailsList.CollapsedGroupsByDefault, checked: this.properties.groupsCollapsed }) @@ -353,6 +391,7 @@ export class DetailsListLayout extends BaseLayout if (propertyPath.localeCompare('layoutProperties.enableGrouping') === 0) { this.properties.groupByField = ''; + this.properties.additionalGroupByFields = []; } if (propertyPath.localeCompare('layoutProperties.enableStickyHeader') === 0) { diff --git a/search-parts/src/layouts/results/detailsList/DetailsListLayout.module.scss b/search-parts/src/layouts/results/detailsList/DetailsListLayout.module.scss new file mode 100644 index 00000000..447faf1f --- /dev/null +++ b/search-parts/src/layouts/results/detailsList/DetailsListLayout.module.scss @@ -0,0 +1,21 @@ +.additionalGroupByFieldsTable { + table-layout: fixed; + + > div { + > span:nth-child(1) { + width: 50px; + } + + > span:nth-child(2) { + width: 350px; + } + + > span:nth-child(3) { + text-align: end; + } + + > span:nth-child(4) { + width: 20px; + } + } +} diff --git a/search-parts/src/layouts/results/detailsList/details-list.html b/search-parts/src/layouts/results/detailsList/details-list.html index 78948166..d107562c 100644 --- a/search-parts/src/layouts/results/detailsList/details-list.html +++ b/search-parts/src/layouts/results/detailsList/details-list.html @@ -66,6 +66,7 @@ data-is-container-field="{{@root.slots.IsFolder}}" data-is-compact="{{properties.layoutProperties.isCompact}}" data-group-by="{{properties.layoutProperties.groupByField}}" + data-additional-group-by="{{JSONstringify properties.layoutProperties.additionalGroupByFields}}" data-groups-collapsed="{{properties.layoutProperties.groupsCollapsed}}" data-context="{{JSONstringify (truncateContext @root)}}" data-instance-id="{{@root.instanceId}}" diff --git a/search-parts/src/loc/commonStrings.d.ts b/search-parts/src/loc/commonStrings.d.ts index 49f9bb2e..d1fc9ca7 100644 --- a/search-parts/src/loc/commonStrings.d.ts +++ b/search-parts/src/loc/commonStrings.d.ts @@ -225,6 +225,9 @@ declare interface ICommonStrings { ValueSortingColumnNoFieldsLabel: string; FileExtensionFieldLabel: string; GroupByFieldLabel: string; + AdditionalGroupByButtonLabel: string; + AdditionalGroupByFieldsLabel: string; + AdditionalGroupByFieldsDescription: string; GroupingDescription: string; EnableGrouping: string; CollapsedGroupsByDefault: string; diff --git a/search-parts/src/loc/da-dk.js b/search-parts/src/loc/da-dk.js index ed2fd2e2..5f9924d5 100644 --- a/search-parts/src/loc/da-dk.js +++ b/search-parts/src/loc/da-dk.js @@ -226,6 +226,9 @@ define([], function() { DisplayNameColumnLabel: "Kolonnens visningsnavn", FileExtensionFieldLabel: "Felt til brug af file extension", GroupByFieldLabel: "Gruppér efter felt", + AdditionalGroupByButtonLabel: "Tilføj felt", + AdditionalGroupByFieldsLabel: "Yderligere grupperingsfelter", + AdditionalGroupByFieldsDescription: "Tilføj yderligere grupperingsfelter for at skabe et hierarki i layoutet. Hver kolonne tilføjes i den viste rækkefølge.", EnableGrouping: "Aktivér gruppering", GroupingDescription: "Sørg for, at du har data vist i resultatwebdelen for at få vist en liste over egenskaber.", CollapsedGroupsByDefault: "Vis collapsed", diff --git a/search-parts/src/loc/de-de.js b/search-parts/src/loc/de-de.js index f02d7ca8..e7d6a0dd 100644 --- a/search-parts/src/loc/de-de.js +++ b/search-parts/src/loc/de-de.js @@ -226,6 +226,9 @@ define([], function () { DisplayNameColumnLabel: "Spaltenanzeigename", FileExtensionFieldLabel: "Zu verwendendes Feld für die Dateierweiterung", GroupByFieldLabel: "Gruppierung nach Feld", + AdditionalGroupByButtonLabel: "Weitere Gruppierung hinzufügen", + AdditionalGroupByFieldsLabel: "Zusätzliche Gruppierungsfelder", + AdditionalGroupByFieldsDescription: "Fügen Sie zusätzliche Gruppierungsfelder hinzu, um die Gruppierungsebene zu erhöhen. Die Reihenfolge der Gruppierungsfelder entspricht der Reihenfolge der Gruppierungsebenen.", EnableGrouping: "Gruppierung aktivieren", GroupingDescription: "Stellen Sie sicher, dass im Ergebnis-Webpart Daten angezeigt werden, damit eine Liste der anzuzeigenden Eigenschaften angezeigt wird.", CollapsedGroupsByDefault: "Eingeklappt anzeigen", diff --git a/search-parts/src/loc/en-us.js b/search-parts/src/loc/en-us.js index cfc51010..c0fb7e32 100644 --- a/search-parts/src/loc/en-us.js +++ b/search-parts/src/loc/en-us.js @@ -226,6 +226,9 @@ define([], function() { DisplayNameColumnLabel: "Column display name", FileExtensionFieldLabel: "Field to use for file extension", GroupByFieldLabel: "Group by field", + AdditionalGroupByButtonLabel: "Add group by field", + AdditionalGroupByFieldsLabel: "Additional group by fields", + AdditionalGroupByFieldsDescription: "Add additional grouping fields to create a hierarchy in the layout. Each column is added in the order shown.", EnableGrouping: "Enable grouping", GroupingDescription: "Ensure you have data showing in the result web part for a list of properties to show.", CollapsedGroupsByDefault: "Show collapsed", diff --git a/search-parts/src/loc/es-es.js b/search-parts/src/loc/es-es.js index 2a3e433a..e77c27a5 100644 --- a/search-parts/src/loc/es-es.js +++ b/search-parts/src/loc/es-es.js @@ -226,6 +226,9 @@ define([], function() { DisplayNameColumnLabel: "Nombre de la columna", FileExtensionFieldLabel: "Campo a utilizar para la extensión del archivo", GroupByFieldLabel: "Agrupar por campo", + AdditionalGroupByButtonLabel: "Añadir campo de agrupación adicional", + AdditionalGroupByFieldsLabel: "Campos de agrupación adicionales", + AdditionalGroupByFieldsDescription: "Agregue campos de agrupación adicionales para crear una jerarquía en el diseño. Cada columna se agrega en el orden que se muestra.", EnableGrouping: "Activar la agrupación", GroupingDescription: "Asegúrese de tener datos que se muestren en el elemento web de resultados para que se muestre una lista de propiedades.", CollapsedGroupsByDefault: "Mostrar colapsado", diff --git a/search-parts/src/loc/fi-fi.js b/search-parts/src/loc/fi-fi.js index e17e610b..e340ae2a 100644 --- a/search-parts/src/loc/fi-fi.js +++ b/search-parts/src/loc/fi-fi.js @@ -224,6 +224,9 @@ define([], function() { DisplayNameColumnLabel: "Sarakkeen näyttönimi", FileExtensionFieldLabel: "Kenttä tiedostotyypin määrittämiseen", GroupByFieldLabel: "Ryhmittele kentän mukaan", + AdditionalGroupByButtonLabel: "Lisää ryhmittelykenttä", + AdditionalGroupByFieldsLabel: "Lisää ryhmittelykenttä", + AdditionalGroupByFieldsDescription: "Lisää ryhmittelykenttiä luodaksesi hierarkian asetteluun. Jokainen sarake lisätään näytetyssä järjestyksessä.", EnableGrouping: "Salli ryhmittely", GroupingDescription: "Varmista, että tulosten verkko-osassa on tietoja, jotta voit näyttää ominaisuusluettelon.", CollapsedGroupsByDefault: "Näytä ryhmät tiivistettynä", diff --git a/search-parts/src/loc/fr-fr.js b/search-parts/src/loc/fr-fr.js index 4485b62b..735b294e 100644 --- a/search-parts/src/loc/fr-fr.js +++ b/search-parts/src/loc/fr-fr.js @@ -226,6 +226,9 @@ define([], function() { ValueSortingColumnNoFieldsLabel: "Aucune propriété disponible", FileExtensionFieldLabel: "Champ à utiliser pour l’extension de fichier", GroupByFieldLabel: "Regrouper par champ", + AdditionalGroupByButtonLabel: "Ajouter un champ de regroupement supplémentaire", + AdditionalGroupByFieldsLabel: "Champs de regroupement supplémentaires", + AdditionalGroupByFieldsDescription: "Ajoutez des champs de regroupement supplémentaires pour créer une hiérarchie dans la mise en page. Chaque colonne est ajoutée dans l'ordre indiqué.", EnableGrouping: "Permettre le regroupement", GroupingDescription: "Assurez-vous que les données s'affichent dans le composant WebPart de résultat pour obtenir une liste des propriétés à afficher.", CollapsedGroupsByDefault: "Afficher les groupes réduits", diff --git a/search-parts/src/loc/nb-no.js b/search-parts/src/loc/nb-no.js index a74c6415..256207d4 100644 --- a/search-parts/src/loc/nb-no.js +++ b/search-parts/src/loc/nb-no.js @@ -223,8 +223,11 @@ define([], function () { ValueColumnLabel: "Kolonneverdi", ValueSortingColumnLabel: "Velg sorteringsfelt...", ValueSortingColumnNoFieldsLabel: "Ingen felt tilgjengelig", - FileExtensionFieldLabel: "Felt för filendelse", + FileExtensionFieldLabel: "Felt for filendelse", GroupByFieldLabel: "Grupper etter felt", + AdditionalGroupByButtonLabel: "Legg til felt", + AdditionalGroupByFieldsLabel: "Ytterligere grupperingsfelt", + AdditionalGroupByFieldsDescription: "Legg til flere grupperingsfelt for å lage et hierarki i oppsettet. Hver kolonne legges til i den viste rekkefølgen.", EnableGrouping: "Aktiver gruppering", GroupingDescription: "Sørg for at du har data som vises i resultatwebdelen for å vise en liste over egenskaper.", CollapsedGroupsByDefault: "Vis kollapsede", diff --git a/search-parts/src/loc/nl-nl.js b/search-parts/src/loc/nl-nl.js index 421daaab..d0e8a322 100644 --- a/search-parts/src/loc/nl-nl.js +++ b/search-parts/src/loc/nl-nl.js @@ -225,6 +225,9 @@ define([], function() { ValueSortingColumnNoFieldsLabel: "Geen velden beschikbaar", FileExtensionFieldLabel: "Te gebruiken veld voor bestandsextensie", GroupByFieldLabel: "Groepeer op veld", + AdditionalGroupByButtonLabel: "Voeg groep toe", + AdditionalGroupByFieldsLabel: "Extra groeperingsvelden", + AdditionalGroupByFieldsDescription: "Hier kunt u extra groepen toevoegen om op te groeperen. U kunt eigenschapswaarden direct in de lij", EnableGrouping: "Groeperen inschakelen", GroupingDescription: "Zorg ervoor dat er gegevens worden weergegeven in het resultaatwebonderdeel voor een lijst met eigenschappen die moeten worden weergegeven.", CollapsedGroupsByDefault: "Toon ingeklapt", diff --git a/search-parts/src/loc/pl-pl.js b/search-parts/src/loc/pl-pl.js index 01a2d4c9..522c10fb 100644 --- a/search-parts/src/loc/pl-pl.js +++ b/search-parts/src/loc/pl-pl.js @@ -226,6 +226,9 @@ define([], function() { DisplayNameColumnLabel: "Nazwa wyświetlana kolumny", FileExtensionFieldLabel: "Pole używane dla rozszerzenia pliku", GroupByFieldLabel: "Grupuj po polu", + AdditionalGroupByButtonLabel: "Dodaj grupowanie", + AdditionalGroupByFieldsLabel: "Dodatkowe pola grupowania", + AdditionalGroupByFieldsDescription: "Dodaj dodatkowe pola grupujące, aby utworzyć hierarchię w układzie. Każda kolumna jest dodawana w pokazanej kolejności.", EnableGrouping: "Grupowanie włączone", GroupingDescription: "Upewnij się, że dane są wyświetlane w wynikowym składniku Web Part, aby wyświetlić listę właściwości.", CollapsedGroupsByDefault: "Pokaż zapadnięte", diff --git a/search-parts/src/loc/pt-br.js b/search-parts/src/loc/pt-br.js index 00c37f2a..025d174f 100644 --- a/search-parts/src/loc/pt-br.js +++ b/search-parts/src/loc/pt-br.js @@ -224,6 +224,9 @@ define([], function() { DisplayNameColumnLabel: "Nome de exibição da coluna", FileExtensionFieldLabel: "Campo usado para a extensão do arquivo", GroupByFieldLabel: "Agrupar pelo campo", + AdditionalGroupByButtonLabel: "Adicionar campo de agrupamento", + AdditionalGroupByFieldsLabel: "Campos de agrupamento adicionais", + AdditionalGroupByFieldsDescription: "Adicione campos de agrupamento adicionais para criar uma hierarquia no layout. Cada coluna é adicionada na ordem mostrada.", EnableGrouping: "Ativar agrupamento", GroupingDescription: "Certifique-se de que os dados sejam exibidos na Web Part de resultado para uma lista de propriedades a serem exibidas.", CollapsedGroupsByDefault: "Mostrar recolhido", diff --git a/search-parts/src/loc/sv-SE.js b/search-parts/src/loc/sv-SE.js index 20dab922..6e042396 100644 --- a/search-parts/src/loc/sv-SE.js +++ b/search-parts/src/loc/sv-SE.js @@ -226,6 +226,9 @@ define([], function () { DisplayNameColumnLabel: "Kolumnens visningsnamn", FileExtensionFieldLabel: "Fält för användning av filtillägg", GroupByFieldLabel: "Gruppera efter fält", + AdditionalGroupByButtonLabel: "Hantera grupperingsfält", + AdditionalGroupByFieldsLabel: "Ytterligare fält för gruppering", + AdditionalGroupByFieldsDescription: "Lägg till ytterligare grupperingsfält för att skapa en hierarki i layouten. Varje kolumn läggs till i ordningen som visas.", EnableGrouping: "Aktivera gruppering", GroupingDescription: "Se till att du har data som visas i resultatwebbdelen för en lista över egenskaper att visa.", CollapsedGroupsByDefault: "Visa kollapsade",