Skip to content

Commit

Permalink
Fix Issue 1911
Browse files Browse the repository at this point in the history
  • Loading branch information
NishkalankBezawada committed Dec 12, 2024
1 parent fe8f98f commit 38e212d
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 35 deletions.
Binary file modified .nvmrc
Binary file not shown.
166 changes: 134 additions & 32 deletions docs/documentation/docs/controls/ModernTaxonomyPicker.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,114 @@ Custom rendering of a More actions button that displays a context menu for each
const termSetId = "36d21c3f-b83b-4acc-a223-4df6fa8e946d";
const [clickedActionTerm, setClickedActionTerm] = React.useState<ITermInfo>();

const addChildTerm = (parentTermId, updateTaxonomyTreeViewCallback): void => {
private addTermSwitch = async (index: number, term: ITermInfo, updateTaxonomyTreeViewCallback: any, isParent: boolean) => {
if (isParent) {
this.addTerm(index, term, updateTaxonomyTreeViewCallback);
} else {
this.addChildTerm(index, term, updateTaxonomyTreeViewCallback);
}
}

//Below methods are using graphClient to create terms
private addTerm = async (index: number, term: ITermInfo, updateTaxonomyTreeViewCallback: any) => {
try {
if (termSetId) {
this.props.context?.msGraphClientFactory?.getClient("3").then((client) => {
client
.api(`/sites/${this.props.context?.pageContext.site.id}/termStore/sets/${termSetId}/terms/${term.id}`)
.post({
labels: [
{
languageTag: "en-US",
name: "TestTerm",
isDefault: true,
},
],
})
.then((response) => {
const { "@odata.context": _, ...filteredResponse } = response;
filteredResponse.isAvailableForTagging = [
{
"setId": termSetId,
"isAvailable": true
}
];
// Pass the filtered response to updateTaxonomyTreeViewCallback
updateTaxonomyTreeViewCallback([filteredResponse] as ITermInfo[], [term] as ITermInfo[], null, null);
})
.catch((error) => {
console.error("Error adding child term", error);
});
});
} else {
console.error("termSetId is undefined");
}
} catch (error) {
console.error("Error adding child term", error);
}
}

private addChildTerm = async (index: number, term: ITermInfo, updateTaxonomyTreeViewCallback: any) => {
try {
if (termSetId) {
this.props.context?.msGraphClientFactory?.getClient("3").then((client) => {
client
.api(`/sites/${this.props.context?.pageContext.site.id}/termStore/sets/${termSetId}/terms/${term.id}/children`)
.post({
labels: [
{
languageTag: "en-US",
name: "TestChild",
isDefault: true,
},
],
})
.then((response) => {
// Exclude @odata.context from the response
const { "@odata.context": _, ...filteredResponse } = response;
filteredResponse.isAvailableForTagging = [
{
"setId": termSetId,
"isAvailable": true
}
];
// Pass the filtered response to updateTaxonomyTreeViewCallback
updateTaxonomyTreeViewCallback([filteredResponse] as ITermInfo[], [term] as ITermInfo[], null, null);
})
.catch((error) => {
console.error("Error adding child term", error);
});
});
} else {
console.error("termSetId is undefined");
}
} catch (error) {
console.error("Error adding child term", error);
}
}


private deleteTerm = (_: number, term: ITermInfo,updateTaxonomyTreeViewCallback: any) => {
if (termSetId) {
this.props.context?.msGraphClientFactory?.getClient("3").then((client) => {
client
.api(`/sites/${this.props.context?.pageContext.site.id}/termStore/sets/${termSetId}/terms/${term.id}`)
.delete()
.then(() => {
console.log("Term deleted");
updateTaxonomyTreeViewCallback(null,null,[term] as ITermInfo[]);
})
.catch((error) => {
console.error("Error deleting term", error);
});
});
} else {
console.error("termSetId is undefined");
}
}

//Another example in how to create term
const addChildTerm = (parentTermId, updateTaxonomyTreeViewCallback): void => {
spPost(sp.termStore.sets.getById(termSetId).terms.getById(parentTermId).children, {
body: JSON.stringify({
"labels": [
Expand All @@ -76,58 +183,53 @@ const addChildTerm = (parentTermId, updateTaxonomyTreeViewCallback): void => {
.then(term => {
updateTaxonomyTreeViewCallback([term], null, null);
});
}

...
}

//Usage
<ModernTaxonomyPicker
allowMultipleSelections={true}
termSetId={termSetId}
panelTitle="Panel title"
label={"Field title"}
context={this.props.context}
required={false}
initialValues={[{labels: [{name: "Subprocess A1", isDefault: true, languageTag: "en-US"}], id: "29eced8f-cf08-454b-bd9e-6443bc0a0f5e"}]}
onChange={this.onTaxPickerChange}
disabled={false}
customPanelWidth={700}
isLightDismiss={false}
isBlocking={false}
onRenderActionButton={(
termStoreInfo: ITermStoreInfo,
termSetInfo: ITermSetInfo,
termInfo: ITermInfo
updateTaxonomyTreeViewCallback?: (newTermItems?: ITermInfo[], updatedTermItems?: ITermInfo[], deletedTermItems?: ITermInfo[]) => void
allowMultipleSelections={true}
termSetId={'8ed8c9ea-7052-4c1d-a4d7-b9c10bffea6f'}
panelTitle='Select Term'
label={'Modern Taxonomy Picker'}
context={this.props.context}
required={false}
disabled={false}
onRenderActionButton={(
termStoreInfo: any,
termSetInfo: any,
termInfo: ITermInfo,
updateTaxonomyTreeViewCallback?: (newTermItems?: ITermInfo[], parentTerm?:ITermInfo[], updatedTermItems?: ITermInfo[], deletedTermItems?: ITermInfo[]) => void
): JSX.Element => {
const menuIcon: IIconProps = { iconName: 'MoreVertical', "aria-label": "More actions", style: { fontSize: "medium" } };
const menuIcon: IIconProps = { iconName: 'MoreVertical', 'aria-label': 'Add or delete terms', style: { fontSize: 'medium' } };
if (termInfo) {
const menuProps: IContextualMenuProps = {
items: [
{
key: 'addTerm',
text: 'Add Term',
iconProps: { iconName: 'Tag' },
onClick: () => addChildTerm(termInfo.id, updateTaxonomyTreeViewCallback)
onClick: () => { (async () => await this.addTermSwitch(0, termInfo, updateTaxonomyTreeViewCallback, false))(); }
},
{
key: 'deleteTerm',
text: 'Delete term',
iconProps: { iconName: 'Untag' },
onClick: () => deleteTerm(termInfo.id, updateTaxonomyTreeViewCallback)
onClick: () => this.deleteTerm(0,termInfo, updateTaxonomyTreeViewCallback)
},
],
};

return (
<IconButton
<>
<IconButton
menuProps={menuProps}
menuIconProps={menuIcon}
style={clickedActionTerm && clickedActionTerm.id === termInfo.id ? {opacity: 1} : null}
onMenuClick={(ev?: React.MouseEvent<HTMLElement, MouseEvent> | React.KeyboardEvent<HTMLElement>, button?: IButtonProps) => {
setClickedActionTerm(termInfo));
style={{opacity: 1}}
onMenuClick={(_: React.MouseEvent<HTMLElement, MouseEvent> | React.KeyboardEvent<HTMLElement>, __?: IButtonProps) => {
console.log('IconButton clicked');
this.setClickedActionTerm(termInfo);
}}
onAfterMenuDismiss={() => setClickedActionTerm(null)}
/>
</>
);
}
else {
Expand All @@ -137,7 +239,7 @@ const addChildTerm = (parentTermId, updateTaxonomyTreeViewCallback): void => {
key: 'addTerm',
text: 'Add term',
iconProps: { iconName: 'Tag' },
onClick: () => addTerm(termInfo.id, updateTaxonomyTreeViewCallback)
onClick: () => { (async () => await this.addTermSwitch(0, termInfo, updateTaxonomyTreeViewCallback, true))(); }
},
],
};
Expand Down Expand Up @@ -175,7 +277,7 @@ The ModernTaxonomyPicker control can be configured with the following properties
| themeVariant | IReadonlyTheme | no | The current loaded SharePoint theme/section background (More info: [Supporting section backgrounds](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/supporting-section-backgrounds)). |
| isLightDismiss | boolean | no | Whether the panel can be light dismissed. |
| isBlocking | boolean | no | Whether the panel uses a modal overlay or not. |
| onRenderActionButton | function | no | Optional custom renderer for adding e.g. a button with additional actions to the terms in the tree view. |
| onRenderActionButton | function | no | Optional custom renderer for adding e.g. a button with additional actions to the terms in the tree view. See advanced example section |
| isPathRendered | boolean | no | Whether the terms will be rendered with the term label or the full path up to the root. |
| allowSelectingChildren | boolean | no | Whether child terms can be selected. Default value is true. |

Expand Down
12 changes: 12 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ const fs = require('fs');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
build.addSuppression(`Warning - [sass] The local CSS class 'ms-motion-slideLeftIn' is not camelCase and will not be type-safe.`);
build.addSuppression(`Warning - [sass] The local CSS class 'ms-motion-fadeIn' is not camelCase and will not be type-safe.`);
build.addSuppression(`Warning - [sass] The local CSS class 'ms-motion-slideRightIn' is not camelCase and will not be type-safe.`);
build.addSuppression(`Warning - [sass] The local CSS class 'ms-motion-fadeOut' is not camelCase and will not be type-safe.`);
build.addSuppression(`Warning - [sass] The local CSS class 'ms-motion-scaleDownIn' is not camelCase and will not be type-safe.`);
build.addSuppression(`Warning - [sass] The local CSS class 'ms-motion-scaleDownOut' is not camelCase and will not be type-safe.`);
build.addSuppression(`Warning - [sass] The local CSS class 'ms-motion-slideLeftOut' is not camelCase and will not be type-safe.`);
build.addSuppression(`Warning - [sass] The local CSS class 'ms-motion-slideRightOut' is not camelCase and will not be type-safe.`);
build.addSuppression(`Warning - [sass] The local CSS class 'ms-motion-slideUpOut' is not camelCase and will not be type-safe.`);
build.addSuppression(`Warning - [sass] The local CSS class 'ms-motion-slideDownOut' is not camelCase and will not be type-safe.`);
build.addSuppression(`Warning - [sass] The local CSS class 'ms-motion-slideUpIn' is not camelCase and will not be type-safe.`);
build.addSuppression(`Warning - [sass] The local CSS class 'ms-motion-slideDownIn' is not camelCase and will not be type-safe.`);

// Update the version number in the version.ts file
gulp.task('versionUpdater', (done) => {
Expand Down
23 changes: 20 additions & 3 deletions src/controls/modernTaxonomyPicker/taxonomyTree/TaxonomyTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export interface ITaxonomyTreeProps {
termInfo: ITermInfo,
updateTaxonomyTreeViewCallback?: (
newTermItems?: ITermInfo[],
parentTerm?: ITermInfo[], //only for adding new terms
updatedTermItems?: ITermInfo[],
deletedTermItems?: ITermInfo[]
) => void
Expand All @@ -84,7 +85,7 @@ export function TaxonomyTree(
const [groups, setGroups] = React.useState<IGroup[]>([]);

const updateTaxonomyTreeViewWithNewTermItems = (
newTermItems: ITermInfo[]
newTermItems: ITermInfo[], parentTerm?: ITermInfo[]
): void => {
for (const term of newTermItems) {
const findGroupContainingTerm = (currentGroup: IGroup): IGroup => {
Expand All @@ -102,6 +103,21 @@ export function TaxonomyTree(
return null;
};

const findParentTermLevel = (groups: IGroup[], parentTermId: string): number | null => {
for (const group of groups) {
if (group.key === parentTermId) {
return group.level;
}
if (group.children && group.children.length > 0) {
const level = findParentTermLevel(group.children, parentTermId);
if (level !== null) {
return level;
}
}
}
return null;
};
const parentTermLevel = findParentTermLevel([groups[0]], parentTerm[0].id );
const groupToAddTermTo = findGroupContainingTerm(groups[0]);
let termNames = term.labels.filter(
(termLabel) =>
Expand All @@ -121,7 +137,7 @@ export function TaxonomyTree(
key: term.id,
startIndex: -1,
count: 50,
level: groupToAddTermTo.level + 1,
level: parentTermLevel + 1,
isCollapsed: true,
data: { skiptoken: "", term: term },
hasMoreData: term.childrenCount > 0,
Expand Down Expand Up @@ -216,11 +232,12 @@ export function TaxonomyTree(

const updateTaxonomyTreeView = (
newTermItems?: ITermInfo[],
parentTerm?:ITermInfo[],
updatedTermItems?: ITermInfo[],
deletedTermItems?: ITermInfo[]
): void => {
if (newTermItems) {
updateTaxonomyTreeViewWithNewTermItems(newTermItems);
updateTaxonomyTreeViewWithNewTermItems(newTermItems,parentTerm);
}

if (updatedTermItems) {
Expand Down

0 comments on commit 38e212d

Please sign in to comment.