UNPKG

@mikezimm/fps-library-v2

Version:

Library of reusable typescript/javascript functions, interfaces and constants

777 lines (775 loc) 46.1 kB
/** * CodeAnalizerComment: Updated 5 imports on 2024-09-22 14:49:52 * Update:: import { IAnySourceItem } to '@mikezimm/fps-core-v7/lib/components/molecules/AnyContent/IAnyContent;' * Update:: import { IAnySourceItemAny } to '@mikezimm/fps-core-v7/lib/components/molecules/AnyContent/IAnyContent;' * Update:: import { getFilteredItems } to '@mikezimm/fps-core-v7/lib/components/molecules/SearchPage/functions/getFilteredV1;' * Update:: import { IFPSAgeSliderProps } to '@mikezimm/fps-core-v7/lib/components/atoms/FPSAgeSlider/FPSAgeTypes;' * Update:: import { FPSAgeSliderOptions7Years } to '@mikezimm/fps-core-v7/lib/components/atoms/FPSAgeSlider/FPSAgeSliderOptions7YearPart;' */ /** * CodeAnalizerComment: Updated 6 imports on 2024-09-21 23:07:24 * Update:: import { check4This } to '@mikezimm/fps-core-v7/lib/logic/Links/CheckSearch;' * Update:: import { IAnySourceItem } to '@mikezimm/fps-core-v7/lib/components/molecules/AnyContent/IAnyContent;' * Update:: import { IAnySourceItemAny } to '@mikezimm/fps-core-v7/lib/components/molecules/AnyContent/IAnyContent;' * Update:: import { makeid } to '@mikezimm/fps-core-v7/lib/logic/Strings/guids;' * Update:: import { getFilteredItems } to '@mikezimm/fps-core-v7/lib/components/molecules/SearchPage/functions/getFilteredV1;' * Update:: import { upperFirstLetter } to '@mikezimm/fps-core-v7/lib/logic/Strings/stringCase;' */ import * as React from 'react'; import { Icon, } from '@fluentui/react/lib/Icon'; import { DefaultMultiSelectCommands, } from './ISourcePagesProps'; import FPSAgeSliderHook from '../../atoms/FPSAgeSlider/FPSAgeHook'; import { check4This, Check4 } from "@mikezimm/fps-core-v7/lib/logic/Links/CheckSearch"; import { makeid } from '@mikezimm/fps-core-v7/lib/logic/Strings/guids'; import { getFilteredItems } from '@mikezimm/fps-core-v7/lib/components/molecules/SearchPage/functions/getFilteredV1'; import SourceSearchAgeHook from '../SearchPage/component/SearchBoxRowAge'; import { FPSAgeSliderOptions7Years } from '@mikezimm/fps-core-v7/lib/components/atoms/FPSAgeSlider/FPSAgeSliderOptions7YearPart'; import { GetGoToListLink } from '../../atoms/Links/GetGoToListLink'; import { FPSFetchStatus } from '../../atoms/FetchStatus/FPSFetchStatus'; import { sourceButtonRow } from './sourceButtonRow'; import { FPSReactJSON } from '../../atoms/ReactJSON/ReactJSONObjectV2'; import { upperFirstLetter } from '@mikezimm/fps-core-v7/lib/logic/Strings/stringCase'; import { stringifyFpsSpServiceObj } from '@mikezimm/fps-core-v7/lib/components/molecules/source-props/createSources/cloneSourceProps'; import { makeSmallTimeObject } from '@mikezimm/fps-core-v7/lib/logic/Time/smallTimeObject'; const AgeSliderOptions = [{ key: -1, maxAge: 0, text: 'all dates', }, ...FPSAgeSliderOptions7Years.map(item => { item.text = `${item.text.replace('The past ', 'older than ')} ago`.replace(`ago ago`, `ago`); // fix double 'ago' return item; })]; const defaultMaxVisible = 20; require('@mikezimm/fps-styles/dist/sourcePages.css'); export default class SourcePages extends React.Component { _updateParentCmds() { if (this.props.onParentRequestsFilteredCmds && this.props.onParentRequestsFilteredCmds.length > 0) { this._onParentRequestsFilteredCmds = this.props.onParentRequestsFilteredCmds; } } /*** * .o88b. .d88b. d8b db .d8888. d888888b d8888b. db db .o88b. d888888b .d88b. d8888b. * d8P Y8 .8P Y8. 888o 88 88' YP `~~88~~' 88 `8D 88 88 d8P Y8 `~~88~~' .8P Y8. 88 `8D * 8P 88 88 88V8o 88 `8bo. 88 88oobY' 88 88 8P 88 88 88 88oobY' * 8b 88 88 88 V8o88 `Y8b. 88 88`8b 88 88 8b 88 88 88 88`8b * Y8b d8 `8b d8' 88 V888 db 8D 88 88 `88. 88b d88 Y8b d8 88 `8b d8' 88 `88. * `Y88P' `Y88P' VP V8P `8888Y' YP 88 YD ~Y8888P' `Y88P' YP `Y88P' 88 YD * * */ //Standards are really site pages, supporting docs are files constructor(props) { super(props); this._itemsPerPage = defaultMaxVisible; this._retainViewXdidUpdates = 0; this._multiButtonLabels = []; this._onParentRequestsFilteredCmds = ['_onParentRequestsFilteredCmds???']; const { stateSource, } = this.props; const refreshId = stateSource ? stateSource.refreshId : 'mzWasHere'; this._updateParentCmds(); const searchText = this.props.deepProps && this.props.deepProps.length >= 1 && this.props.deepProps[0] ? decodeURIComponent(this.props.deepProps[0]) : ''; const topSearchStr = this.props.deepProps && this.props.deepProps.length >= 2 && this.props.deepProps[1] ? decodeURIComponent(this.props.deepProps[1]) : '[]'; const topSearch = !topSearchStr ? [] : JSON.parse(topSearchStr); const filtered = stateSource ? getFilteredItems(stateSource.items, searchText, [], [], [], topSearch) : []; this._itemsPerPage = this.props.itemsPerPage ? this.props.itemsPerPage : this._itemsPerPage; const enableAge = this.props.ageSlider === true && this.props.searchAgeProp && this.props.searchAgeOp ? true : false; const ageIndex = this.props.ageIndexDefault ? this.props.ageIndexDefault : 0; const searchAge = AgeSliderOptions[Math.abs(ageIndex)].maxAge; //ageIndex is negative... needs inverse to get array element this.state = { refreshId: refreshId ? refreshId : 'mzWasHere', filtered: filtered, topSearch: topSearch, sortNum: 'asc', sortName: '-', sortGroup: '-', searchTime: null, searchText: searchText, showItemPanel: false, showCanvasContent1: false, showPanelJSON: false, showThisItem: filtered.length > 0 ? filtered[0] : null, firstVisible: 0, lastVisible: this._itemsPerPage - 1, resetArrows: refreshId ? refreshId : 'mzWasHere', detailToggle: false, searchAge: searchAge, enableAge: enableAge, lastItemMultiClickIdx: -79, renderJSON: this.props.jsonOption === 'Default' || this.props.jsonOption === 'Only' ? true : false, infinateItems: this.props.jsonOption === 'Default' || this.props.jsonOption === 'Only' ? true : false, parentRequestStatus0: '', parentRequestStatus1: '', parentRequestStatus2: '', parentRequestStatus3: '', }; } async componentDidMount() { await this.updateWebInfo(); } // /*** * d8888b. d888888b d8888b. db db d8888b. d8888b. .d8b. d888888b d88888b * 88 `8D `88' 88 `8D 88 88 88 `8D 88 `8D d8' `8b `~~88~~' 88' * 88 88 88 88 88 88 88 88oodD' 88 88 88ooo88 88 88ooooo * 88 88 88 88 88 88 88 88~~~ 88 88 88~~~88 88 88~~~~~ * 88 .8D .88. 88 .8D 88b d88 88 88 .8D 88 88 88 88. * Y8888D' Y888888P Y8888D' ~Y8888P' 88 Y8888D' YP YP YP Y88888P * * this._retainFilters = true; */ componentDidUpdate(prevProps) { //Just rebuild the component const { stateSource, topButtons, ageSlider, searchAgeProp, searchAgeOp, } = this.props; const enableAge = ageSlider === true && searchAgeProp && searchAgeOp ? true : false; const itemsLength = stateSource ? stateSource.items.length : 0; let resetArrows = false; if (prevProps.resetArrows !== this.props.resetArrows || prevProps.ageSlider !== ageSlider || prevProps.searchAgeProp !== searchAgeProp || prevProps.searchAgeOp !== searchAgeOp) { resetArrows = true; } let lastVisible = this._itemsPerPage; if (check4This(Check4.filtered_Eq_true) === true) console.log('filtered SourePage', lastVisible, stateSource.items); if (itemsLength < lastVisible) lastVisible = itemsLength; if (!stateSource || topButtons.join('-') !== prevProps.topButtons.join('-')) { this.setState({ filtered: stateSource ? stateSource.items : [], topSearch: [], searchText: '', firstVisible: 0, lastVisible: lastVisible - 1, refreshId: makeid(4), resetArrows: makeid(4), enableAge: enableAge, lastItemMultiClickIdx: -79, }); /** * 2024-12-22: Had to clear the fpsSpService from the stringify process or else get an error like: * 'Something went wrong' * ERROR: * Converting circular structure to json * --> property '_registrations' -> object with constructure 'Object' * --> property 'sp-page-context:PageContext_9' -> object with constructure 'Object' * --> property 'service' -> object with constructure 'a' * * Originally looked like this: * } else if ( JSON.stringify(this.props.primarySource ) !== JSON.stringify(prevProps.primarySource ) ) { * Added the refreshId check first so it does not have to stringify the props */ } else if (this.props.primarySource.refreshId !== prevProps.primarySource.refreshId || stringifyFpsSpServiceObj(this.props.primarySource) !== stringifyFpsSpServiceObj(prevProps.primarySource)) { this.setState({ filtered: stateSource ? stateSource.items : [], topSearch: [], searchText: '', firstVisible: 0, lastVisible: lastVisible - 1, refreshId: makeid(4), resetArrows: makeid(4), enableAge: enableAge, lastItemMultiClickIdx: -79, }); } else if (this.props.forceRender !== prevProps.forceRender || this.props.stateSource.items.length !== prevProps.stateSource.items.length) { this.setState({ topSearch: [], filtered: stateSource.items, // added searchText reset for https://github.com/mikezimm/Compliance/issues/126 searchText: '', firstVisible: 0, lastVisible: lastVisible - 1, refreshId: makeid(4), resetArrows: makeid(4), enableAge: enableAge, lastItemMultiClickIdx: -79, }); } else if (this.props.stateSource.refreshId !== prevProps.stateSource.refreshId || this.props.pageWidth !== prevProps.pageWidth || this.props.topButtons.length !== prevProps.topButtons.length) { // Added this loop for https://github.com/fps-solutions/HubCon/issues/46 // Essentially allows to keep the same view items ( paging and items on the screen ) after you call onParentCall -- as in case where you 'select' an item but want to keep same items on the screen. if (this._retainViewXdidUpdates > 0) { this._retainViewXdidUpdates--; const ageFilteredItems = this.state.enableAge === false ? this.props.stateSource.items : []; if (this.state.enableAge === true) { this.props.stateSource.items.map((item) => { if (item.FPSItem && item.FPSItem.Stamp) if (item[this.props.searchAgeProp] > this.state.searchAge) { ageFilteredItems.push(item); } }); } const filtered = getFilteredItems(ageFilteredItems, this.state.searchText, [], [], [], this.state.topSearch); let lastVisible = this._itemsPerPage; if (check4This(Check4.filtered_Eq_true) === true) console.log('filtered SourePage', lastVisible, filtered); this.setState({ filtered: filtered, }); } else { this.setState({ topSearch: [], filtered: this.props.stateSource.items, firstVisible: 0, lastVisible: lastVisible - 1, refreshId: this.props.stateSource.refreshId, resetArrows: makeid(4), enableAge: enableAge, lastItemMultiClickIdx: -79, }); } } else if (resetArrows === true) { this.setState({ firstVisible: 0, lastVisible: lastVisible - 1, resetArrows: makeid(4), enableAge: enableAge, lastItemMultiClickIdx: -79, }); } } async updateWebInfo() { } /*** * d8888b. d88888b d8b db d8888b. d88888b d8888b. * 88 `8D 88' 888o 88 88 `8D 88' 88 `8D * 88oobY' 88ooooo 88V8o 88 88 88 88ooooo 88oobY' * 88`8b 88~~~~~ 88 V8o88 88 88 88~~~~~ 88`8b * 88 `88. 88. 88 V888 88 .8D 88. 88 `88. * 88 YD Y88888P VP V8P Y8888D' Y88888P 88 YD * * */ render() { var _a; const { primarySource, topButtons, showItemType, stateSource, sourcePageClassName, disableSpinner, tableFractionalWidths = [], tableStyles = {} } = this.props; // canvasOptions const { debugMode, selectedClass, tableHeaderElements, tableHeaderClassName, tableClassName } = this.props; // canvasOptions const { headingElement, footerElement, multiSelectCall, multiSelectCommands, multiSelectKeyword, ReactJSONSettings, onParentDisabled } = this.props; // canvasOptions // eslint-disable-next-line @typescript-eslint/no-unused-vars const { searchText, renderJSON } = this.state; const StatusElement = FPSFetchStatus(primarySource, stateSource, disableSpinner); // /** * 2024-12-30: Added disablePage as a way to disable buttons, search etc which should not work due to data not being loaded. */ const disablePage = StatusElement || stateSource.ok !== true ? true : false; const topSearch = []; //All major future to be grid components topButtons.map(searchObjectFull => { // Added this if then so only buttons with valid value will create button... empty, undefined and null will not create button if (searchObjectFull) { const searchObjectArray = searchObjectFull.split('=='); const searchObject = searchObjectArray[0]; const classNames = ['button']; if (this.state.topSearch.indexOf(searchObjectFull) > -1) { classNames.push('isSelected'); classNames.push(selectedClass); } /** * This topSearch using arrow function did not work */ topSearch.push(React.createElement("div", { className: classNames.join(' '), style: null, onClick: this._clickTop.bind(this, searchObjectFull), title: searchObjectArray.length > 0 ? searchObjectFull : '' }, searchObject)); //Only show Title prop if the button has special search } }); const topSearchContent = React.createElement("div", { className: 'topSearch', style: { background: debugMode === true ? 'pink' : null } }, topSearch); const renderAsTable = tableHeaderElements && tableHeaderElements.length > 0 ? true : false; let tableElement = undefined; const filtered = []; let tableHeaderRow = undefined; if (renderAsTable === true) { tableHeaderRow = React.createElement("tr", { className: tableHeaderClassName }, tableHeaderElements.map((item, index) => { return React.createElement("th", { key: index }, item); })); } /** * 2024-12-30: https://github.com/fps-solutions/HubCon/issues/115 * I considered adding stateSource.ok === true in the if but decided against it because in HubCon for instance, * the 1 item in the state.filtered array was the error tile so I will let it show. */ const { optionalColumns1, optionalColumns2, optionalColumns3, optionalColumns4, optionalColumns5, optionalColumns6, optionalColumns7, expand, openItemButton } = this.props; // canvasOptions const { rowParamBoo1, rowParamStr1, rowParamNum1, rowParamObj1 } = this.props; // canvasOptions if (renderJSON === false && stateSource.loaded === true) { this.state.filtered.map((item, idx) => { if (idx >= this.state.firstVisible && idx <= this.state.lastVisible) { filtered.push(this.props.renderRow({ item: item, searchText: searchText, onClick: this.clickListItem.bind(this), onTextFilter: this.clickTextFilter.bind(this), onPropFilter: this.clickPropFilter.bind(this), details: this.state.detailToggle, showItemType: showItemType, onParentCall: this._parentCall.bind(this), sendItemToParent: this._sendItemToParent.bind(this), optionalColumns1: optionalColumns1, optionalColumns2: optionalColumns2, optionalColumns3: optionalColumns3, optionalColumns4: optionalColumns4, optionalColumns5: optionalColumns5, optionalColumns6: optionalColumns6, optionalColumns7: optionalColumns7, /** * 2025-03-04: Only adding some of the optional params down until the additional ones are needed */ rowParamBoo1: rowParamBoo1, rowParamStr1: rowParamStr1, rowParamNum1: rowParamNum1, rowParamObj1: rowParamObj1, expand: expand, openItemButton: openItemButton, })); } }); } else { // push spinner element // if ( this.props.disableSpinner !== true ) filtered.push( FPSFetchSpinner( stateSource, primarySource )); } if (renderJSON === false && (!stateSource || stateSource.items.length === 0)) { // This is duplicated in SearchPage.tsx and SourcePages.tsx as well // const FetchingSpinner = this.props.showSpinner === false ? null : <div style={{display: 'inline'}}><Spinner size={SpinnerSize.large} label={"Fetching more information ..."} style={{ padding: 30 }} /></div>; // const spinnerStyles : ISpinnerStyles = { label: {fontSize: '20px', fontWeight: '600', }}; // const FetchingSpinner = this.props.showSpinner === false ? null : <div style={{display: 'inline', top: -10, position: 'relative'}}> // <Spinner size={SpinnerSize.medium} label={"Fetching more information ..."} labelPosition= 'right' // style={{ paddingBottom: 10, backgroundColor: 'lightyellow' }} styles={ spinnerStyles }/></div>; filtered.push(undefined); } /** * https://github.com/fps-solutions/HubCon/issues/115 * 2024-12-30: DELETED THIS section because after I added * stateSource.ok === true to only show after valid loaded results * I realized it was the exact same conditions and result content as noResults: JSX.Element below and a duplicate * * */ // } else if ( stateSource.ok === true && stateSource.items.length > 0 && filtered.length === 0 ) { // filtered.push( <div> // <h2>Hmmm... I could not find any items with</h2> // <h3>Search text: </h3> // <div style={{ fontWeight: 'bold', color: 'darkred' }}>{ searchText ? searchText : 'Does not look like you typed anything in the search box...' }</div> // <h3>With any of these words (top buttons)</h3> // {this.state.topSearch.length === 0 ? // <div> // No top buttons were selected. // </div> // : // <div style={{ fontWeight: 'bold', color: 'blue' }}>{ this.state.topSearch.map( (str: string, idx: number ) => { // return <li key={idx} >{ str }</li> // })}</div> // } // </div> // ) // } const noResults = stateSource.ok === true && stateSource.items.length > 0 && filtered.length === 0 ? React.createElement("div", null, React.createElement("h2", null, "Hmmm... I could not find any items with"), React.createElement("h3", null, "Search text: "), React.createElement("div", { style: { fontWeight: 'bold', color: 'darkred' } }, searchText ? searchText : 'Does not look like you typed anything in the search box...'), React.createElement("h3", null, "With any of these words (top buttons)"), this.state.topSearch.length === 0 ? React.createElement("div", null, "No top buttons were selected.") : React.createElement("div", { style: { fontWeight: 'bold', color: 'blue' } }, this.state.topSearch.map((str, idx) => { return React.createElement("li", { key: idx }, str); }))) : undefined; const tableClasses = ['sourceTable', tableClassName]; if (renderJSON !== true && renderAsTable === true) { tableElement = React.createElement("table", { className: tableClasses.join(' '), style: tableStyles }, tableHeaderRow, filtered); } const { ageSlider, searchAgeProp, jsonOption, jsonObject, jsonFiltered } = this.props; // canvasOptions const AgeSliderWPProps = ageSlider === false ? undefined : { FPSAgeIsVisible: true, disabled: disablePage, // https://github.com/fps-solutions/PagePal/issues/7 FPSAgeColumnName: searchAgeProp ? searchAgeProp : 'modifiedAge', FPSAgeColumnTitle: searchAgeProp ? upperFirstLetter(searchAgeProp, true) : 'Modified', FPSAgeDefault: 0, onChange: (value) => this._onAgeChange(value), alternateOptions: AgeSliderOptions, }; const AgeSlider = ageSlider === false ? undefined : React.createElement(FPSAgeSliderHook, { props: AgeSliderWPProps }); const gotoListLink = GetGoToListLink({ primarySource: primarySource, }); // GetGoToListLink, GetGoToItemLink, GetGoToWebLink const debugContent = debugMode !== true ? null : React.createElement("div", { style: { cursor: 'default', marginLeft: '20px' } }, "App in debugMode - Change in Web Part Properties - Page Preferences. ", React.createElement("b", null, React.createElement("em", null, "Currently in ", primarySource.listTitle))); const searchSourceDesc = !primarySource.searchSourceDesc ? null : React.createElement("div", { className: 'searchSourceDesc' }, React.createElement("div", { className: 'sourceDesc' }, primarySource.searchSourceDesc), gotoListLink); const jsonIconCSS = { fontSize: 'x-large', padding: '7px', width: '18px', borderRadius: '7px', marginRight: '10px', cursor: 'pointer' }; // background: this.state.renderJSON === true ? 'lightgreen' : 'white', const InfinateIcon = jsonOption === 'Never' || ((_a = stateSource === null || stateSource === void 0 ? void 0 : stateSource.items) === null || _a === void 0 ? void 0 : _a.length) <= defaultMaxVisible ? undefined : React.createElement(Icon, { title: 'Show up to 1000 Filtered items', style: { ...jsonIconCSS, ...{ fontWeight: this.state.infinateItems === true ? 900 : 300, } }, iconName: 'LineSpacing', onClick: disablePage === true ? null : this._setInfinate.bind(this) }); const JSONIcon = jsonOption === 'Never' || jsonOption === 'Only' ? undefined : React.createElement(Icon, { title: 'Show items as JSON', style: { ...jsonIconCSS, ...{ fontWeight: this.state.renderJSON === true ? 900 : 300, } }, iconName: 'Code', onClick: disablePage === true ? null : () => this.setState({ renderJSON: !this.state.renderJSON }) }); const INJSONIcons = React.createElement("div", { style: { display: 'flex', alignItems: 'center', } }, JSONIcon, InfinateIcon); let MultiSelectEle = null; // multiSelectCall, multiSelectCommands, multiSelectKeyword if (multiSelectCall) { let buttonLabels = []; this._multiButtonLabels = multiSelectCommands && multiSelectCommands.length > 0 ? multiSelectCommands : DefaultMultiSelectCommands; if (multiSelectKeyword) { this._multiButtonLabels.map((item) => { buttonLabels.push(item ? item.replace(`Select`, multiSelectKeyword) : ''); }); } else { buttonLabels = this._multiButtonLabels; } const multiSelectButtonRowProps = { title: '', // heading?: JSX.Element; // Heading above row of buttons Labels: buttonLabels, onClick: this._multiCall.bind(this), selected: null, infoEle: INJSONIcons, rowClass: null, selectedClass: null, rowCSS: { display: 'inline-flex', gap: '1em', paddingTop: '0px' }, buttonCSS: null, disabled: disablePage === true ? ['all'] : null, descEle: null, // Added as block element below buttons. strings are made to smaller font-size. }; MultiSelectEle = sourceButtonRow(multiSelectButtonRowProps); } const searchBox = React.createElement(SourceSearchAgeHook, { disabled: disablePage, _onSearchChange: this._onSearchChange.bind(this), searchTime: this.state.searchTime, searchText: searchText, farLeftEle: MultiSelectEle ? MultiSelectEle : INJSONIcons, itemsPerPage: this._itemsPerPage, itemCount: this.state.filtered.length, _updateFirstLastVisible: this._updateFirstLastVisible.bind(this), debugMode: debugMode, resetArrows: this.state.resetArrows, layout: 'grid', ageElement: AgeSlider }); // const deepHistory = debugMode !== true ? null : // <ReactJson src={ this.state.filtered } name={ primarySource.listTitle } collapsed={ false } displayDataTypes={ false } displayObjectSize={ false } enableClipboard={ true } style={{ padding: '20px 0px' }} theme= { 'rjv-default' } indentWidth={ 2}/>; // // Moved entire panel to separate functional component so it can be reused from Search as well // const thePanel = showItemPanel !== true ? null : // ContentPanel( { // showItemPanel: showItemPanel, // showThisItem: showThisItem, // primarySource: primarySource, // onClosePanel: this._onClosePanel.bind(this), // debugMode: debugMode, // topButtons: topButtons, // refreshId: refreshId, // search: search, // source: source, // canvasOptions: canvasOptions, // } ); // const errorMessage = stateSource && stateSource.errorInfo && stateSource.errorInfo.returnMess ? true : false; // const theMessage = errorMessage === false ? '' : stateSource.errorInfo.returnMess.split('"value":"'); // const webUrl = itemList[ preLoadIndex ].Subsite; // const listTitle = itemList[ preLoadIndex ].NoRecordsDeclared; // const webLinkElemennt2 = <div style={{ paddingLeft: '20px' }}className={ [ 'searchSourceStatus', 'fps-gen-goToLink' ].join(' ')} onClick={ () => { window.open( `${primarySource.webUrl}`,'_blank' ) ; } }> // Go to web <Icon iconName='OpenInNewTab'/></div>; // const webUrlLink = <span className={ 'errorLink' } onClick={ () => { window.open( primarySource.webUrl, '_blank')}}>{ primarySource.webUrl }</span>; // const webUrlLinkDiv = <div style={ { color: 'black', fontSize: 'large', paddingBottom: '10px', fontWeight: 600 }} >Site Url: { webUrlLink }</div>; // const GoToWebLink1 = GetGoToWebLink( { primarySource: primarySource, altWebText: 'Site Url:', }); // GetGoToListLink, GetGoToItemLink, GetGoToWebLink // const GoToWebLink2 = GetGoToWebLink( { primarySource: primarySource, altWebText: 'Go to site:', showWebIcon: true, webLinkCSS: { color: null, fontSize: null, marginRight: '60px'} }); // GetGoToListLink, GetGoToItemLink, GetGoToWebLink // const errorElement = errorMessage !== true ? undefined : <div style={{ background: 'yellow', color: 'red', height: '200px', paddingTop: '25px', textAlign: 'center' }}> // { GoToWebLink1 } // {/* <div style={{ color: 'black', paddingBottom: '5px', fontSize: 'large', fontWeight: 600 }}>Site Url: { webUrlLink }</div> // <div style={{ color: 'black', paddingBottom: '15px', fontSize: 'large', fontWeight: 600 }}>Library: { listUrlLink }</div> */} // <div style={{ fontSize: 'x-large', paddingBottom: '5px', fontWeight: 700 }}>{ stateSource.errorInfo.friendly }</div> // <div style={{ fontSize: 'large', paddingBottom: '15px' }}>{ theMessage[ theMessage.length -1 ].replace('"}}}', '') }</div> // { GoToWebLink2 } // { gotoListLink } // </div>; // Added this const hasError = stateSource.status === 'Success' || stateSource.status === 'Unknown' ? false : true; let JsonElementF = undefined; let JsonElementU = undefined; if (renderJSON === true && stateSource.status === 'Success') { // jsonOption?: ISourceJsonOption; // Default = false // jsonObject?: ISourceJsonObject; // default = items // jsonFiltered?: ISourceJsonFilter; // default = filtered const JSONLabel = `${jsonObject === 'items' ? jsonObject === 'items' : 'StateSource'}`; if (jsonFiltered === 'both' || jsonFiltered === 'unfiltered') { const useThisObject = jsonObject === 'items' ? stateSource.items : stateSource; const JSONBase = { name: `UnFiltered ${JSONLabel} [ ${stateSource.items.length} ]`, jsonObject: useThisObject, collapsed: true, }; const AdjustedReactJSONSettings = { ...ReactJSONSettings, ...{ style: { paddingTop: '20px' } } }; const JSONSettings = AdjustedReactJSONSettings ? { ...JSONBase, ...AdjustedReactJSONSettings, } : JSONBase; JsonElementU = FPSReactJSON(JSONSettings); } if (jsonFiltered === 'both' || jsonFiltered === 'filtered') { const useThisObject = jsonObject === 'items' ? this.state.filtered : { ...stateSource, ...{ items: this.state.filtered } }; const JSONBase = { name: `Filtered ${JSONLabel} [ ${this.state.filtered.length} ]`, jsonObject: useThisObject, collapsed: true, }; const JSONSettings = ReactJSONSettings ? { ...JSONBase, ...ReactJSONSettings, } : JSONBase; JsonElementF = FPSReactJSON(JSONSettings); if (this.props.onParentRequestsFiltered) { JsonElementF = React.createElement("div", { className: 'topSearch' }, JsonElementF, this._onParentRequestsFilteredCmds.map((cmd, idx) => { return React.createElement("div", { style: { paddingLeft: '2em', minWidth: '240px' } }, React.createElement("div", { style: { padding: '.5em 2em', height: '19px' }, className: `button${onParentDisabled === true ? ' isDisabled' : ''}`, onClick: onParentDisabled === true ? null : () => this._SendParentFiltered(cmd, idx) }, cmd), React.createElement("div", { style: { padding: '1em 0em 0em 1em', paddingLeft: '1em' } }, this.state[`parentRequestStatus${idx}`])); })); } } } return (React.createElement("div", { className: ['sourcePage', sourcePageClassName].join(' ') }, debugContent, headingElement, searchSourceDesc, hasError === false ? searchBox : undefined, hasError === false ? topSearchContent : undefined, renderJSON === false && hasError === false && renderAsTable === true ? tableElement : undefined, renderJSON === false && hasError === false && renderAsTable === false ? filtered : undefined, JsonElementU, JsonElementF, noResults, StatusElement, footerElement)); } _SendParentFiltered(cmd, idx) { const timeNow = makeSmallTimeObject(''); const stateMessage = `${this.state.filtered.length} @ ${timeNow.now.toLocaleString()}`; this.setState({ [`parentRequestStatus${idx}`]: stateMessage }); this.props.onParentRequestsFiltered(this.state.filtered, cmd, idx); } _multiCall(buttonIdx) { // export const DefaultMultiSelectCommands: IMultiSelectCommand[] = [ 'Select Visible', 'Un-Select Visible', 'Clear All' ]; // this._multiButtonLabels let command = null; const sendThese = []; if (this._multiButtonLabels[buttonIdx] === DefaultMultiSelectCommands[0]) { // Selected Visible command = DefaultMultiSelectCommands[0]; this._retainViewXdidUpdates = 1; // Skip render when Selecting or Un-Selecting Visible items this.state.filtered.map((item, idx) => { if (idx >= this.state.firstVisible && idx <= this.state.lastVisible) sendThese.push(item); }); } else if (this._multiButtonLabels[buttonIdx] === DefaultMultiSelectCommands[1]) { // Un-Selected Visible command = DefaultMultiSelectCommands[1]; this._retainViewXdidUpdates = 1; // Skip render when Selecting or Un-Selecting Visible items this.state.filtered.map((item, idx) => { if (idx >= this.state.firstVisible && idx <= this.state.lastVisible) sendThese.push(item); }); } else if (this._multiButtonLabels[buttonIdx] === DefaultMultiSelectCommands[2]) { // Clear All command = DefaultMultiSelectCommands[2]; this._retainViewXdidUpdates = 0; // Skip render when Selecting or Un-Selecting Visible items } else { alert('SourcePages Error: _multiCall ~ 502'); } if (this.props.multiSelectCall) { this.props.multiSelectCall(command, sendThese); } else { alert('SourcePages Error: _multiCall ~ 508'); } } _sendItemToParent(command, Id, type, item, event) { const sendItemToParent = this.props.sendItemToParent; if (!sendItemToParent) { alert(`SourcePages _sendItemToParent:\n\nThere is no sendItemToParent function to call !!`); return; } sendItemToParent(command, Id, type, item, event); } _parentCall(command, Id, type, item, retainViewXdidUpdates, event) { if (retainViewXdidUpdates > 0) this._retainViewXdidUpdates = retainViewXdidUpdates; // As of 2023-10-08: Tested SPO Shift Click functionality and it is always 'Addative' and never shift Click unselects anything const isShift = event && event.shiftKey ? true : false; // This is a normal call: // NOTE Have to test what happens if you hold Shift and click on the same item twice... Does it still keep selected? // Need to verify both the visible status and the selected property of the item. if (!this.props.onParentCallMultiClick || isShift === false || this.state.lastItemMultiClickIdx < 0) { this.props.onParentCall(command, Id, type, item); } else { // This is a special call like shift-click const selectedItems = this._getItemsBetweenIds(Id, this.state.lastItemMultiClickIdx, this.state.filtered); this.props.onParentCallMultiClick(command, Id, type, selectedItems); } this.setState({ lastItemMultiClickIdx: Id }); } // Id is the latest clicked item _getItemsBetweenIds(Id1, Id2, items) { const results = []; let found1 = false; let found2 = false; let skipRest = false; items.map((item, idx) => { if (skipRest === false) { if (item.Id === Id1) found1 = true; if (item.Id === Id2) found2 = true; // If this is either of the end points or in between, push it to results. if (found1 === true || found2 === true) results.push(item); if (found1 === true && found2 === true) skipRest = true; } }); return results; } _clickTop(itemC, event) { const { stateSource, searchAgeProp, } = this.props; // canvasOptions const { topSearch, enableAge, searchAge, searchText } = this.state; const selected = this.toggleSearchInArray(topSearch, itemC, event.ctrlKey === true ? 'multi' : 'single'); console.log('_clickTop:', itemC, selected); const ageFilteredItems = enableAge === false ? stateSource.items : []; if (enableAge === true) { stateSource.items.map((item) => { if (item.FPSItem && item.FPSItem.Stamp) if (item[searchAgeProp] > searchAge) { ageFilteredItems.push(item); } }); } const filtered = getFilteredItems(ageFilteredItems, searchText, [], [], [], selected); let lastVisible = this._itemsPerPage; if (check4This(Check4.filtered_Eq_true) === true) console.log('filtered SourePage', lastVisible, filtered); if (filtered.length < lastVisible) lastVisible = filtered.length; this.setState({ topSearch: selected, filtered: filtered, firstVisible: 0, lastVisible: lastVisible - 1, resetArrows: makeid(4), }); } // private _detailsToggle(): void { // const newState = this.state.detailToggle === true ? false : true; // this.setState({ detailToggle: newState }); // } _setInfinate() { const newSetting = this.state.infinateItems === true ? false : true; this._itemsPerPage = newSetting === true ? 1000 : defaultMaxVisible; let lastVisible = this.props.itemsPerPage ? this.props.itemsPerPage : defaultMaxVisible; if (newSetting === true) lastVisible = 1000; if (this.state.filtered.length < lastVisible) lastVisible = this.state.filtered.length; this.setState({ firstVisible: 0, lastVisible: lastVisible - 1, refreshId: makeid(4), resetArrows: makeid(4), infinateItems: newSetting, }); } toggleSearchInArray(searchArray, value, doThis) { let selected = JSON.parse(JSON.stringify(searchArray)); const idx = selected.indexOf(value); if (doThis === 'multi') { if (idx < 0) { selected.push(value); } else { delete selected[idx]; } } else if (doThis === 'single') { if (selected.length > 1) { selected = [value]; } else if (idx < 0) { selected = [value]; } else if (idx > -1) { selected = []; } else { alert('toggleSearchInArrayError'); console.log('toggleSearchInArray Not triggered:', value, doThis, searchArray); } } return selected; } /** * https://www.kindacode.com/article/react-typescript-handling-onclick-event/ * React.MouseEvent<HTMLImageElement> * @param NewSearch * * * Found sample here: * https://github.com/pnp/sp-dev-fx-webparts/blob/b139ba199cb57363a88f070dd9814e5af4fc3cbd/samples/react-my-sites/src/webparts/mySites/components/MySites/MySites.tsx#L168 * (event?: React.ChangeEvent<HTMLInputElement>, newValue?: string) */ _onAgeChange(ageIndex) { const startTime = new Date(); const searchAge = AgeSliderOptions[Math.abs(ageIndex)].maxAge; //ageIndex is negative... needs inverse to get array element // Defaults searchAgeProp to 'modifiedAge' if nothing is provided but ageSearch is enabled. // Defaults searchAgeOp to 'show <' if nothing is provided but ageSearch is enabled. const searchAgeProp = this.props.searchAgeProp ? this.props.searchAgeProp : 'modifiedAge'; const searchAgeOp = this.props.searchAgeOp ? this.props.searchAgeOp : 'show <'; const ageFilteredItems = this.state.enableAge === false ? this.props.stateSource.items : []; if (this.state.enableAge === true) { this.props.stateSource.items.map((item) => { if (searchAgeOp === 'show >') { if (item[searchAgeProp] > searchAge) ageFilteredItems.push(item); } else if (searchAgeOp === 'show <') { if (item[searchAgeProp] < searchAge) ageFilteredItems.push(item); } }); } const filtered = getFilteredItems(ageFilteredItems, this.state.searchText, [], [], [], this.state.topSearch); const endTime = new Date(); const totalTime = endTime.getTime() - startTime.getTime(); let lastVisible = this.props.itemsPerPage ? this.props.itemsPerPage : defaultMaxVisible; if (filtered.length < lastVisible) lastVisible = filtered.length; this.setState({ filtered: filtered, searchText: this.state.searchText, searchTime: totalTime, firstVisible: 0, lastVisible: lastVisible - 1, refreshId: makeid(4), resetArrows: makeid(4), searchAge: searchAge, }); } _onSearchChange(event, NewSearch) { const startTime = new Date(); const SearchValue = NewSearch; const ageFilteredItems = this.state.enableAge === false ? this.props.stateSource.items : []; if (this.state.enableAge === true) { this.props.stateSource.items.map((item) => { if (item[this.props.searchAgeProp] > this.state.searchAge) ageFilteredItems.push(item); }); } const filtered = getFilteredItems(ageFilteredItems, NewSearch, [], [], [], this.state.topSearch); const endTime = new Date(); const totalTime = endTime.getTime() - startTime.getTime(); let lastVisible = this.props.itemsPerPage ? this.props.itemsPerPage : defaultMaxVisible; if (filtered.length < lastVisible) lastVisible = filtered.length; this.setState({ filtered: filtered, searchText: !SearchValue ? '' : SearchValue, searchTime: totalTime, firstVisible: 0, lastVisible: lastVisible - 1, refreshId: makeid(4), resetArrows: makeid(4), }); } // eslint-disable-next-line @typescript-eslint/no-explicit-any clickListItem(ID, category, item, event) { if (check4This(Check4.onClicks_Eq_true) === true) console.log('onClicks clickNewsItem:', ID, item); this.setState({ showItemPanel: true, showThisItem: item }); } clickTextFilter(value, event) { if (check4This(Check4.onClicks_Eq_true) === true) console.log('onClicks clickTextFilter:', value); this._onSearchChange(null, value); } clickPropFilter(prop, value, event) { if (check4This(Check4.onClicks_Eq_true) === true) console.log('onClicks clickPropFilter:', prop, value); //Clear filter if it was already set to this value if (value === this.state.searchText) value = ''; this._onSearchChange(null, value); } _updateFirstLastVisible(firstVisible, lastVisible) { this.setState({ firstVisible: firstVisible, lastVisible: lastVisible, }); } } //# sourceMappingURL=SourcePages.js.map