import * as React from 'react'; import styles from './AddJsCssReference.module.scss'; import { IAddJsCssReferenceProps } from './IAddJsCssReferenceProps'; import { escape } from '@microsoft/sp-lodash-subset'; import { TextField, MaskedTextField } from 'office-ui-fabric-react/lib/TextField'; import { ListView, IViewField, SelectionMode} from "@pnp/spfx-controls-react/lib/ListView"; import {MessageBarType,Link,Separator, CommandBarButton,IStackStyles,Text,MessageBar,PrimaryButton,DefaultButton,Dialog,DialogFooter,DialogType,Stack, IStackTokens, updateA, Icon, Spinner } from 'office-ui-fabric-react'; import { sp} from "@pnp/sp"; import "@pnp/sp/webs"; import "@pnp/sp/user-custom-actions"; import "@pnp/sp/presets/all"; import {TypedHash} from "@pnp/common"; import { IUserCustomActionAddResult,IUserCustomActionUpdateResult,IUserCustomAction } from '@pnp/sp/user-custom-actions'; import { createTheme, ITheme } from 'office-ui-fabric-react/lib/Styling'; import { mergeStyleSets } from 'office-ui-fabric-react/lib/Styling'; import { PermissionKind } from '@pnp/sp/presets/all'; const stackTokens: IStackTokens = { childrenGap: 40 }; const CustomActionTitle = 'JSCssAppCustomizer'; const ApplicationCustomizerComponentID = '38afa8d7-b498-4529-9f99-6279392f9309'; const description = 'This user action is of type application customizer to custom js and css file references via SFPx extension'; const theme: ITheme = createTheme({ fonts: { medium: { // fontFamily: 'Monaco, Menlo, Consolas', fontSize: '18px' } } }); const stackStyles: Partial = { root: { height: 30 } }; export interface IAddJsCssReferenceState { disableRegisterButton: boolean; disableRemoveButton: boolean; jsfiles:any[]; cssfiles:any[]; currentjsRef:string; currentcssRef:string; hideJSDailog:boolean; hideCSSDailog:boolean; currentCustomAction:any; isEdit:boolean; editIndex:number; showMesssage:boolean; successmessage:string; userHasPermission:boolean; showspinner:boolean; } export default class AddJsCssReference extends React.Component { private viewFields: any[] = [ { name: "Type", displayName: "Action", minWidth: 60, maxWidth:60, render: (item,index) =>{ console.log(item); return ( this.editClicked(item,index)} /> this.deleteClicked(item,index)} /> {/* this.editClicked(item,index)} aria-hidden="true"> this.deleteClicked(item,index)} aria-hidden="true"> */} ); }, className:"test" }, { name: "FilePath", displayName: "FilePath", minWidth:600, render: (item,index) =>{ console.log(item); return ( {item.FilePath} ); } // maxWidth:800 } ]; constructor(props: IAddJsCssReferenceProps,state:IAddJsCssReferenceProps) { super(props); this.state = { disableRegisterButton:false, disableRemoveButton:false, jsfiles:[], cssfiles:[], currentjsRef:"", currentcssRef:"", hideJSDailog:true, hideCSSDailog:true, currentCustomAction:null, isEdit:false, editIndex:-1, showMesssage:false, successmessage:"", userHasPermission:false, showspinner:true }; sp.setup(this.props.context); } public render(): React.ReactElement { return ( {this.state.showspinner && } {this.state.userHasPermission &&
SPFx JS CSS References WebPart

This webpart can be used to add reference to custom js files and css files via SPFx extension application customizer.

{this.state.showMesssage && { this.setState({showMesssage:false});}} messageBarType={MessageBarType.success}> {this.state.successmessage} } {this.state.currentCustomAction && this.state.showMesssage != true && We found you already have some custom js and css files references added via this customizer. Feel free to Edit or Remove references. }

CSS Files this.openAddCSSDailog()} /> {/* this.openAddCSSDailog()} /> */} {this.state.cssfiles.length === 0 && No References Found. this.openAddCSSDailog()}> Click here to add new.
} {this.state.cssfiles.length > 0 && }

this._registerClicked()} disabled={(this.state.jsfiles.length>0 || this.state.cssfiles.length>0 )?false:true} /> this._removeClicked()} disabled={this.state.currentCustomAction==null?true:false} />
} {!this.state.userHasPermission && !this.state.showspinner && Access denied, you do not have permission to access this section. Please connect with your site admins. }
); } public componentDidMount() { this.checkPermisson(); } private async checkPermisson(){ const perms2 = await sp.web.currentUserHasPermissions(PermissionKind.ManageWeb); this.setState({userHasPermission:perms2}); console.log(perms2); var temp = true; this.setState({showspinner:false}); if(perms2){ this.getCustomAction(); } } private _registerClicked(): void { this.setCustomAction(); } private _removeClicked(): void { const uca = sp.web.userCustomActions.getById(this.state.currentCustomAction.Id); const response = uca.delete(); console.log("removed custom action"); console.log(response); this.setState({currentCustomAction:null,jsfiles:[],cssfiles:[], showMesssage:true,successmessage:"Application Customizer deactivated sucessfully."}); } private updateCSSValue(evt) { this.setState({ currentcssRef: evt.target.value }); } private editClicked (item,index){ if(item.Type == "js") { this.setState({hideJSDailog:false, currentjsRef:item.FilePath, isEdit:true, editIndex:index }); } if(item.Type == "css") { this.setState({hideCSSDailog:false, currentcssRef:item.FilePath, isEdit:true, editIndex:index }); } } private deleteClicked (item,index){ if(item.Type == "css") { let currentitems = this.state.cssfiles.map((x) => x); currentitems.splice(index,1); this.setState({cssfiles:currentitems}); } } private openAddCSSDailog (){ this.setState({hideCSSDailog:false}); } private _addJsReference (){ if(!this.state.isEdit){ var item = { FilePath:this.state.currentjsRef, Type: "js" }; let currentitems = this.state.jsfiles.map((x) => x); currentitems.push(item); currentitems[this.state.jsfiles.length] = item; this.setState({jsfiles:currentitems, hideJSDailog:true,currentjsRef:""}); } else{ item = { FilePath:this.state.currentjsRef, Type: "js" }; let currentitems = this.state.jsfiles.map((x) => x); currentitems[this.state.editIndex] = item; this.setState({jsfiles:currentitems, hideJSDailog:true,currentjsRef:"", isEdit:false,editIndex:-1}); } } private _addCSSReference (){ if(!this.state.isEdit){ console.log("add item to grid"); var item = { FilePath:this.state.currentcssRef, Type:"css" }; let currentitems = this.state.cssfiles.map((x) => x); currentitems.push(item); currentitems[this.state.cssfiles.length] = item; this.setState({cssfiles:currentitems, hideCSSDailog:true, currentcssRef:""}); } else{ console.log("add item to grid"); item = { FilePath:this.state.currentcssRef, Type:"css" }; let currentitems = this.state.cssfiles.map((x) => x); currentitems[this.state.editIndex] = item; this.setState({cssfiles:currentitems, hideCSSDailog:true, currentcssRef:"", editIndex:-1,isEdit:false}); } } private _closeJSDialog = (): void => { this.setState({ hideJSDailog: true }); } private _closeCSSDialog = (): void => { this.setState({ hideCSSDailog: true }); } private async getCustomAction(){ var web = await sp.web.get(); console.log(web); var customactions:any = await sp.web.userCustomActions.get(); console.log(customactions); var found = customactions.filter(item => item.Title == CustomActionTitle); if (found.length > 0) { this.setState({currentCustomAction:found[0]}); var jsonproperties = found[0].ClientSideComponentProperties; var jsfileArray = JSON.parse(jsonproperties).jsfiles; var cssfileArray = JSON.parse(jsonproperties).cssfiles; console.log(jsfileArray); console.log(cssfileArray); this.setState({jsfiles:jsfileArray,cssfiles:cssfileArray}); } } protected async setCustomAction() { try { const payload: TypedHash = { "Title": CustomActionTitle, "Description": description, "Location": 'ClientSideExtension.ApplicationCustomizer', ClientSideComponentId:ApplicationCustomizerComponentID, ClientSideComponentProperties: JSON.stringify({jsfiles:this.state.jsfiles,cssfiles:this.state.cssfiles }), }; if(this.state.currentCustomAction == null) { const response : IUserCustomActionAddResult = await sp.web.userCustomActions.add(payload); console.log(response); const uca = await sp.web.userCustomActions.getById(response.data.Id); this.setState({currentCustomAction: uca,showMesssage:true,successmessage:"Application customizer activated sucessfully."}); } else{ const uca = sp.web.userCustomActions.getById(this.state.currentCustomAction.Id); const response: IUserCustomActionUpdateResult =await uca.update(payload); const ucaupdated = await sp.web.userCustomActions.getById(response.data.Id); this.setState({currentCustomAction: ucaupdated,showMesssage:true,successmessage:"Application customizer updated sucessfully."}); } } catch (error) { console.error(error); } } }