@pnp/spfx-property-controls
Version:
Reusable property pane controls for SharePoint Framework solutions
367 lines • 16.4 kB
JavaScript
import { __awaiter } from "tslib";
import { TermStorePickerServiceHelper } from "./ISPTermStorePickerService";
import { SPHttpClient } from "@microsoft/sp-http";
/**
* Term Store Picker Service implementation that uses SharePoint REST API for taxonomy
* This replaces the old @pnp/sp-taxonomy which is no longer available in PnPjs v4
*/
export default class PnPTermStorePickerService {
constructor(props, context) {
this.props = props;
this._termSetCollectionObjectType = 'SP.Taxonomy.TermSetCollection';
this._termGroupCollectionObjectType = 'SP.Taxonomy.TermGroupCollection';
this._groups = {};
// No initialization needed - we use SPHttpClient from context
this.context = context;
}
/**
* Makes a request to the taxonomy REST API
* @param endpoint - The endpoint path after /v2.1/_api/
*/
_taxonomyRequest(endpoint) {
return __awaiter(this, void 0, void 0, function* () {
const url = `${this.context.pageContext.web.absoluteUrl}/_api/v2.1/${endpoint}`;
const response = yield this.context.spHttpClient.get(url, SPHttpClient.configurations.v1);
if (!response.ok) {
throw new Error(`Taxonomy API request failed: ${response.statusText}`);
}
return response.json();
});
}
/**
* Gets term stores from the taxonomy service
*/
getTermStores() {
return __awaiter(this, void 0, void 0, function* () {
yield this._ensureTermStores();
return this._termStores;
});
}
/**
* Searches terms by provided text
* @param searchText text to search
*/
searchTermsByName(searchText) {
return __awaiter(this, void 0, void 0, function* () {
if (this.props.limitByTermsetNameOrID) {
return this._searchTermsByTermSet(searchText);
}
else if (this.props.limitByGroupNameOrID) {
return this._searchTermsByGroup(searchText);
}
else {
return this._searchAllTerms(searchText);
}
});
}
/**
* Gets term sets from the stores
*/
getTermSets() {
return __awaiter(this, void 0, void 0, function* () {
yield this._ensureTermStores();
let termSets = [];
for (const termStore of this._termStores) {
const groups = this._groups[termStore.Id];
for (const group of groups) {
if (this.props.limitByTermsetNameOrID) {
// Filter to specific term set
const filteredTermSets = group.TermSets._Child_Items_.filter(ts => ts.Name === this.props.limitByTermsetNameOrID ||
ts.Id.toLowerCase() === this.props.limitByTermsetNameOrID.toLowerCase());
termSets = [...termSets, ...filteredTermSets];
}
else {
termSets = [...termSets, ...group.TermSets._Child_Items_];
}
}
}
return termSets;
});
}
/**
* Gets all terms from the specified term set
* @param termSet Term Set to get terms from
*/
getAllTerms(termSet) {
return __awaiter(this, void 0, void 0, function* () {
yield this._ensureTermStores();
try {
// Use the new taxonomy REST API to get terms
const response = yield this._taxonomyRequest(`termStore/sets/${termSet.Id}/terms?$expand=children`);
const resultTerms = [];
// Recursively process terms to build flat list with paths
const processTerms = (terms, parentPath = '', depth = 1) => {
for (const taxonomyTerm of terms) {
const termName = this._getDefaultLabel(taxonomyTerm);
const pathOfTerm = parentPath ? `${parentPath};${termName}` : termName;
const term = {
_ObjectType_: 'SP.Taxonomy.Term',
_ObjectIdentity_: taxonomyTerm.id,
Id: taxonomyTerm.id,
Name: termName,
Description: this._getDescription(taxonomyTerm),
IsDeprecated: taxonomyTerm.isDeprecated || false,
IsAvailableForTagging: taxonomyTerm.isAvailableForTagging !== false,
IsRoot: depth === 1,
PathOfTerm: pathOfTerm,
PathDepth: depth,
TermSet: {
_ObjectType_: 'SP.Taxonomy.TermSet',
_ObjectIdentity_: termSet.Id,
Id: termSet.Id,
Name: termSet.Name
}
};
if (this.props.includeLabels) {
term.Labels = taxonomyTerm.labels.map(l => l.name);
}
resultTerms.push(term);
// Process children recursively
if (taxonomyTerm.children && taxonomyTerm.children.length > 0) {
processTerms(taxonomyTerm.children, pathOfTerm, depth + 1);
}
}
};
processTerms(response.value);
return TermStorePickerServiceHelper.sortTerms(resultTerms);
}
catch (error) {
console.error('Error loading terms', error);
return [];
}
});
}
/**
* Get term sets from the specified group
* @param group Term Group
*/
getGroupTermSets(group) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
yield this._ensureTermStores();
const groupData = (_b = this._groups[((_a = group.TermStore) === null || _a === void 0 ? void 0 : _a.Id) || this._termStoreId]) === null || _b === void 0 ? void 0 : _b.find(g => g.Id === group.Id);
if (!groupData) {
return {
_ObjectType_: this._termSetCollectionObjectType,
_Child_Items_: []
};
}
let termSets = groupData.TermSets._Child_Items_;
if (this.props.limitByTermsetNameOrID) {
termSets = termSets.filter(ts => ts.Name === this.props.limitByTermsetNameOrID ||
ts.Id.toLowerCase() === this.props.limitByTermsetNameOrID.toLowerCase());
}
return {
_ObjectType_: this._termSetCollectionObjectType,
_Child_Items_: termSets
};
});
}
/**
* Searches terms by provided text in the term sets specified by limitByTermsetNameOrID
*/
_searchTermsByTermSet(searchText) {
return __awaiter(this, void 0, void 0, function* () {
yield this._ensureTermStores();
const returnTerms = [];
const termSets = yield this.getTermSets();
for (const termSet of termSets) {
const terms = yield this.getAllTerms(termSet);
const filtered = this._filterTermsBySearch(terms, searchText);
for (const term of filtered) {
returnTerms.push(this._termToPickerTerm(term, termSet));
}
}
return returnTerms;
});
}
/**
* Searches terms by provided text in the group specified by limitByGroupNameOrID
*/
_searchTermsByGroup(searchText) {
return __awaiter(this, void 0, void 0, function* () {
yield this._ensureTermStores();
const returnTerms = [];
for (const termStore of this._termStores) {
const groups = this._groups[termStore.Id];
const targetGroup = groups.find(g => g.Name === this.props.limitByGroupNameOrID ||
g.Id.toLowerCase() === this.props.limitByGroupNameOrID.toLowerCase());
if (targetGroup) {
for (const termSet of targetGroup.TermSets._Child_Items_) {
const terms = yield this.getAllTerms(termSet);
const filtered = this._filterTermsBySearch(terms, searchText);
for (const term of filtered) {
const pickerTerm = this._termToPickerTerm(term, termSet);
pickerTerm.termGroup = targetGroup.Id;
returnTerms.push(pickerTerm);
}
}
}
}
return returnTerms;
});
}
/**
* Searches for terms across all term stores
*/
_searchAllTerms(searchText) {
return __awaiter(this, void 0, void 0, function* () {
yield this._ensureTermStores();
const returnTerms = [];
for (const termStore of this._termStores) {
const groups = this._groups[termStore.Id];
for (const group of groups) {
for (const termSet of group.TermSets._Child_Items_) {
const terms = yield this.getAllTerms(termSet);
const filtered = this._filterTermsBySearch(terms, searchText);
for (const term of filtered) {
const pickerTerm = this._termToPickerTerm(term, termSet);
pickerTerm.termGroup = group.Id;
returnTerms.push(pickerTerm);
}
}
}
}
return returnTerms;
});
}
/**
* Filters terms by search text (starts with, case-insensitive)
*/
_filterTermsBySearch(terms, searchText) {
const lowerSearch = searchText.toLowerCase();
return terms.filter(t => t.Name.toLowerCase().startsWith(lowerSearch)).slice(0, 30);
}
/**
* Converts an ITerm to an IPickerTerm
*/
_termToPickerTerm(term, termSet) {
const pickerTerm = {
key: term.Id,
name: term.Name,
path: term.PathOfTerm,
termSet: termSet.Id,
termSetName: termSet.Name,
termGroup: ''
};
if (term.Labels) {
pickerTerm.labels = term.Labels;
}
return pickerTerm;
}
/**
* Ensures term stores and groups are loaded
*/
_ensureTermStores() {
return __awaiter(this, void 0, void 0, function* () {
if (this._termStores) {
return;
}
try {
// Get the default term store
const termStoreInfo = yield this._taxonomyRequest('termStore');
this._termStoreId = termStoreInfo.id;
// Get all groups in the term store
const groupsResponse = yield this._taxonomyRequest('termStore/groups');
let groups = groupsResponse.value;
// Filter by group if specified
if (this.props.limitByGroupNameOrID) {
groups = groups.filter(g => g.name === this.props.limitByGroupNameOrID ||
g.id.toLowerCase() === this.props.limitByGroupNameOrID.toLowerCase());
}
// Exclude system groups if specified
if (this.props.excludeSystemGroup) {
groups = groups.filter(g => g.type !== 'systemGroup');
}
// Build the groups with their term sets
const processedGroups = [];
for (const taxonomyGroup of groups) {
// Get term sets for this group
const termSetsResponse = yield this._taxonomyRequest(`termStore/groups/${taxonomyGroup.id}/sets`);
let termSets = termSetsResponse.value;
// Filter by term set if specified
if (this.props.limitByTermsetNameOrID) {
termSets = termSets.filter(ts => {
var _a, _b;
const name = ((_a = ts.localizedNames.find(n => n.languageTag === termStoreInfo.defaultLanguageTag)) === null || _a === void 0 ? void 0 : _a.name) || ((_b = ts.localizedNames[0]) === null || _b === void 0 ? void 0 : _b.name);
return name === this.props.limitByTermsetNameOrID ||
ts.id.toLowerCase() === this.props.limitByTermsetNameOrID.toLowerCase();
});
}
const group = {
_ObjectType_: 'SP.Taxonomy.TermGroup',
_ObjectIdentity_: taxonomyGroup.id,
Id: taxonomyGroup.id,
Name: taxonomyGroup.name,
IsSystemGroup: taxonomyGroup.type === 'systemGroup',
TermStore: {
Id: termStoreInfo.id,
Name: termStoreInfo.name
},
TermSets: {
_ObjectType_: this._termSetCollectionObjectType,
_Child_Items_: termSets.map(ts => this._convertTermSet(ts, termStoreInfo.defaultLanguageTag, taxonomyGroup.id))
}
};
// Only add groups that have term sets (after filtering)
if (group.TermSets._Child_Items_.length > 0 || !this.props.limitByTermsetNameOrID) {
processedGroups.push(group);
}
}
this._groups[termStoreInfo.id] = processedGroups;
// Build the term store result
this._termStores = [{
_ObjectType_: 'SP.Taxonomy.TermStore',
_ObjectIdentity_: termStoreInfo.id,
Id: termStoreInfo.id,
Name: termStoreInfo.name,
Groups: {
_ObjectType_: this._termGroupCollectionObjectType,
_Child_Items_: processedGroups
}
}];
}
catch (error) {
console.error('Error loading term stores', error);
this._termStores = [];
}
});
}
/**
* Converts a taxonomy API term set to the internal ITermSet format
*/
_convertTermSet(taxonomyTermSet, defaultLanguage, groupId) {
var _a, _b;
const defaultName = ((_a = taxonomyTermSet.localizedNames.find(n => n.languageTag === defaultLanguage)) === null || _a === void 0 ? void 0 : _a.name) ||
((_b = taxonomyTermSet.localizedNames[0]) === null || _b === void 0 ? void 0 : _b.name) || '';
const names = {};
taxonomyTermSet.localizedNames.forEach(n => {
names[n.languageTag] = n.name;
});
return {
_ObjectType_: 'SP.Taxonomy.TermSet',
_ObjectIdentity_: taxonomyTermSet.id,
Id: taxonomyTermSet.id,
Name: defaultName,
Description: taxonomyTermSet.description || '',
Names: names,
Group: groupId
};
}
/**
* Gets the default label from a taxonomy term
*/
_getDefaultLabel(taxonomyTerm) {
var _a;
const defaultLabel = taxonomyTerm.labels.find(l => l.isDefault);
return (defaultLabel === null || defaultLabel === void 0 ? void 0 : defaultLabel.name) || ((_a = taxonomyTerm.labels[0]) === null || _a === void 0 ? void 0 : _a.name) || '';
}
/**
* Gets the description from a taxonomy term
*/
_getDescription(taxonomyTerm) {
var _a, _b;
return ((_b = (_a = taxonomyTerm.descriptions) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.description) || '';
}
}
//# sourceMappingURL=PnPTermStorePickerService.js.map