- 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.
158 lines
5.5 KiB
TypeScript
158 lines
5.5 KiB
TypeScript
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);
|
||
}
|
||
}
|
||
}
|