Skip to content

Commit 7ff35e1

Browse files
committed
Merge branch 'dev' of https://github.com/siata13/sp-dev-fx-controls-react into siata13-dev
2 parents 430721e + ebc2d88 commit 7ff35e1

File tree

15 files changed

+504
-32
lines changed

15 files changed

+504
-32
lines changed

docs/documentation/docs/controls/TaxonomyPicker.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import { TaxonomyPicker, IPickerTerms } from "@pnp/spfx-controls-react/lib/Taxon
4242
context={this.props.context}
4343
onChange={this.onTaxPickerChange}
4444
isTermSetSelectable={false}
45+
termActions={termActions}
4546
/>
4647
```
4748

@@ -71,6 +72,7 @@ The TaxonomyPicker control can be configured with the following properties:
7172
| disabledTermIds | string[] | no | Specify which terms should be disabled in the term set so that they cannot be selected. |
7273
| disableChildrenOfDisabledParents | boolean | no | Specify if you want to disable the child terms when their parent is disabled. |
7374
| anchorId | string | no | Set the anchorid to a child term in the TermSet to be able to select terms from that level and below. |
75+
| termActions | ITermActions | no | Allows to execute custom action on the term like e.g. get other term labelsITermActions. |
7476

7577
Interface `IPickerTerm`
7678

@@ -86,4 +88,18 @@ Interface `IPickerTerms`
8688

8789
An Array of IPickerTerm
8890

91+
Interface `ITermActions`
92+
| Property | Type | Required | Description |
93+
| ---- | ---- | ---- | ---- |
94+
| actions | ITermAction[] | yes | The array of supported actions |
95+
| termActionsDisplayStyle | TermActionsDisplayStyle | no | Defines how to display term action button, available options: text (default), icon, text and icon |
96+
| termActionsDisplayMode | TermActionsDisplayMode | no | Defines how to display term actions, as buttons (default) or dropdown |
97+
98+
Interface `ITermAction`
99+
| Property | Type | Required | Description |
100+
| ---- | ---- | ---- | ---- |
101+
| id | string | yes | Unique id of the term action |
102+
| displayText | string | no | Name of the action |
103+
| iconName | string | no | Name of the icon to be used to display action |
104+
89105
![](https://telemetry.sharepointpnp.com/sp-dev-fx-controls-react/wiki/controls/Placeholder)

src/controls/taxonomyPicker/ITaxonomyPicker.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { ApplicationCustomizerContext } from '@microsoft/sp-application-base';
22
import { IPickerTerms } from './ITermPicker';
3-
import { ITermStore, IGroup, ITermSet, ITerm } from '../../services/ISPTermStorePickerService';
4-
import SPTermStorePickerService from '../../services/SPTermStorePickerService';
3+
import { ITermSet, ITerm } from '../../services/ISPTermStorePickerService';
54
import { IWebPartContext } from '@microsoft/sp-webpart-base';
5+
import { ITermActions } from './termActions/ITermsActions';
66

77
/**
88
* PropertyFieldTermPickerHost properties interface
@@ -52,6 +52,17 @@ export interface ITaxonomyPickerProps {
5252
* Whether the property pane field is enabled or not.
5353
*/
5454
disabled?: boolean;
55+
56+
/**
57+
* Include standard term actions.
58+
*/
59+
includeDefaultTermActions?: boolean;
60+
61+
/**
62+
* Specifies the available term actions and their basic properties.
63+
*/
64+
termActions?: ITermActions;
65+
5566
/**
5667
* The method is used to get the validation error message and determine whether the input value is valid or not.
5768
*
@@ -77,7 +88,6 @@ export interface ITaxonomyPickerProps {
7788
* PropertyFieldTermPickerHost state interface
7889
*/
7990
export interface ITaxonomyPickerState {
80-
8191
termSetAndTerms? : ITermSet;
8292
errorMessage?: string;
8393
openPanel?: boolean;
@@ -99,7 +109,9 @@ export interface ITermParentProps extends ITermChanges {
99109
anchorId? : string;
100110
isTermSetSelectable?: boolean;
101111

112+
termActions?: ITermActions;
102113
autoExpand: () => void;
114+
updateTaxonomyTree: () => void;
103115
termSetSelectedChange?: (termSet: ITermSet, isChecked: boolean) => void;
104116
}
105117

@@ -114,8 +126,12 @@ export interface ITermProps extends ITermChanges {
114126
term: ITerm;
115127
multiSelection: boolean;
116128
disabled: boolean;
129+
termActions?: ITermActions;
130+
131+
updateTaxonomyTree: () => void;
117132
}
118133

119134
export interface ITermState {
120135
selected?: boolean;
136+
termLabel: string;
121137
}

src/controls/taxonomyPicker/ITermPicker.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { ApplicationCustomizerContext } from '@microsoft/sp-application-base';
22
import { IWebPartContext } from '@microsoft/sp-webpart-base';
33

4-
5-
64
/**
75
* Selected terms
86
*/

src/controls/taxonomyPicker/TaxonomyPicker.module.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
.contextualMenu {
2+
display: inline-block
3+
}
4+
15
.listItem {
26
height: 36px;
37
line-height: 36px;

src/controls/taxonomyPicker/TaxonomyPicker.tsx

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ import TermPicker from './TermPicker';
77
import { IPickerTerms, IPickerTerm } from './ITermPicker';
88
import { ITaxonomyPickerProps, ITaxonomyPickerState } from './ITaxonomyPicker';
99
import SPTermStorePickerService from './../../services/SPTermStorePickerService';
10-
import { ITermSet, IGroup, ITerm } from './../../services/ISPTermStorePickerService';
10+
import { ITermSet, ITerm } from './../../services/ISPTermStorePickerService';
11+
import { TermLabelAction, ITermActions } from './termActions';
12+
1113
import styles from './TaxonomyPicker.module.scss';
1214
import { sortBy, uniqBy, cloneDeep, isEqual } from '@microsoft/sp-lodash-subset';
1315
import TermParent from './TermParent';
1416
import FieldErrorMessage from './ErrorMessage';
15-
import * as telemetry from '../../common/telemetry';
1617

18+
import * as telemetry from '../../common/telemetry';
1719

1820
/**
1921
* Image URLs / Base64
@@ -81,19 +83,28 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
8183
*/
8284
private loadTermStores(): void {
8385
this.termsService = new SPTermStorePickerService(this.props, this.props.context);
86+
87+
if (this.props.termActions) {
88+
this.props.termActions.actions.map(x => {
89+
x.initialize(this.termsService);
90+
});
91+
}
8492
this.termsService.getAllTerms(this.props.termsetNameOrID).then((response: ITermSet) => {
8593
// Check if a response was retrieved
86-
if (response !== null) {
87-
this.setState({
88-
termSetAndTerms: response,
89-
loaded: true
90-
});
91-
} else {
92-
this.setState({
93-
termSetAndTerms: null,
94-
loaded: true
95-
});
96-
}
94+
let termSetAndTerms = response ? response : null;
95+
this.setState({
96+
termSetAndTerms,
97+
loaded: true
98+
});
99+
});
100+
}
101+
102+
/**
103+
* Force update of the taxonomy tree - required by term action in case the term has been added, deleted or moved.
104+
*/
105+
private updateTaxonomyTree(): void {
106+
this.setState({
107+
termSetAndTerms: this.state.termSetAndTerms
97108
});
98109
}
99110

@@ -304,7 +315,11 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
304315
disabledTermIds={this.props.disabledTermIds}
305316
disableChildrenOfDisabledParents={this.props.disableChildrenOfDisabledParents}
306317
changedCallback={this.termsChanged}
307-
multiSelection={this.props.allowMultipleSelections} />
318+
multiSelection={this.props.allowMultipleSelections}
319+
320+
updateTaxonomyTree={this.updateTaxonomyTree}
321+
termActions={this.props.termActions}
322+
/>
308323
</div>
309324
)
310325
}

src/controls/taxonomyPicker/Term.tsx

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import * as React from 'react';
2-
import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox';
2+
import { Checkbox, ICheckboxStyles } from 'office-ui-fabric-react/lib/Checkbox';
33
import { ITermProps, ITermState } from './ITaxonomyPicker';
44

55
import styles from './TaxonomyPicker.module.scss';
6+
import TermActionsControl from './termActions/TermActionsControl';
7+
import { UpdateAction, UpdateType } from './termActions';
68

79

810
/**
@@ -17,7 +19,8 @@ export default class Term extends React.Component<ITermProps, ITermState> {
1719
let active = this.props.activeNodes.filter(item => item.key === this.props.term.Id);
1820

1921
this.state = {
20-
selected: active.length > 0
22+
selected: active.length > 0,
23+
termLabel: this.props.term.Name
2124
};
2225

2326
this._handleChange = this._handleChange.bind(this);
@@ -43,7 +46,8 @@ export default class Term extends React.Component<ITermProps, ITermState> {
4346
if (!this.props.multiSelection) {
4447
let active = nextProps.activeNodes.filter(item => item.key === this.props.term.Id);
4548
this.state = {
46-
selected: active.length > 0
49+
selected: active.length > 0,
50+
termLabel: this.state.termLabel
4751
};
4852
}
4953
}
@@ -63,23 +67,52 @@ export default class Term extends React.Component<ITermProps, ITermState> {
6367
return styles.termEnabled;
6468
}
6569

70+
private termActionCallback = (updateAction: UpdateAction): void => {
71+
if (updateAction == null) {
72+
return;
73+
}
74+
75+
if (updateAction.updateActionType === UpdateType.updateTermLabel) {
76+
this.props.term.Name = updateAction.value;
77+
this.setState({
78+
termLabel: updateAction.value
79+
});
80+
}
81+
else {
82+
this.props.updateTaxonomyTree();
83+
}
84+
}
85+
6686
/**
6787
* Default React render
6888
*/
6989
public render(): JSX.Element {
7090
const styleProps: React.CSSProperties = {
7191
marginLeft: `${(this.props.term.PathDepth * 30)}px`
7292
};
93+
const checkBoxStyle: React.CSSProperties = {
94+
display: "inline-flex"
95+
};
7396

7497
return (
75-
<div className={`${styles.listItem} ${styles.term}`} style={styleProps}>
76-
<Checkbox
77-
checked={this.state.selected}
78-
disabled={this.props.term.IsDeprecated || !this.props.term.IsAvailableForTagging || this.props.disabled}
79-
className={this.getClassName()}
80-
label={this.props.term.Name}
81-
onChange={this._handleChange} />
98+
<div>
99+
<div className={`${styles.listItem} ${styles.term}`} style={styleProps}>
100+
<div>
101+
<Checkbox
102+
checked={this.state.selected}
103+
style={checkBoxStyle}
104+
disabled={this.props.term.IsDeprecated || !this.props.term.IsAvailableForTagging || this.props.disabled}
105+
className={this.getClassName()}
106+
label={this.state.termLabel}
107+
onChange={this._handleChange} />
108+
</div>
109+
{
110+
this.props.termActions &&
111+
<TermActionsControl term={this.props.term} termActions={this.props.termActions} termActionCallback={this.termActionCallback} />
112+
}
113+
</div>
82114
</div>
115+
83116
);
84117
}
85118
}

src/controls/taxonomyPicker/TermParent.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,10 @@ export default class TermParent extends React.Component<ITermParentProps, ITermP
106106
disabled = parentPath && parentPath.length > 0;
107107
}
108108

109-
return <Term key={term.Id} term={term} termset={this.props.termset.Id} activeNodes={this.props.activeNodes} changedCallback={this.props.changedCallback} multiSelection={this.props.multiSelection} disabled={disabled} />;
109+
return <Term key={term.Id} term={term} termset={this.props.termset.Id}
110+
activeNodes={this.props.activeNodes} changedCallback={this.props.changedCallback}
111+
multiSelection={this.props.multiSelection} disabled={disabled}
112+
termActions={this.props.termActions} updateTaxonomyTree={this.props.updateTaxonomyTree}/>;
110113
})
111114
}
112115
</div>

src/controls/taxonomyPicker/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
export * from './ITaxonomyPicker';
22
export * from './TaxonomyPicker';
3-
export * from './ITermPicker';
3+
export * from './ITermPicker';
4+
export * from "./termActions/ITermsActions";
5+
export * from './termActions/TermActionsControl';
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import * as React from 'react';
2+
import { CommandBarButton } from 'office-ui-fabric-react/lib/Button';
3+
import { ITermAction, TermActionsDisplayStyle, IConreteTermActionProps } from './ITermsActions';
4+
5+
export default class ButtonTermAction extends React.Component<IConreteTermActionProps> {
6+
public render(): React.ReactElement<IConreteTermActionProps> {
7+
const { term, termActions } = this.props;
8+
9+
return (
10+
<div style={{ display: 'flex', alignItems: 'stretch', height: '32px' }}>
11+
{
12+
termActions &&
13+
termActions.map(termAction => {
14+
const { name, text, iconName } = this._prepareCommandBarButton(termAction);
15+
return (
16+
<div>
17+
<CommandBarButton split={true}
18+
onClick={() => { this._onActionExecute(termAction); }}
19+
iconProps={{ iconName: iconName }}
20+
text={text}
21+
name={name}
22+
key={term.Id}
23+
style={this._getTermActionActionButtonStyle()}
24+
/>
25+
</div>
26+
);
27+
})
28+
}
29+
</div>
30+
);
31+
}
32+
33+
34+
private _prepareCommandBarButton = (termAction: ITermAction): { name: string, text: string, iconName: string } => {
35+
let name, text, iconName = "";
36+
37+
if (this.props.displayStyle && (this.props.displayStyle === TermActionsDisplayStyle.text || this.props.displayStyle === TermActionsDisplayStyle.textAndIcon)) {
38+
name = termAction.displayText;
39+
text = termAction.displayText;
40+
}
41+
if (this.props.displayStyle && (this.props.displayStyle === TermActionsDisplayStyle.icon || this.props.displayStyle === TermActionsDisplayStyle.textAndIcon)) {
42+
iconName = termAction.iconName;
43+
}
44+
45+
return { name, text, iconName };
46+
}
47+
48+
private _getTermActionActionButtonStyle = (): React.CSSProperties => {
49+
let result: React.CSSProperties = {
50+
backgroundColor: "transparent",
51+
width: "32px",
52+
height: "32px"
53+
};
54+
55+
return result;
56+
}
57+
58+
private _onActionExecute = async (termAction: ITermAction) => {
59+
const updateAction = await termAction.actionCallback(this.props.term);
60+
this.props.termActionCallback(updateAction);
61+
}
62+
}

0 commit comments

Comments
 (0)