Add Expiry Indicator functionality with configuration and command set
- Implemented ExpiryItemService to manage expiry date logic for list items. - Created ExpiryModels to define types and structures for expiry configurations and rules. - Added RestError utility for handling API response errors. - Developed ExpiryIndicatorFieldCustomizer to display expiry information in list views. - Introduced ExpiryIndicatorCommandSet for extending expiry dates and managing settings. - Added settings dialog for configuring expiry settings. - Implemented localization support for English and German languages. - Added TypeScript configuration files for project setup. - Included TSLint configuration for code quality enforcement.
This commit is contained in:
157
src/extensions/expiryIndicator/ExpiryIndicatorFieldCustomizer.ts
Normal file
157
src/extensions/expiryIndicator/ExpiryIndicatorFieldCustomizer.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import { override } from '@microsoft/decorators';
|
||||
import {
|
||||
BaseFieldCustomizer,
|
||||
IFieldCustomizerCellEventParameters
|
||||
} from '@microsoft/sp-listview-extensibility';
|
||||
import { evaluateExpiry, formatDate, parseSharePointDate } from '../../common/ExpiryDateCalculator';
|
||||
import { ExpiryConfigService } from '../../common/ExpiryConfigService';
|
||||
import { ExpiryItemService } from '../../common/ExpiryItemService';
|
||||
import {
|
||||
createDefaultConfig,
|
||||
IExpiryConfig,
|
||||
IExpiryEvaluation,
|
||||
IItemDateValues,
|
||||
resolveBehavior
|
||||
} from '../../common/ExpiryModels';
|
||||
import styles from './ExpiryIndicatorFieldCustomizer.module.scss';
|
||||
import * as strings from 'ExpiryIndicatorStrings';
|
||||
|
||||
export interface IExpiryIndicatorFieldCustomizerProperties {
|
||||
}
|
||||
|
||||
export default class ExpiryIndicatorFieldCustomizer
|
||||
extends BaseFieldCustomizer<IExpiryIndicatorFieldCustomizerProperties> {
|
||||
|
||||
private _config: IExpiryConfig = createDefaultConfig();
|
||||
private _itemService: ExpiryItemService;
|
||||
private _itemCache: { [id: string]: Promise<IItemDateValues> } = {};
|
||||
|
||||
@override
|
||||
public onInit(): Promise<void> {
|
||||
if (!this.context.pageContext.list) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const service: ExpiryConfigService = new ExpiryConfigService(
|
||||
this.context.spHttpClient,
|
||||
this.context.pageContext.web.absoluteUrl
|
||||
);
|
||||
|
||||
this._itemService = new ExpiryItemService(
|
||||
this.context.spHttpClient,
|
||||
this.context.pageContext.web.absoluteUrl,
|
||||
this.context.pageContext.list.id.toString()
|
||||
);
|
||||
|
||||
return service.getConfig(this.context.pageContext.list.id.toString())
|
||||
.then((config: IExpiryConfig): void => { this._config = config; })
|
||||
.catch((): void => { this._config = createDefaultConfig(); });
|
||||
}
|
||||
|
||||
@override
|
||||
public onRenderCell(event: IFieldCustomizerCellEventParameters): void {
|
||||
this._clear(event.domElement);
|
||||
|
||||
const expiry: Date | undefined = parseSharePointDate(event.fieldValue);
|
||||
const createdValue: any = event.listItem && event.listItem.getValueByName
|
||||
? event.listItem.getValueByName(this._config.baseField)
|
||||
: undefined;
|
||||
const created: Date | undefined = parseSharePointDate(createdValue);
|
||||
|
||||
const idValue: any = event.listItem && event.listItem.getValueByName
|
||||
? (event.listItem.getValueByName('ID') || event.listItem.getValueByName('Id'))
|
||||
: undefined;
|
||||
const itemId: number = Number(idValue);
|
||||
|
||||
if (itemId > 0 && this._itemService) {
|
||||
const requestKey: string = String(itemId);
|
||||
event.domElement.setAttribute('data-expiry-item-id', requestKey);
|
||||
this._renderNeutral(event.domElement, strings.Loading);
|
||||
if (!this._itemCache[requestKey]) {
|
||||
this._itemCache[requestKey] = this._itemService.getItemDates(itemId, this._config);
|
||||
}
|
||||
|
||||
this._itemCache[requestKey].then((item: IItemDateValues): void => {
|
||||
if (event.domElement.getAttribute('data-expiry-item-id') !== requestKey) {
|
||||
return;
|
||||
}
|
||||
this._clear(event.domElement);
|
||||
this._renderValues(event.domElement, item.created, item.expiry, item.fieldValues);
|
||||
}).catch((): void => {
|
||||
if (event.domElement.getAttribute('data-expiry-item-id') === requestKey) {
|
||||
this._clear(event.domElement);
|
||||
this._renderValues(event.domElement, created, expiry, {});
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this._renderValues(event.domElement, created, expiry, {});
|
||||
}
|
||||
|
||||
@override
|
||||
public onDisposeCell(event: IFieldCustomizerCellEventParameters): void {
|
||||
this._clear(event.domElement);
|
||||
super.onDisposeCell(event);
|
||||
}
|
||||
|
||||
private _renderEvaluation(container: HTMLElement, evaluation: IExpiryEvaluation): void {
|
||||
const wrapper: HTMLSpanElement = document.createElement('span');
|
||||
wrapper.className = styles.cell + (evaluation.wasCalculated ? ' ' + styles.calculated : '');
|
||||
|
||||
if (evaluation.matchedRule) {
|
||||
wrapper.style.backgroundColor = evaluation.matchedRule.backgroundColor;
|
||||
wrapper.style.color = evaluation.matchedRule.textColor;
|
||||
}
|
||||
|
||||
const date: HTMLSpanElement = document.createElement('span');
|
||||
date.className = styles.date;
|
||||
date.textContent = formatDate(evaluation.effectiveExpiryDate);
|
||||
wrapper.appendChild(date);
|
||||
|
||||
if (evaluation.matchedRule && evaluation.matchedRule.label) {
|
||||
const label: HTMLSpanElement = document.createElement('span');
|
||||
label.className = styles.label;
|
||||
label.textContent = evaluation.matchedRule.label;
|
||||
wrapper.appendChild(label);
|
||||
}
|
||||
|
||||
const calculationHint: string = evaluation.wasCalculated ? ' – ' + strings.CalculatedHint : '';
|
||||
wrapper.title = strings.DaysUntilExpiry.replace('{0}', String(evaluation.daysUntilExpiry)) + calculationHint;
|
||||
container.appendChild(wrapper);
|
||||
}
|
||||
|
||||
private _renderValues(
|
||||
container: HTMLElement,
|
||||
created: Date | undefined,
|
||||
expiry: Date | undefined,
|
||||
fieldValues: { [fieldName: string]: any }
|
||||
): void {
|
||||
if (!expiry && !created) {
|
||||
this._renderNeutral(container, this._config.nullText);
|
||||
return;
|
||||
}
|
||||
|
||||
const evaluation: IExpiryEvaluation = evaluateExpiry(
|
||||
created || expiry as Date,
|
||||
expiry,
|
||||
this._config,
|
||||
undefined,
|
||||
resolveBehavior(this._config, fieldValues)
|
||||
);
|
||||
this._renderEvaluation(container, evaluation);
|
||||
}
|
||||
|
||||
private _renderNeutral(container: HTMLElement, text: string): void {
|
||||
const wrapper: HTMLSpanElement = document.createElement('span');
|
||||
wrapper.className = styles.cell + ' ' + styles.neutral;
|
||||
wrapper.textContent = text;
|
||||
container.appendChild(wrapper);
|
||||
}
|
||||
|
||||
private _clear(container: HTMLElement): void {
|
||||
while (container.firstChild) {
|
||||
container.removeChild(container.firstChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user