\r\n \r\n \r\n )\r\n }\r\n\r\n // Funzione che si occupa di renderizzare ogni singolo campo in base al tipo e ai suoi parametri\r\n renderField = (field: ResourceField) => {\r\n/*\r\n // Qui la lista è filtrata a monte in caso di update, va gestita in caso di insert - TODO capire come gestirla\r\n if (this.props.isNew && !field.Is_Visible && !field.Is_Key && !field.Is_Nullable) return\r\n\r\n // Questi campi non devono mai essere visibili\r\n if (field.FieldName == 'dat_obsoleto' || \r\n field.FieldName == 'cod_utente_cre' || \r\n field.FieldName == 'dat_utente_cre' || \r\n field.FieldName == 'cod_utente_mod' || \r\n field.FieldName == 'dat_utente_mod') return\r\n\r\n if (this.props.isNew && !field.Is_Visible && (field.Is_Key || field.Is_Nullable)) {\r\n field.Field_Label = \"ERRORE - Campo chiave o non nullabile\"\r\n field.Readonly = true\r\n }\r\n\r\n // Se è di tipo Object List non devo mostrarlo\r\n if (field.Reffered_Resource_Type == 1 || field.Is_Decode || field.Is_Identity) return\r\n\r\n // Questi campi vanno sempre ignorati e mai visualizzati\r\n if (field.FieldName == \"ts_update\" || field.FieldName == \"flg_isdeleted\" || field.FieldName == \"dat_ultvar\" || field.FieldName == \"customer_ID\") return\r\n \r\n // Qui scorro i fixed fields per trovare l'elenco dei campi non editabili\r\n if (this.props.fixedFields) {\r\n let i : number\r\n for (i=0; i\r\n
\r\n \r\n \r\n
\r\n \r\n \r\n {validationError}\r\n \r\n \r\n )\r\n }\r\n\r\n // Controllo se è un pdf e nel caso gli assegno il Field_Type 400\r\n if (field.Field_Type == 22 && field.ContentType == \"pdf\") field.Field_Type = 400 \r\n \r\n // Checkbox\r\n switch (field.Field_Type) {\r\n case 1:\r\n case 2:\r\n return (\r\n \r\n
\r\n \r\n \r\n
\r\n \r\n {validationError}\r\n \r\n \r\n )\r\n\r\n case 4:\r\n case 15:\r\n case 33:\r\n // Datetime\r\n return (\r\n \r\n
\r\n \r\n \r\n
\r\n \r\n {validationError}\r\n \r\n \r\n )\r\n case 31:\r\n // Date - Controllare MOMENT\r\n return (\r\n \r\n
\r\n \r\n \r\n
\r\n \r\n {validationError}\r\n \r\n \r\n )\r\n\r\n case 400:\r\n // PDF - Assegnato a monte\r\n // Creo il component per il PDF\r\n //return \r\n return ( \r\n \r\n
\r\n \r\n {validationError}\r\n \r\n \r\n )\r\n }\r\n }\r\n\r\n // Valida i campi e genera i messaggi da mostrare in tempo reale sotto al campo stesso\r\n validateField = (field: ResourceField) => {\r\n // TODO Lookup\r\n // Ritorna null se il campo è valido -> governa il tasto update\r\n // Come gestire la stringa vuota???\r\n var valueToCheck = this.state.myObject[field.FieldName]\r\n \r\n if (field.Is_Key && valueToCheck!==0 && valueToCheck!==false && valueToCheck===undefined) return (\r\n \r\n Questo campo è chiave e dunque obbligatorio\r\n \r\n ) \r\n if (!field.Is_Nullable && valueToCheck!==false && valueToCheck!==0 && valueToCheck===undefined) return (\r\n \r\n Questo campo non può essere nullo\r\n \r\n )\r\n\r\n if (field.Required && valueToCheck!==false && valueToCheck!==0 && (valueToCheck===undefined || valueToCheck=='')) return (\r\n \r\n Questo campo è obbligatorio\r\n \r\n )\r\n\r\n if (valueToCheck) {\r\n // Controllo la lunghezza\r\n if (field.Field_Size > 0 && valueToCheck.length > field.Field_Size) return (\r\n \r\n Questo campo supera la lunghezza massima consentita\r\n \r\n )\r\n //Se è un numero controllo che ci siano solo cifre\r\n if ((field.Field_Type == 0 || field.Field_Type == 5 || field.Field_Type == 6 || field.Field_Type == 8 || field.Field_Type == 13 ) && isNaN(valueToCheck)) return (\r\n \r\n Questo campo deve essere numerico\r\n \r\n )\r\n }\r\n \r\n return null*/\r\n }\r\n}\r\n","import React, { Component } from 'react'\r\nimport cubeApiClient from '../BusinessObjects/cubeApiService';\r\n\r\nimport LoggedContext from '../BusinessObjects/LoggedContext';\r\nimport ResourceField from '../Models/ResourceField';\r\nimport EsaedroResourceFilter from '../Models/EsaedroResourceFilter';\r\nimport EsaedroLookup from './EsaedroLookup';\r\nimport { renderGridObject } from '../Utils/EsaedroHelper';\r\nimport { themeEditButton, themeDeleteButton, themeNewButton, themeCol12xl, themeStripedTable, themeExpandButton, themeGroup, themeCol9, themeSpinner, themeFormInput } from '../Utils/EsaedroTheme';\r\nimport { Row, Col, Button, InputGroup, InputGroupAddon, Input, ButtonGroup, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';\r\nimport EsaedroPager from './EsaedroPager';\r\nimport EsaedroFilterConfig from './EsaedroFilterConfig';\r\n\r\ninterface EsaedroObjectListProps {\r\n myObjType: string;\r\n myObjUrl: string;\r\n myRowObjType?: string;\r\n myRowObjUrl?: string;\r\n myRowObjLinkFields?: string;\r\n onObjectEdit?(objectToEdit: any): void;\r\n onObjectDelete?(objectToDel: any): void;\r\n onObjectCreate?(): void;\r\n onInputFiltersUpdate?(filters: EsaedroResourceFilter[]): void\r\n onPageUpdate?(page: number): void\r\n navigationFilters?: EsaedroResourceFilter[];\r\n startingInputFilters?: EsaedroResourceFilter[];\r\n startingPage?: number;\r\n totalPages?: number;\r\n hideButtons?: boolean;\r\n hideFilters?: boolean;\r\n canCreate?: boolean;\r\n canUpdate?: boolean;\r\n canDelete?: boolean;\r\n}\r\n\r\ninterface EsaedroObjectsListState {\r\n myObjects: any[];\r\n myObjectsToDisplay: any[];\r\n myObjectFields: ResourceField[];\r\n myObjectInputFilters: EsaedroResourceFilter[];\r\n myObjectViewFilters: EsaedroResourceFilter[];\r\n toggleFilters: boolean;\r\n loading: boolean;\r\n errorMessage:string;\r\n}\r\n\r\nconst pageSize = 10\r\n\r\nexport default class EsaedroObjectsList extends Component {\r\n static contextType = LoggedContext\r\n context!: React.ContextType\r\n\r\n currentPage: number = 1\r\n totalPages: number = 1 \r\n\r\n constructor(props: EsaedroObjectListProps) {\r\n super(props);\r\n\r\n this.state = {\r\n myObjects: [],\r\n myObjectsToDisplay: [],\r\n myObjectFields: [],\r\n myObjectInputFilters: [],\r\n myObjectViewFilters: [],\r\n toggleFilters: false,\r\n loading: true,\r\n errorMessage: ''\r\n }\r\n }\r\n\r\n componentDidMount() {\r\n\r\n // La prima cosa che faccio è recuperare gli item della pagina 1\r\n this.getPageItems(this.props.startingPage?this.props.startingPage:1)\r\n }\r\n\r\n // Callback alla funzione di EsaedroContentPage per andare nell'edit dell'oggetto\r\n setItemToEdit = (item: any) => {\r\n if (this.props.onObjectEdit!=undefined) {\r\n this.props.onObjectEdit(item)\r\n }\r\n }\r\n\r\n // Callback alla funzione di EsaedroContentPage per andare nel delete dell'oggetto\r\n setItemToDelete = (item: any) => {\r\n if (this.props.onObjectDelete!=undefined) {\r\n this.props.onObjectDelete(item)\r\n }\r\n }\r\n\r\n // Callback alla funzione di EsaedroContentPage per andare nella creazione di un oggetto\r\n goToNewItem = () => {\r\n if (this.props.onObjectCreate!=undefined) {\r\n this.props.onObjectCreate()\r\n }\r\n }\r\n \r\n // Espande una testata mostrando le sue righe\r\n expandObject = (index: number) => {\r\n if (this.state.myObjectsToDisplay.length > index) {\r\n let newObjects = this.state.myObjectsToDisplay\r\n newObjects[index].Expanded = !newObjects[index].Expanded\r\n this.setState({myObjectsToDisplay: newObjects})\r\n }\r\n }\r\n\r\n // Chiama il servizio per ottenere gli item da mostrare in una determinata pagina, tenendo conto dei filtri\r\n getPageItems = (page: number) => {\r\n\r\n this.currentPage = page\r\n this.setState({loading: true})\r\n\r\n if (this.props.onPageUpdate!=undefined) {\r\n this.props.onPageUpdate(page)\r\n }\r\n\r\n const service = new cubeApiClient();\r\n const t = this.context.tokenAPI;\r\n\r\n let filterString = \"\"\r\n // Applico eventuali filtri da jump o menu di navigazione\r\n if (this.props.navigationFilters)\r\n {\r\n for(var i=0;i< this.props.navigationFilters.length;i++)\r\n {\r\n filterString += (i?\" and \":\"\") \r\n + this.props.navigationFilters[i].FieldName \r\n + this.props.navigationFilters[i].Operator \r\n + \"'\" + this.props.navigationFilters[i].Value + \"'\"\r\n }\r\n }\r\n\r\n // Applico anche i filtri eventuali impostati dalla maschera\r\n let filtersToAppend = ''\r\n // Prendo gli input filters dalle props o dallo stato a seconda del caso in cui ci troviamo\r\n let inputFilters = this.state.myObjectInputFilters.length\r\n ?this.state.myObjectInputFilters\r\n :this.props.startingInputFilters\r\n ?this.props.startingInputFilters\r\n :undefined\r\n if (inputFilters) {\r\n\r\n if (filterString>'') filtersToAppend = \" and \"\r\n\r\n let found = false\r\n inputFilters.forEach(element => {\r\n if (element.Value!='') {\r\n filtersToAppend += (found?\" and \":\"\") \r\n + 'lower('\r\n + element.FieldName\r\n + ')'\r\n + element.Operator \r\n + 'lower('\r\n + \"'%\" + element.Value + \"%'\"\r\n + ')'\r\n found = true\r\n }\r\n });\r\n\r\n if (!found) filtersToAppend = ''\r\n }\r\n\r\n // Aggiungo eventuali filtri della vista\r\n // TODO qui utilizzare l'oggetto EsaedroResourcesView e aggiungerla come parametro alla richiesta\r\n if (this.state.myObjectViewFilters) {\r\n\r\n let oldFiltersToAppend = filtersToAppend\r\n\r\n if (filtersToAppend>'') filtersToAppend += \" and \"\r\n else if (filterString>'') filtersToAppend = \" and \"\r\n\r\n let found = false\r\n this.state.myObjectViewFilters.forEach(element => {\r\n if (element.Value!='') {\r\n filtersToAppend += (found?\" and \":\"\") \r\n + 'lower('\r\n + element.FieldName\r\n + ')'\r\n + element.Operator \r\n + 'lower('\r\n + \"'%\" + element.Value + \"%'\"\r\n + ')'\r\n found = true\r\n }\r\n });\r\n\r\n if (!found) filtersToAppend = oldFiltersToAppend\r\n }\r\n \r\n const requrl = this.props.myObjUrl + ((filterString+filtersToAppend)>\"\"?'?RecordSelection=':'') + encodeURIComponent(filterString + filtersToAppend) + ((filterString+filtersToAppend)>\"\"?\"&PageSize=\"+pageSize+\"&PageNumber=\"+page:\"?PageSize=\"+pageSize+\"&PageNumber=\"+page)\r\n \r\n // Per debug\r\n //alert(requrl)\r\n\r\n service\r\n .getItems(requrl,t)\r\n .then((data: any) => {\r\n\r\n if (this.props.myRowObjType != undefined && this.props.myRowObjUrl != undefined) {\r\n // Se è un oggetto HeaderRow setto Expanded a false per tutti gli elementi\r\n data.forEach((element: any) => {\r\n element.Expanded = false\r\n });\r\n }\r\n\r\n if (data[0]) \r\n {\r\n this.totalPages = data[0].PageCount\r\n }\r\n else this.totalPages = 1\r\n\r\n this.setState({ myObjects: data, myObjectsToDisplay: data });\r\n const reqFieldsurl ='api/sys/ResourcesFields?RecordSelection=' + encodeURIComponent(\"ResourceName='\" + this.props.myObjType + \"' and Referred_Resource_ID is null and Is_Grid=1\") \r\n\r\n service\r\n .getItems(reqFieldsurl,t)\r\n .then((data: any) => {\r\n // In caso fossero vuoti li creo a partire dai resourceFields, altrimenti dalle props\r\n if (!this.state.myObjectInputFilters.length) this.createStartingInputFilters(data)\r\n this.setState({ \r\n myObjectFields: data, \r\n loading: false \r\n });\r\n },\r\n (error: any) => {\r\n this.setState({ \r\n myObjects: [], \r\n myObjectsToDisplay: [], \r\n loading: false, \r\n errorMessage: error \r\n });\r\n });\r\n\r\n },\r\n (error: any) => {\r\n this.setState({ \r\n myObjects: [], \r\n myObjectsToDisplay: [], \r\n loading: false, \r\n errorMessage: error \r\n });\r\n });\r\n }\r\n\r\n // Filtra gli oggetti ma solo di una lookup HARDCODED\r\n filterObjects = (e: any) => {\r\n // TODO mettere controllo e cercare di fare dinamico, funziona solo per il filtro fatto a mano tramite lookup\r\n let updateList = this.state.myObjects;\r\n\r\n updateList = updateList.filter(item => {\r\n return item.Resource_ID.toString().toLowerCase().search(\r\n e.target.value.toLowerCase()\r\n ) !== -1;\r\n });\r\n\r\n this.setState({\r\n myObjectsToDisplay: updateList\r\n });\r\n }\r\n\r\n // Crea i filtri in input iniziali: possono essere impostati da chi crea il component o vuoti in base alle proprietà con isGrid = 1\r\n createStartingInputFilters = (myFields: ResourceField[]) => {\r\n // Creo i filtri dalla property se settata\r\n if (this.props.startingInputFilters && this.props.startingInputFilters.length) {\r\n let newFilters : EsaedroResourceFilter[] = []\r\n this.props.startingInputFilters.forEach(filter => {\r\n newFilters.push(new EsaedroResourceFilter(filter.FieldName, filter.Value, filter.Operator, filter.description))\r\n });\r\n this.setState({myObjectInputFilters: newFilters})\r\n }\r\n // Altrimenti li creo vuoti\r\n else if (myFields.length){\r\n let myFilters: EsaedroResourceFilter[] = []\r\n myFields.map((field: ResourceField) => {\r\n if (field.Field_Type == 4 || \r\n field.Field_Type == 15 || \r\n field.Field_Type == 33) { \r\n myFilters.push(new EsaedroResourceFilter(field.FieldName, '', ' like ', field.Field_Label, \"datetime-local\"))\r\n }\r\n else if (field.Field_Type == 31) { \r\n myFilters.push(new EsaedroResourceFilter(field.FieldName, '', ' like ', field.Field_Label, \"date\"))\r\n }\r\n else myFilters.push(new EsaedroResourceFilter(field.FieldName, '', ' like '))\r\n })\r\n this.setState({myObjectInputFilters: myFilters})\r\n }\r\n }\r\n\r\n // Svuota i filtri in input e ricarica la vista chiamando gli item di pagina 1\r\n resetInputFilters = () => {\r\n this.state.myObjectInputFilters.forEach(element => {\r\n element.Value = ''\r\n });\r\n this.getPageItems(1)\r\n }\r\n\r\n // Fa l'update dei filtri in input (alla digitazione) senza però far partire nessun procedimento di filtraggio \r\n updateInputFilters = (e: any) => {\r\n let newFilters = this.state.myObjectInputFilters\r\n newFilters[e.target.max].Value = e.target.value\r\n this.setState({myObjectInputFilters: newFilters})\r\n }\r\n\r\n // Applica i filtri in input e chiama la pagina 1. Con un callback manda i filtri all'HistoryItem della EsaedroContentPage\r\n applyInputFilters = () => {\r\n this.getPageItems(1)\r\n if (this.props.onInputFiltersUpdate!=undefined) {\r\n this.props.onInputFiltersUpdate(this.state.myObjectInputFilters)\r\n }\r\n }\r\n\r\n toggleFilterBtnPressed = () => {\r\n this.setState({toggleFilters: !this.state.toggleFilters})\r\n }\r\n\r\n viewFiltersUpdated = (viewFilters?: EsaedroResourceFilter[], errorMessage?: string) => {\r\n // Torno dalla vista che ha settato i filtri. TODO save. Per ora li mando come parametro e ricarico pagina 1\r\n if (viewFilters) {\r\n this.setState({ myObjectViewFilters: viewFilters,\r\n toggleFilters: !this.state.toggleFilters,\r\n errorMessage:errorMessage?errorMessage:\"\" })\r\n \r\n this.getPageItems(1)\r\n }\r\n else if (errorMessage && errorMessage>\"\") {\r\n this.setState({ toggleFilters: !this.state.toggleFilters, errorMessage: errorMessage})\r\n } \r\n }\r\n\r\n render() {\r\n\r\n const { myObjectsToDisplay } = this.state;\r\n\r\n let toggleFilterButton = \r\n\r\n // TODO CHANGE Applica button con il fare qualcosa :D\r\n let filtersModal = \r\n Filtri Ricerca\r\n \r\n \r\n \r\n \r\n\r\n // Creo il pager\r\n let navigation = \r\n\r\n if (this.state.loading)\r\n {\r\n return (\r\n \r\n
\r\n Caricamento... \r\n \r\n \r\n )\r\n }\r\n\r\n // Il rendering si basa sempre sugli oggetti da mostrare\r\n if (myObjectsToDisplay && myObjectsToDisplay.length) {\r\n\r\n // Calcolo la size totale dei fields da mostrare\r\n var totalSize = 0\r\n this.state.myObjectFields.forEach((field: ResourceField) => {\r\n totalSize+=field.Field_Size\r\n })\r\n\r\n let objectsData = myObjectsToDisplay.map((item: any, index) => {\r\n\r\n // Splitto la stringa di campi su cui filtrare e creo gli EsaedroResourceFilter da mandare alla ObjectList delle rows\r\n var rowsFilters = undefined\r\n if (this.props.myRowObjLinkFields != undefined) {\r\n // Per ora metto uguale per tutti in questo caso. Capire se bisogna gestirla diversamente\r\n rowsFilters = []\r\n let rowsFiltersFields = this.props.myRowObjLinkFields.split(',')\r\n rowsFiltersFields.map(element => {\r\n rowsFilters.push(new EsaedroResourceFilter(element,item[element],\"=\"));\r\n });\r\n }\r\n // Per gli edit del detail, entrare in testata e poi fare edit da li\r\n let rows = (this.props.myRowObjType != undefined && this.props.myRowObjUrl != undefined) &&\r\n (item[this.props.myRowObjType] && item.Expanded) &&\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n // Creo i vari pulsanti in base ai parametri del component\r\n let buttons = undefined\r\n if (!this.props.hideButtons) {\r\n\r\n // Se l'oggetto non può essere modificato gli setto una property in più\r\n item.disableEdit = !this.props.canUpdate\r\n\r\n let editButton = this.props.canUpdate ?\r\n \r\n : \r\n \r\n let deleteButton = this.props.canDelete &&\r\n \r\n \r\n let expandButton = (this.props.myRowObjType && this.props.myRowObjUrl) &&\r\n \r\n \r\n buttons =
\r\n {item.Expanded?rows:undefined}\r\n \r\n )});\r\n // Filtro per le maschere - HardCoded. Da mettere tramite struttura dei Menu\r\n let filterLookup = this.props.myObjType==\"ResourcesFields\"\r\n ? \r\n : ''\r\n\r\n let contents = this.state.loading\r\n ?
Loading...
\r\n : objectsData;\r\n\r\n let newItem = !this.props.hideButtons && this.props.canCreate\r\n ?
\r\n : undefined\r\n }\r\n {!this.props.hideFilters\r\n ? this.state.myObjectInputFilters.map((filter: EsaedroResourceFilter, index) => {\r\n // Qui gestire filtri di altro tipo\r\n return (\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n
\r\n )\r\n })\r\n : undefined\r\n }\r\n
\r\n \r\n {contents}\r\n {navigation}\r\n
\r\n
\r\n
\r\n
\r\n )\r\n }\r\n else {\r\n return (\r\n
\r\n
\r\n Non ci sono dati da visualizzare\r\n
\r\n
\r\n )\r\n }\r\n }\r\n}\r\n\r\n\r\n","\r\nimport EsaedroResourceFilter from '../Models/EsaedroResourceFilter';\r\nimport ResourceField from '../Models/ResourceField';\r\nimport React from 'react'\r\nimport moment from 'moment'\r\n\r\nexport function isFilterable(objToFilter: any, filter: EsaedroResourceFilter): boolean {\r\n // Forse sto metodo non serve... \r\n if (filter.FieldName in objToFilter) return true\r\n\r\n return false\r\n}\r\n\r\nexport function renderGridObject(field: ResourceField, item: any, index: number, totalSize: number, totalFields: number): any {\r\n // Calcolo la percentuale sulla base di fieldSize e totalSize e poi la imposto come larghezza ai campi\r\n let margin = 50\r\n totalSize = totalSize+margin*totalFields\r\n var cellWidth: string = (field.Field_Size+margin)/totalSize*100 + '%'\r\n\r\n if (field.FieldName == \"num_giorno\" ) {\r\n switch(item[field.FieldName]) {\r\n case 1:\r\n return (\r\n
Lunedi
\r\n )\r\n case 2:\r\n return (\r\n
Martedi
\r\n )\r\n case 3:\r\n return (\r\n
Mercoledi
\r\n )\r\n case 4:\r\n return (\r\n
Giovedi
\r\n )\r\n case 5:\r\n return (\r\n
Venerdi
\r\n )\r\n case 6:\r\n return (\r\n
Sabato
\r\n )\r\n case 7:\r\n return (\r\n
Domenica
\r\n )\r\n }\r\n }\r\n\r\n switch (field.Field_Type) {\r\n case 1:\r\n if (item[field.FieldName])\r\n return (\r\n
True
\r\n )\r\n else return (\r\n
False
\r\n )\r\n case 2:\r\n if (item[field.FieldName])\r\n return (\r\n
True
\r\n )\r\n else return (\r\n
False
\r\n )\r\n // Gestisco i DateTime\r\n case 4:\r\n case 15:\r\n case 33:\r\n return (\r\n
\r\n )\r\n }\r\n}\r\n ","import React, { Component } from 'react'\r\nimport { Button, NavItem, Nav, NavLink } from 'reactstrap';\r\n\r\nimport '../App.css';\r\nimport LoggedContext from '../BusinessObjects/LoggedContext'\r\nimport EsaedroHistoryItem from '../Models/EsaedroHistoryItem';\r\n\r\n\r\ninterface IEsaedroMenuHistoryProps {\r\n name:string;\r\n className:string;\r\n onClick?(menuItemId: any): void;\r\n items: EsaedroHistoryItem[]\r\n}\r\n\r\nexport default class EsaedroMenuHistory extends Component {\r\n static contextType = LoggedContext\r\n\r\n incrementalKey = 0\r\n \r\n constructor(props: IEsaedroMenuHistoryProps){\r\n super(props);\r\n\r\n this.historyMenuItemSelected = this.historyMenuItemSelected.bind(this)\r\n }\r\n\r\n historyMenuItemSelected(e: any) {\r\n if (this.props.onClick!=undefined) {\r\n this.props.onClick(e.target.value)\r\n }\r\n }\r\n\r\n render() {\r\n \r\n this.incrementalKey++\r\n if (!this.props.items.length)\r\n {\r\n return (\r\n \r\n \r\n )\r\n }\r\n else\r\n {\r\n const historyBar = (this.props.items!==undefined? this.props.items.map((menuVoice: any, i , voices) => {\r\n if (voices.length-1 === i)\r\n return (\r\n \r\n {menuVoice.selectedItem.Description}\r\n \r\n )\r\n else return (\r\n \r\n / \r\n \r\n ) \r\n }\r\n ):'Nessuno storico...');\r\n\r\n return (\r\n \r\n )\r\n }\r\n }\r\n}\r\n ","import React, { Component } from 'react'\r\nimport { Button } from 'reactstrap';\r\nimport '../App.css';\r\nimport LoggedContext from '../BusinessObjects/LoggedContext'\r\n\r\n\r\ninterface IEsaedroJumpMenuProps {\r\n name:string;\r\n className:string;\r\n onClick?(menuItemId: any): void;\r\n items: any[]\r\n}\r\n\r\nexport default class EsaedroJumpMenu extends Component {\r\n \r\n constructor(props: IEsaedroJumpMenuProps){\r\n super(props);\r\n\r\n }\r\n\r\n jumpMenuItemSelected = (e: any) => {\r\n if (this.props.onClick!=undefined) {\r\n this.props.onClick(e.target.value)\r\n }\r\n }\r\n\r\n render() {\r\n\r\n if (this.props.items.length) {\r\n const elements = (this.props.items!==undefined? this.props.items.map((menuVoice: any) => {\r\n return (\r\n \r\n )\r\n }\r\n ):'Errore: non ci sono elementi da visualizzare...');\r\n\r\n return (\r\n
\r\n {elements} \r\n
\r\n )\r\n }\r\n else return (\r\n
\r\n
\r\n )\r\n }\r\n}\r\n ","import EsaedroResourceFilter from \"./EsaedroResourceFilter\";\r\n\r\nclass EsaedroHistoryItem {\r\n setSelectedItemFilters(filters: EsaedroResourceFilter[]) {\r\n throw new Error(\"Method not implemented.\");\r\n }\r\n\r\n private _selectedItem: any;\r\n public get selectedItem() : any { return this._selectedItem } \r\n public set selectedItem(newvalue: any) { this._selectedItem = newvalue }\r\n\r\n private _itemToEdit: any;\r\n public get itemToEdit() : any { return this._itemToEdit } \r\n public set itemToEdit(newvalue: any) { this._itemToEdit = newvalue }\r\n\r\n private _itemToDel: any;\r\n public get itemToDel() : any { return this._itemToDel } \r\n public set itemToDel(newvalue: any) { this._itemToDel = newvalue }\r\n\r\n private _itemToJump: any;\r\n public get itemToJump() : any { return this._itemToJump } \r\n public set itemToJump(newvalue: any) { this._itemToJump = newvalue }\r\n\r\n private _newItem: boolean = false;\r\n public get newItem() : boolean { return this._newItem } \r\n public set newItem(newvalue: boolean) { this._newItem = newvalue }\r\n\r\n private _menuItems: any[] = [];\r\n public get menuItems() : any[] { return this._menuItems } \r\n public set menuItems(newvalue: any[]) { this._menuItems = newvalue }\r\n\r\n private _jumpMenuItems: any[] = [];\r\n public get jumpMenuItems() : any[] { return this._jumpMenuItems } \r\n public set jumpMenuItems(newvalue: any[]) { this._jumpMenuItems = newvalue }\r\n\r\n private _selectedItemFilters: EsaedroResourceFilter[] = [];\r\n public get selectedItemFilters() : EsaedroResourceFilter[] { return this._selectedItemFilters } \r\n public set selectedItemFilters(newvalue: EsaedroResourceFilter[]) { this._selectedItemFilters = newvalue }\r\n\r\n private _listInputFilters: EsaedroResourceFilter[] = [];\r\n public get listInputFilters() : EsaedroResourceFilter[] { return this._listInputFilters } \r\n public set listInputFilters(newvalue: EsaedroResourceFilter[]) { this._listInputFilters = newvalue }\r\n\r\n private _startingPage: number = 1;\r\n public get startingPage() : number { return this._startingPage } \r\n public set startingPage(newvalue: number) { this._startingPage = newvalue }\r\n\r\n private _customComponentName: string = '';\r\n public get customComponentName() : string { return this._customComponentName } \r\n public set customComponentName(newvalue: string) { this._customComponentName = newvalue }\r\n\r\n /**\r\n * clearDetailState\r\n */\r\n public clearDetailState() {\r\n this.itemToEdit= undefined, \r\n this.itemToDel= undefined, \r\n this.newItem=false\r\n }\r\n\r\n /**\r\n * clearJumpState\r\n */\r\n public clearJumpState() {\r\n this.itemToJump= undefined\r\n }\r\n\r\n /**\r\n * cloneSelf\r\n */\r\n public cloneSelf() : EsaedroHistoryItem {\r\n\r\n let objToRet = new EsaedroHistoryItem ({})\r\n\r\n objToRet.selectedItem = Object.assign({},this.selectedItem)\r\n objToRet.itemToEdit=Object.assign({},this.itemToEdit)\r\n objToRet.itemToDel=Object.assign({},this.itemToDel)\r\n objToRet.itemToJump=Object.assign({},this.itemToJump)\r\n objToRet.newItem=this.newItem\r\n objToRet.startingPage=this.startingPage\r\n objToRet.customComponentName=this.customComponentName\r\n \r\n if (this.menuItems.length) {\r\n let newMenuItems: any[] = []\r\n this.menuItems.forEach(element => {\r\n newMenuItems.push(Object.assign({},element))\r\n });\r\n objToRet.menuItems=newMenuItems\r\n }\r\n if (this.jumpMenuItems.length) {\r\n let newJumpMenuItems: any[] = []\r\n this.jumpMenuItems.forEach(element => {\r\n newJumpMenuItems.push(Object.assign({},element))\r\n });\r\n objToRet.jumpMenuItems=newJumpMenuItems\r\n }\r\n\r\n if (this.selectedItemFilters.length) {\r\n let newSelectedItemFilters: EsaedroResourceFilter[] = []\r\n this.selectedItemFilters.forEach(element => {\r\n newSelectedItemFilters.push(new EsaedroResourceFilter(element.FieldName, element.Value, element.Operator, element.description))\r\n });\r\n objToRet.selectedItemFilters=newSelectedItemFilters\r\n }\r\n\r\n if (this.listInputFilters.length) {\r\n let newListInputFilters: EsaedroResourceFilter[] = []\r\n this.listInputFilters.forEach(element => {\r\n newListInputFilters.push(new EsaedroResourceFilter(element.FieldName, element.Value, element.Operator, element.description))\r\n });\r\n objToRet.listInputFilters=newListInputFilters\r\n }\r\n\r\n return objToRet\r\n }\r\n\r\n constructor(selectedItem: any, \r\n itemToEdit?: any, \r\n itemToDel?: any, \r\n itemToJump?: any, \r\n newItem?: boolean, \r\n menuItems?: any[], \r\n jumpMenuItems?: any[], \r\n selectedItemFilters?: EsaedroResourceFilter[], \r\n listInputFilters?: EsaedroResourceFilter[], \r\n startingPage?: number,\r\n customComponentName?: string\r\n ) {\r\n\r\n this.selectedItem=selectedItem\r\n this.itemToEdit=itemToEdit\r\n this.itemToDel=itemToDel\r\n this.itemToJump=itemToJump\r\n this.newItem=newItem?newItem:false\r\n this.menuItems=menuItems?menuItems:[]\r\n this.jumpMenuItems=jumpMenuItems?jumpMenuItems:[]\r\n this.selectedItemFilters=selectedItemFilters?selectedItemFilters:[]\r\n this.listInputFilters=listInputFilters?listInputFilters:[]\r\n this.startingPage=startingPage?startingPage:1\r\n this.customComponentName=customComponentName?customComponentName:''\r\n }\r\n\r\n}\r\n\r\nexport default EsaedroHistoryItem;","import React, { Component } from 'react'\r\nimport { Row, Col, UncontrolledAlert } from 'reactstrap';\r\nimport '../App.css';\r\nimport LoggedContext from '../BusinessObjects/LoggedContext'\r\nimport cubeApiClient from '../BusinessObjects/cubeApiService';\r\nimport EsaedroMenu from './EsaedroMenu';\r\nimport EsaedroObjectsList from './EsaedroObjectsList';\r\nimport EsaedroObjectEdit from './EsaedroObjectEdit';\r\nimport EsaedroObjectDelete from './EsaedroObjectDelete';\r\nimport EsaedroMenuHistory from './EsaedroMenuHistory';\r\nimport EsaedroJumpMenu from './EsaedroJumpMenu';\r\nimport EsaedroResourceFilter from '../Models/EsaedroResourceFilter';\r\nimport { themeCol9, themeGroup, themeSpinner } from '../Utils/EsaedroTheme';\r\nimport EsaedroHistoryItem from '../Models/EsaedroHistoryItem';\r\n\r\n\r\ninterface IEsaedroContentPageProps {\r\n name?:string\r\n className?:string\r\n onChange?(event: any): void\r\n}\r\ninterface IEsaedroContentPageState\r\n{\r\n menuHistory: EsaedroHistoryItem[];\r\n selectedHistoryItem: EsaedroHistoryItem\r\n loading: boolean\r\n errorMessage: string\r\n successMessage: string\r\n}\r\n\r\nexport default class EsaedroContentPage extends Component {\r\n static contextType = LoggedContext\r\n context!: React.ContextType\r\n\r\n // Utilizzato per forzare il rendering quando si clicca su una menuHistory\r\n incrementalKey: number = 0\r\n\r\n constructor(props: IEsaedroContentPageProps){\r\n super(props);\r\n\r\n // Creo la home manualmente, un item fittizio con Id = 0\r\n let homeHistoryItem = new EsaedroHistoryItem({Description: \"Home\", Id: \"0\"})\r\n this.state={\r\n selectedHistoryItem: homeHistoryItem,\r\n menuHistory:[homeHistoryItem], \r\n loading:true,\r\n errorMessage:'',\r\n successMessage:''\r\n };\r\n }\r\n\r\n componentDidMount()\r\n {\r\n if (!this.state.selectedHistoryItem.menuItems.length)\r\n {\r\n const service = new cubeApiClient();\r\n const t = this.context.tokenAPI;\r\n var requrl =\"api/sys/MenuItems?RecordSelection=ParentMenuId is null\" \r\n\r\n // Controllo se ho un token di autorizzazione\r\n if (t != \"\")\r\n {\r\n service\r\n .getItems(requrl,t)\r\n .then((data: any) => {\r\n\r\n // Creo il Menu iniziale\r\n if (data)\r\n {\r\n this.setState(prevState => ({\r\n ...prevState.selectedHistoryItem.menuItems=data,\r\n loading:false\r\n })) \r\n }\r\n else this.setState({\r\n loading: false, \r\n errorMessage: \"Si è verificato un problema nello scaricare i dati.\"\r\n })\r\n },\r\n (error: any) => {\r\n this.setState({ \r\n loading: false, \r\n errorMessage: error \r\n });\r\n });\r\n }\r\n \r\n // Non ho un token valido quindi devo rifare il login\r\n else {\r\n this.setState({\r\n loading: false, \r\n errorMessage: \"Si prega di effettuare il login.\"\r\n })\r\n }\r\n \r\n }\r\n }\r\n\r\n onMenuClick = (id: any) => {\r\n // Recupero la voce di menu cliccata. Non è posizionale ma si basa sull'Id. Si può cambiare? Conviene?\r\n let selectedVoices : any = this.state.selectedHistoryItem.menuItems[0].Id\r\n ? this.state.selectedHistoryItem.menuItems.filter(item => (item.Id == id))\r\n : undefined\r\n if (selectedVoices!=undefined && selectedVoices.length > 0) {\r\n\r\n this.setState({\r\n loading: true,\r\n successMessage:'',\r\n errorMessage:''\r\n })\r\n const service = new cubeApiClient();\r\n const t = this.context.tokenAPI;\r\n let voiceID = selectedVoices[0].Id\r\n ? selectedVoices[0].Id.toString()\r\n : undefined\r\n\r\n if (voiceID) {\r\n\r\n var requrl =\"api/sys/MenuItems?RecordSelection=ParentMenuId=\" + voiceID ; \r\n \r\n service\r\n .getItems(requrl,t)\r\n .then((data: any) => {\r\n // Creo il nuovo HistoryItem, con relativo Menu, lo aggiungo allo storico e lo rendo attivo\r\n if (data)\r\n {\r\n let newSelectedItem = new EsaedroHistoryItem(selectedVoices[0])\r\n // gli setto il customComponent se presente\r\n newSelectedItem.customComponentName = newSelectedItem.selectedItem.CustomEditComponent\r\n newSelectedItem.menuItems=data\r\n this.setState(prevState => ({\r\n selectedHistoryItem: newSelectedItem,\r\n menuHistory: [...prevState.menuHistory, newSelectedItem],\r\n loading:false\r\n })) \r\n }\r\n \r\n else this.setState({\r\n loading: false, \r\n errorMessage: \"Si è verificato un problema nello scaricare i dati del Menu.\"\r\n })\r\n },\r\n (error: any) => {\r\n this.setState({ \r\n loading: false, \r\n errorMessage: error \r\n });\r\n });\r\n }\r\n else {\r\n this.setState({ \r\n loading: false, \r\n errorMessage: \"Si è verificato un errore nel recuperare le voci di menu\" \r\n });\r\n }\r\n \r\n }\r\n else \r\n {\r\n this.setState({ \r\n loading: false, \r\n errorMessage: \"Si è verificato un errore nel recuperare le voci di menu\" \r\n });\r\n }\r\n }\r\n\r\n onMenuHistoryClick = (id: any) => {\r\n\r\n /***********************************************************************\r\n Un piccolo passo per il codice, un grande passo per l'umanità\r\n Questo semplice incrementale, che va propagato su TUTTI gli \r\n oggetti figli della content page e passato alla loro property key,\r\n fa si che ogni volta che si clicchi su uno history il componente \r\n figlio faccia un'unmount e una mount, ricaricando \r\n tutti i dati in maniera corretta\r\n ***********************************************************************/\r\n this.incrementalKey++\r\n\r\n // Recupero la voce di menu history cliccata. Non è posizionale ma si basa sull'Id. Si può cambiare? Conviene?\r\n let selectedVoices : any = this.state.menuHistory[0].selectedItem.Id\r\n ? this.state.menuHistory.filter(item => (item.selectedItem.Id == id))\r\n : undefined\r\n \r\n if (selectedVoices!=undefined) {\r\n\r\n this.setState({\r\n loading: true,\r\n successMessage:'',\r\n errorMessage:''\r\n })\r\n // Creo un nuovo array come HisoryMenu, e gli aggiungo tutte le voci di history menu sino alla selezionata\r\n let i: number\r\n let newHistory: EsaedroHistoryItem[] = []\r\n for (i=0; i {\r\n\r\n // Recupero la voce di menu jump cliccata. Non è posizionale ma si basa sul JumpName. Si può cambiare? Conviene?\r\n let selectedVoices : any = this.state.selectedHistoryItem.jumpMenuItems.filter(item => (item.JumpName == jumpName))\r\n if (selectedVoices!=undefined) {\r\n \r\n // Clono l'HistoryItem in cui mi trovavo e aggiungo le informazioni relative al salto\r\n let newHistoryItem = this.state.selectedHistoryItem.cloneSelf()\r\n newHistoryItem.itemToJump=selectedVoices[0]\r\n //alert(JSON.stringify(selectedVoices[0]))\r\n newHistoryItem.jumpMenuItems=[]\r\n\r\n // Qui creo gli EsaedroResourceFilters da mettere come selectedItemFilters - Al momento non gestiamo la description\r\n let itemFilters: EsaedroResourceFilter[] = []\r\n if (selectedVoices[0].ResourcesJumpFilters) {\r\n selectedVoices[0].ResourcesJumpFilters.forEach((element: { DestinationFieldName: string, SourceFieldName: string; FilterOperator: string; }) => {\r\n itemFilters.push(new EsaedroResourceFilter(element.DestinationFieldName, newHistoryItem.itemToEdit[element.SourceFieldName] ,element.FilterOperator))\r\n });\r\n }\r\n newHistoryItem.selectedItemFilters=itemFilters\r\n\r\n // Resetto gli altri oggetti di stato\r\n newHistoryItem.itemToEdit=undefined\r\n newHistoryItem.itemToDel=undefined\r\n newHistoryItem.newItem=false\r\n\r\n // Metto la starting page a 1 per le liste successive che partiranno da questa\r\n newHistoryItem.startingPage=1\r\n\r\n // Salvo il customComponentName in caso ci sia\r\n newHistoryItem.customComponentName = newHistoryItem.itemToJump.DestinationCustomEditComponent\r\n\r\n // Setto correttamente le varie proprietà del nuovo SelectedItem\r\n newHistoryItem.selectedItem.Id=newHistoryItem.selectedItem.Id+\"_\"+jumpName\r\n newHistoryItem.selectedItem.Description=selectedVoices[0].JumpLabel\r\n newHistoryItem.selectedItem.ResourceName=selectedVoices[0].DestinationResourceName\r\n newHistoryItem.selectedItem.EndPoint=selectedVoices[0].DestinationEndPoint\r\n\r\n // Aggiungo il nuovo History Item alla menu history e imposto il nuovo Item come attivo\r\n this.setState(prevState => ({\r\n selectedHistoryItem: newHistoryItem,\r\n menuHistory: [...prevState.menuHistory, newHistoryItem],\r\n successMessage:'',\r\n errorMessage:''\r\n }))\r\n }\r\n }\r\n\r\n OnEditClick = (objToEdit: any) => {\r\n \r\n this.setState({\r\n loading: true,\r\n successMessage:'',\r\n errorMessage:''\r\n })\r\n const service = new cubeApiClient();\r\n const t = this.context.tokenAPI;\r\n var requrl =\"api/sys/ResourcesJumps?RecordSelection=SourceResourceName='\" + this.state.selectedHistoryItem.selectedItem.ResourceName +\"'\" ; \r\n\r\n let jumpItems: EsaedroResourceFilter[] = []\r\n service\r\n .getItems(requrl,t)\r\n .then((data: any) => {\r\n // Creo il nuovo HistoryItem, con relativo JumpMenu, lo aggiungo allo storico e lo rendo attivo\r\n if (data)\r\n {\r\n jumpItems = data\r\n }\r\n \r\n // Come prima cosa clono il mio selectedItem\r\n let newHistoryItem = this.state.selectedHistoryItem.cloneSelf()\r\n newHistoryItem.itemToEdit=objToEdit\r\n // Svuoto eventuali filtri in input che possono essere stati clonati\r\n newHistoryItem.listInputFilters=[]\r\n // Gli aggiungo eventuali jumpItems recuperati dal servizio\r\n newHistoryItem.jumpMenuItems=jumpItems\r\n // Metto la starting page a 1 per le liste successive che partiranno da questa\r\n newHistoryItem.startingPage=1\r\n \r\n // Aggiungo la voce all'history menu e poi setto questo item come selectedItem\r\n newHistoryItem.selectedItem.Id=newHistoryItem.selectedItem.Id+\"_\"+objToEdit.Id\r\n newHistoryItem.selectedItem.Description=newHistoryItem.selectedItem.Description+\" - Dettaglio\"\r\n this.setState(prevState => ({\r\n selectedHistoryItem: newHistoryItem,\r\n menuHistory: [...prevState.menuHistory, newHistoryItem],\r\n loading: false\r\n }))\r\n\r\n },\r\n (error: any) => {\r\n this.setState({ \r\n loading: false, \r\n errorMessage: error \r\n });\r\n }); \r\n }\r\n\r\n OnDeleteClick = (objToDelete: any) => {\r\n let newHistoryItem = this.state.selectedHistoryItem.cloneSelf()\r\n // Setto le nuove proprietà al mio history object\r\n newHistoryItem.itemToEdit=undefined\r\n newHistoryItem.itemToDel=objToDelete\r\n newHistoryItem.newItem=false\r\n // Aggiungo la voce all'history menu e poi setto questo item come selectedItem\r\n newHistoryItem.selectedItem.Id=newHistoryItem.selectedItem.Id+\"_DEL\"\r\n newHistoryItem.selectedItem.Description=\"Elimina \" + newHistoryItem.selectedItem.Description\r\n this.setState(prevState => ({\r\n selectedHistoryItem: newHistoryItem,\r\n menuHistory: [...prevState.menuHistory, newHistoryItem],\r\n successMessage:'',\r\n errorMessage:''\r\n }))\r\n }\r\n\r\n OnReturnToList = (returnMessage?: string) => {\r\n this.popLastHistoryItemAndUpdateSelected(returnMessage)\r\n }\r\n\r\n popLastHistoryItemAndUpdateSelected = (returnMessage?:string) => {\r\n let newHistory = this.state.menuHistory\r\n newHistory.pop()\r\n this.setState({\r\n menuHistory: newHistory, \r\n selectedHistoryItem: newHistory[newHistory.length-1],\r\n successMessage:returnMessage?returnMessage:'',\r\n errorMessage:''\r\n })\r\n }\r\n\r\n OnNewItem = () => {\r\n let newHistoryItem = this.state.selectedHistoryItem.cloneSelf()\r\n // Setto le nuove proprietà al mio history object\r\n newHistoryItem.itemToEdit=undefined\r\n newHistoryItem.itemToDel=undefined\r\n newHistoryItem.newItem=true\r\n // Metto la starting page a 1 per le liste successive che partiranno da questa\r\n newHistoryItem.startingPage=1\r\n // Aggiungo la voce all'history menu e poi setto questo item come selectedItem\r\n newHistoryItem.selectedItem.Id=newHistoryItem.selectedItem.Id+\"_NEW\"\r\n newHistoryItem.selectedItem.Description=\"Crea \" + newHistoryItem.selectedItem.Description\r\n this.setState(prevState => ({\r\n selectedHistoryItem: newHistoryItem,\r\n menuHistory: [...prevState.menuHistory, newHistoryItem],\r\n successMessage:'',\r\n errorMessage:''\r\n }))\r\n }\r\n\r\n OnListFiltersUpdate = (filters: EsaedroResourceFilter[]) => {\r\n let newFilters : EsaedroResourceFilter[] = []\r\n filters.forEach(filter => {\r\n newFilters.push(new EsaedroResourceFilter(filter.FieldName, filter.Value, filter.Operator, filter.description))\r\n });\r\n this.state.selectedHistoryItem.listInputFilters = newFilters\r\n }\r\n\r\n OnListPageUpdate = (newPage: number) => {\r\n this.state.selectedHistoryItem.startingPage = newPage\r\n }\r\n\r\n clearDetailState = () => {\r\n this.setState({\r\n loading: true,\r\n successMessage:'',\r\n errorMessage:''})\r\n this.state.selectedHistoryItem.clearDetailState()\r\n this.setState({loading: false})\r\n }\r\n\r\n clearJumpState = () => {\r\n this.setState({\r\n loading: true,\r\n successMessage:'',\r\n errorMessage:''\r\n })\r\n this.state.selectedHistoryItem.clearJumpState()\r\n this.setState({loading: false})\r\n }\r\n\r\n render() {\r\n\r\n if (this.state.loading)\r\n {\r\n return (\r\n \r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n )\r\n }\r\n}\r\n","import React, { Component } from 'react';\r\nimport { Container } from 'reactstrap';\r\nimport { AppRoutes } from './Routes';\r\nimport EsaedroNavigationBar from './Components/EsaedroNavigationBar'\r\nimport { BrowserRouter } from 'react-router-dom';\r\nimport { ApplicationInsights } from '@microsoft/applicationinsights-web'\r\nimport LoggedContext from './BusinessObjects/LoggedContext'\r\nimport UserProfile from './Models/UserProfile';\r\nconst appInsights = new ApplicationInsights({ config: {\r\n instrumentationKey: '3759d2b0-c01c-466d-85ed-82a223cbbb8a'\r\n /* ...Other Configuration Options... */\r\n} });\r\n\r\nclass LoggedComponent extends Component {\r\n state = {\r\n username : '',\r\n tokenAPI:'',\r\n userProfile:null,\r\n selectedItem:null,\r\n selectedMenuItem:null,\r\n setUserToken: (UserName:string,TokenAPI:string) => {\r\n this.setState({username: UserName, tokenAPI:TokenAPI})\r\n },\r\n setUserProfile:(user:UserProfile) => {\r\n this.setState({userProfile: user})\r\n },\r\n setSelectedItem:(item:any) => {\r\n this.setState({selectedItem: item})\r\n },\r\n setSelectedMenuItem:(item:any) => {\r\n this.setState({selectedMenuItem: item})\r\n }\r\n \r\n }\r\n \r\n render() {\r\n return \r\n {this.props.children}\r\n \r\n }\r\n}\r\nappInsights.loadAppInsights();\r\n\r\nclass App extends Component {\r\n constructor(props:any)\r\n {\r\n super(props);\r\n\r\n \r\n }\r\n\r\n render() {\r\n\r\n return ( \r\n \r\n \r\n \r\n \r\n {AppRoutes}\r\n \r\n \r\n \r\n );\r\n }\r\n}\r\n\r\nexport default App;","// This optional code is used to register a service worker.\r\n// register() is not called by default.\r\n\r\n// This lets the app load faster on subsequent visits in production, and gives\r\n// it offline capabilities. However, it also means that developers (and users)\r\n// will only see deployed updates on subsequent visits to a page, after all the\r\n// existing tabs open on the page have been closed, since previously cached\r\n// resources are updated in the background.\r\n\r\n// To learn more about the benefits of this model and instructions on how to\r\n// opt-in, read https://bit.ly/CRA-PWA\r\n\r\nconst isLocalhost = Boolean(\r\n window.location.hostname === 'localhost' ||\r\n // [::1] is the IPv6 localhost address.\r\n window.location.hostname === '[::1]' ||\r\n // 127.0.0.1/8 is considered localhost for IPv4.\r\n window.location.hostname.match(\r\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\r\n )\r\n);\r\n\r\ntype Config = {\r\n onSuccess?: (registration: ServiceWorkerRegistration) => void;\r\n onUpdate?: (registration: ServiceWorkerRegistration) => void;\r\n};\r\n\r\nexport function register(config?: Config) {\r\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\r\n // The URL constructor is available in all browsers that support SW.\r\n const publicUrl = new URL(\r\n (process as { env: { [key: string]: string } }).env.PUBLIC_URL,\r\n window.location.href\r\n );\r\n if (publicUrl.origin !== window.location.origin) {\r\n // Our service worker won't work if PUBLIC_URL is on a different origin\r\n // from what our page is served on. This might happen if a CDN is used to\r\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\r\n return;\r\n }\r\n\r\n window.addEventListener('load', () => {\r\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\r\n\r\n if (isLocalhost) {\r\n // This is running on localhost. Let's check if a service worker still exists or not.\r\n checkValidServiceWorker(swUrl, config);\r\n\r\n // Add some additional logging to localhost, pointing developers to the\r\n // service worker/PWA documentation.\r\n navigator.serviceWorker.ready.then(() => {\r\n console.log(\r\n 'This web app is being served cache-first by a service ' +\r\n 'worker. To learn more, visit https://bit.ly/CRA-PWA'\r\n );\r\n });\r\n } else {\r\n // Is not localhost. Just register service worker\r\n registerValidSW(swUrl, config);\r\n }\r\n });\r\n }\r\n}\r\n\r\nfunction registerValidSW(swUrl: string, config?: Config) {\r\n navigator.serviceWorker\r\n .register(swUrl)\r\n .then(registration => {\r\n registration.onupdatefound = () => {\r\n const installingWorker = registration.installing;\r\n if (installingWorker == null) {\r\n return;\r\n }\r\n installingWorker.onstatechange = () => {\r\n if (installingWorker.state === 'installed') {\r\n if (navigator.serviceWorker.controller) {\r\n // At this point, the updated precached content has been fetched,\r\n // but the previous service worker will still serve the older\r\n // content until all client tabs are closed.\r\n console.log(\r\n 'New content is available and will be used when all ' +\r\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\r\n );\r\n\r\n // Execute callback\r\n if (config && config.onUpdate) {\r\n config.onUpdate(registration);\r\n }\r\n } else {\r\n // At this point, everything has been precached.\r\n // It's the perfect time to display a\r\n // \"Content is cached for offline use.\" message.\r\n console.log('Content is cached for offline use.');\r\n\r\n // Execute callback\r\n if (config && config.onSuccess) {\r\n config.onSuccess(registration);\r\n }\r\n }\r\n }\r\n };\r\n };\r\n })\r\n .catch(error => {\r\n console.error('Error during service worker registration:', error);\r\n });\r\n}\r\n\r\nfunction checkValidServiceWorker(swUrl: string, config?: Config) {\r\n // Check if the service worker can be found. If it can't reload the page.\r\n fetch(swUrl)\r\n .then(response => {\r\n // Ensure service worker exists, and that we really are getting a JS file.\r\n const contentType = response.headers.get('content-type');\r\n if (\r\n response.status === 404 ||\r\n (contentType != null && contentType.indexOf('javascript') === -1)\r\n ) {\r\n // No service worker found. Probably a different app. Reload the page.\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister().then(() => {\r\n window.location.reload();\r\n });\r\n });\r\n } else {\r\n // Service worker found. Proceed as normal.\r\n registerValidSW(swUrl, config);\r\n }\r\n })\r\n .catch(() => {\r\n console.log(\r\n 'No internet connection found. App is running in offline mode.'\r\n );\r\n });\r\n}\r\n\r\nexport function unregister() {\r\n if ('serviceWorker' in navigator) {\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister();\r\n });\r\n }\r\n}\r\n","import React from 'react';\r\nimport ReactDOM from 'react-dom';\r\nimport 'jquery';\r\nimport './index.css';\r\nimport 'bootstrap'\r\nimport 'bootstrap/dist/css/bootstrap.css';\r\nimport App from './App';\r\nimport * as serviceWorker from './serviceWorker';\r\n\r\n\r\nReactDOM.render(\r\n \r\n ,\r\n document.getElementById('root')\r\n);\r\n\r\n// If you want your app to work offline and load faster, you can change\r\n// unregister() to register() below. Note this comes with some pitfalls.\r\n// Learn more about service workers: https://bit.ly/CRA-PWA\r\nserviceWorker.unregister();\r\n","\r\nexport function themeGroup () { return \"form-group\" }\r\nexport function themeEditButton() { return \"btn btn-info btn-sm\" }\r\nexport function themeBackButton() { return \"btn btn-info\" }\r\nexport function themeSaveButton() { return \"btn btn-success\" }\r\nexport function themeUpdateButton() { return \"btn btn-primary\" }\r\nexport function themeDeleteButton() { return \"btn btn-danger btn-sm\" }\r\nexport function themeNewButton() { return \"btn btn-info\" }\r\nexport function themeExpandButton() { return \"btn btn-success btn-sm\" }\r\nexport function themeStripedTable() {return \"table table-striped\"}\r\nexport function themeSpinner() {return \"fa fa-refresh fa-spin\"}\r\nexport function themeFormInput() {return \"form-control\"}\r\nexport function themeCol3() {return \"col-3\"}\r\nexport function themeCol4() {return \"col-4\"}\r\nexport function themeCol6() {return \"col-6\"}\r\nexport function themeCol6Right() {return \"col-6 text-right\"}\r\nexport function themeCol9() {return \"col-9\"}\r\nexport function themeCol12xl() { return \"col-xl-12\" }\r\n\r\n \r\n \r\n ","class EsaedroLookupItem {\r\n private _value: any;\r\n\r\n public get value() : any {\r\n return this._value\r\n } \r\n\r\n public set value(newvalue: any) {\r\n this._value = newvalue\r\n }\r\n\r\n private _description: string = \"\";\r\n\r\n public get description() : string {\r\n return this._description\r\n } \r\n\r\n public set description(newvalue: string) {\r\n this._description = newvalue\r\n }\r\n constructor(value:any,description:string) {\r\n this.value=value;\r\n this.description=description;\r\n }\r\n\r\n}\r\n\r\nexport default EsaedroLookupItem;","import React, { Component, Fragment } from 'react'\r\nimport { Row, Col, Container, Button, Modal, ModalHeader, ModalBody, ModalFooter, ButtonGroup } from 'reactstrap';\r\nimport '../App.css';\r\nimport LoggedContext from '../BusinessObjects/LoggedContext'\r\nimport EsaedroLookupItem from '../Models/EsaedroLookupItem';\r\nimport cubeApiClient from '../BusinessObjects/cubeApiService';\r\nimport ResourcesLookups from '../Models/ResourcesLookups';\r\nimport { themeCol9, themeSpinner, themeGroup, themeCol4, themeCol3, themeFormInput } from '../Utils/EsaedroTheme';\r\nimport EsaedroResourceFilter from '../Models/EsaedroResourceFilter';\r\n\r\n\r\ninterface IEsaedroLookupsProps {\r\n name:string;\r\n value:any;\r\n fatherObj:any;\r\n lookupName: string;\r\n lookupValues:string;\r\n className?:string;\r\n displayName?:string;\r\n onChange?(event: any): void;\r\n onFieldsToCheckLoaded?(lookupName: string, fieldsToCheck: any[]) : void;\r\n items?:EsaedroLookupItem[];\r\n isSys?:boolean;\r\n isDisabled?:boolean;\r\n}\r\ninterface IEsaedroLookupState\r\n{\r\n lookupResource?: ResourcesLookups;\r\n items:EsaedroLookupItem[];\r\n itemsToDisplay:EsaedroLookupItem[];\r\n toggleSearch: boolean\r\n loading:boolean;\r\n lookupResourceDisplayFilters: EsaedroResourceFilter[];\r\n errorMessage:string;\r\n}\r\n\r\nexport default class EsaedroLookup extends Component {\r\n static contextType = LoggedContext\r\n context!: React.ContextType\r\n \r\n // Campi che manipolano il rendering\r\n filterFailed: boolean = false\r\n fieldsToCheck: any[] = []\r\n initialDisplayField: string = ''\r\n \r\n constructor(props: IEsaedroLookupsProps){\r\n super(props);\r\n this.state={lookupResource: undefined, items:[],itemsToDisplay:[],toggleSearch:false, loading:true, lookupResourceDisplayFilters:[], errorMessage:''};\r\n }\r\n\r\n componentDidMount()\r\n {\r\n this.getLookupData()\r\n }\r\n \r\n getLookupData = () => {\r\n\r\n // Questo metodo viene chiamato solo alla DidMount, e popola la lookup\r\n this.setState({loading: true})\r\n\r\n //Elenco di valori fissi, li setto e mi fermo\r\n if (this.props.lookupValues)\r\n {\r\n let valuesToShow = this.props.lookupValues.split('|')\r\n\r\n let newItems: EsaedroLookupItem[] = []\r\n let newItemsToDisp: EsaedroLookupItem[] = []\r\n valuesToShow.map(element => {\r\n var v =element.split('=');\r\n newItems.push(new EsaedroLookupItem(v[0],v[1]));\r\n newItemsToDisp.push(new EsaedroLookupItem(v[0],v[1]));\r\n });\r\n\r\n this.setState({\r\n items: newItems,\r\n itemsToDisplay: newItemsToDisp,\r\n loading:false\r\n });\r\n }\r\n else\r\n //Elenco da lookup resource - Gestione complessa\r\n if(this.props.lookupName)\r\n {\r\n //Col lookupName vado a richiedere i dettagli della lookup\r\n const service = new cubeApiClient();\r\n const t = this.context.tokenAPI;\r\n var requrl =\"api/sys/ResourcesLookups?RecordSelection=\" + encodeURIComponent(\"LookupName='\" + this.props.lookupName + \"'\") ; \r\n \r\n service\r\n .getItems(requrl,t)\r\n .then((data: any) => {\r\n //Se li trovo procedo\r\n if (data)\r\n {\r\n var resourceLookup:ResourcesLookups=data[0];\r\n if (resourceLookup)\r\n {\r\n // Compilo i fieldsToCheck \r\n if (resourceLookup.ResourcesLookupsFilters) {\r\n for(var i=0;i< resourceLookup.ResourcesLookupsFilters.length;i++)\r\n {\r\n this.fieldsToCheck.push(resourceLookup.ResourcesLookupsFilters[i].ParentField_Name)\r\n }\r\n // Invoco il callback per salvare i fields to check della lookup\r\n this.sendFieldsToCheckToParent(resourceLookup.ValueField_Name, this.fieldsToCheck)\r\n \r\n }\r\n // Setto la resourceLookup\r\n this.setState({lookupResource: resourceLookup})\r\n // Se non ha LoadOnClick allora chiedo già i campi\r\n if (!resourceLookup.LoadOnClick) {\r\n this.reloadResourceLookupFields()\r\n }\r\n else {\r\n // Ottengo la descrizione del primo Item\r\n let filterString = '?RecordSelection=' + resourceLookup.ValueField_Name + \" = '\" + this.props.value + \"'\"\r\n // Applico i filtri in caso ce ne siano\r\n if (resourceLookup.ResourcesLookupsFilters && this.props.fatherObj) {\r\n this.fieldsToCheck = []\r\n for(var i=0;i< resourceLookup.ResourcesLookupsFilters.length;i++)\r\n {\r\n this.fieldsToCheck.push(resourceLookup.ResourcesLookupsFilters[i].ParentField_Name)\r\n if (this.props.fatherObj[resourceLookup.ResourcesLookupsFilters[i].ParentField_Name]) {\r\n filterString += \" and \"\r\n + resourceLookup.ResourcesLookupsFilters[i].LookupField_Name \r\n + resourceLookup.ResourcesLookupsFilters[i].FilterOperator \r\n + \"'\" + this.props.fatherObj[resourceLookup.ResourcesLookupsFilters[i].ParentField_Name] + \"'\"\r\n }\r\n else this.filterFailed = true\r\n }\r\n if (this.filterFailed) filterString = '?RecordSelection=1=0'\r\n }\r\n\r\n //var requrl ='api/Resources/' + resourceLookup.Resource_Name + filterString;\r\n //if (this.props.isSys) requrl ='api/sys/' + resourceLookup.Resource_Name + filterString;\r\n var requrl =resourceLookup.Resource_Endpoint + filterString;\r\n\r\n // Vado a chiedere al servizio il primo item per recuperarne la descrizione completa\r\n service\r\n .getItems(requrl,t)\r\n .then((elenco: any) => {\r\n // Se trovo l'oggetto, allora setto la descrizione completa\r\n if (elenco.length) {\r\n var element=elenco[0];\r\n if (element) {\r\n var descriptionField:string=\"\";\r\n // Salvo i campi su cui poi filtrerò e intanto mi ricreo la descrizione completa\r\n for(var idxFields=0;idxFields< resourceLookup.ResourcesLookupsDisplayFields.length;idxFields++)\r\n {\r\n this.state.lookupResourceDisplayFilters.push(new EsaedroResourceFilter(resourceLookup.ResourcesLookupsDisplayFields[idxFields].DisplayField_Name, '', ' like ', resourceLookup.ResourcesLookupsDisplayFields[idxFields].DisplayField_Description))\r\n descriptionField = descriptionField + (idxFields?\" | \":\"\") + element[resourceLookup.ResourcesLookupsDisplayFields[idxFields].DisplayField_Name];\r\n }\r\n // Mi salvo la descrizione completa a lookup non ancora caricata\r\n this.initialDisplayField = descriptionField\r\n this.setState({loading: false})\r\n }\r\n else {\r\n // Salvo comunque i campi su cui poi filtrerò e intanto mi ricreo la descrizione completa\r\n for(var idxFields=0;idxFields< resourceLookup.ResourcesLookupsDisplayFields.length;idxFields++)\r\n {\r\n this.state.lookupResourceDisplayFilters.push(new EsaedroResourceFilter(resourceLookup.ResourcesLookupsDisplayFields[idxFields].DisplayField_Name, '', ' like ', resourceLookup.ResourcesLookupsDisplayFields[idxFields].DisplayField_Description))\r\n }\r\n this.setState({loading: false})\r\n } \r\n }\r\n else {\r\n // Salvo comunque i campi su cui poi filtrerò e intanto mi ricreo la descrizione completa\r\n for(var idxFields=0;idxFields< resourceLookup.ResourcesLookupsDisplayFields.length;idxFields++)\r\n {\r\n this.state.lookupResourceDisplayFilters.push(new EsaedroResourceFilter(resourceLookup.ResourcesLookupsDisplayFields[idxFields].DisplayField_Name, '', ' like ', resourceLookup.ResourcesLookupsDisplayFields[idxFields].DisplayField_Description))\r\n }\r\n this.setState({loading: false})\r\n }\r\n },\r\n (error: any) => {this.setState({ loading: false, errorMessage: error });}); \r\n }\r\n }\r\n else this.setState({loading:false});\r\n } \r\n else this.setState({loading:false});\r\n },\r\n (error: any) => {\r\n // Non ho trovato i dettagli della Resource Lookup\r\n this.setState({ loading: false, errorMessage: error });\r\n });\r\n \r\n }\r\n else\r\n {\r\n //Ultima spiaggia...valori items presi dal padre\r\n if (this.props.items!==undefined) this.setState({items:this.props.items, itemsToDisplay:this.props.items, loading: false});\r\n else this.setState({loading:false});\r\n }\r\n }\r\n\r\n sendFieldsToCheckToParent = (fieldName: string, fieldsToCheck: any[]) => {\r\n // Tramite callback manda alla ObjectEdit i campi da controllare per scatenare il re-rendering della lookup\r\n if (this.props.onFieldsToCheckLoaded != undefined)\r\n this.props.onFieldsToCheckLoaded(fieldName, fieldsToCheck)\r\n }\r\n\r\n reloadResourceLookupFields = () => {\r\n\r\n // Ricarica i campi della lookup\r\n this.setState({loading: true, toggleSearch: false})\r\n\r\n //Elenco da lookup resource\r\n if(this.state.lookupResource)\r\n {\r\n let resourceLookup = this.state.lookupResource\r\n\r\n let recSelString = '?RecordSelection=' \r\n let filterString = \"\"\r\n // Applico i filtri in caso ce ne siano\r\n if (resourceLookup.ResourcesLookupsFilters && this.props.fatherObj)\r\n {\r\n this.fieldsToCheck = []\r\n this.filterFailed = false\r\n for(var i=0;i< resourceLookup.ResourcesLookupsFilters.length;i++)\r\n {\r\n if (resourceLookup.ResourcesLookupsFilters[i].ParentField_Name) {\r\n this.fieldsToCheck.push(resourceLookup.ResourcesLookupsFilters[i].ParentField_Name)\r\n if (this.props.fatherObj[resourceLookup.ResourcesLookupsFilters[i].ParentField_Name]) {\r\n filterString += (i?\" and \":\"\") \r\n + resourceLookup.ResourcesLookupsFilters[i].LookupField_Name \r\n + resourceLookup.ResourcesLookupsFilters[i].FilterOperator \r\n + \"'\" + this.props.fatherObj[resourceLookup.ResourcesLookupsFilters[i].ParentField_Name] + \"'\"\r\n }\r\n else this.filterFailed = true\r\n }\r\n else if (resourceLookup.ResourcesLookupsFilters[i].FixedValue) {\r\n filterString += (i?\" and \":\"\") \r\n + resourceLookup.ResourcesLookupsFilters[i].LookupField_Name \r\n + resourceLookup.ResourcesLookupsFilters[i].FilterOperator \r\n + \"'\" + resourceLookup.ResourcesLookupsFilters[i].FixedValue + \"'\"\r\n }\r\n }\r\n if (this.filterFailed) filterString = '1=0'\r\n }\r\n\r\n // Applico anche i filtri eventuali impostati dalla maschera\r\n let filtersToAppend = ''\r\n if (this.state.lookupResourceDisplayFilters.length && !this.filterFailed) {\r\n\r\n if (filterString>'') filtersToAppend = \" and \"\r\n\r\n let found = false\r\n this.state.lookupResourceDisplayFilters.forEach(element => {\r\n if (element.Value!='') {\r\n filtersToAppend += (found?\" and lower(\":\"lower(\") \r\n + element.FieldName\r\n + ')'\r\n + element.Operator\r\n + 'lower('\r\n + \"'%\" + element.Value + \"%'\"\r\n + ')'\r\n found = true\r\n }\r\n });\r\n\r\n if (!found) filtersToAppend = ''\r\n }\r\n\r\n const service = new cubeApiClient();\r\n const t = this.context.tokenAPI;\r\n\r\n // var requrl ='api/Resources/' + resourceLookup.Resource_Name + ((filterString>''||filtersToAppend>'')?recSelString + encodeURIComponent(filterString + filtersToAppend):'');\r\n\r\n // if (this.props.isSys) requrl ='api/sys/' + resourceLookup.Resource_Name + filterString + filtersToAppend;\r\n var requrl = resourceLookup.Resource_Endpoint + ((filterString>''||filtersToAppend>'')?recSelString + encodeURIComponent(filterString + filtersToAppend):'');\r\n\r\n service\r\n .getItems(requrl,t)\r\n .then((elenco: any) => {\r\n if (elenco) {\r\n let newItems: EsaedroLookupItem[] = []\r\n let newItemsToDisp: EsaedroLookupItem[] = []\r\n for (var i=0; i < elenco.length; i++) {\r\n var element=elenco[i];\r\n var descriptionField:string=\"\";\r\n\r\n var hasFilterDisplayFields = this.state.lookupResourceDisplayFilters.length? true: false\r\n for(var idxFields=0;idxFields< resourceLookup.ResourcesLookupsDisplayFields.length;idxFields++)\r\n {\r\n if (!hasFilterDisplayFields) this.state.lookupResourceDisplayFilters.push(new EsaedroResourceFilter(resourceLookup.ResourcesLookupsDisplayFields[idxFields].DisplayField_Name, '', ' like ', resourceLookup.ResourcesLookupsDisplayFields[idxFields].DisplayField_Description))\r\n descriptionField = descriptionField + (idxFields?\" | \":\"\") + element[resourceLookup.ResourcesLookupsDisplayFields[idxFields].DisplayField_Name];\r\n }\r\n newItems.push(new EsaedroLookupItem(element[resourceLookup.ValueField_Name],descriptionField));\r\n newItemsToDisp.push(new EsaedroLookupItem(element[resourceLookup.ValueField_Name],descriptionField)); \r\n }\r\n this.setState({\r\n items: newItems,\r\n itemsToDisplay: newItemsToDisp,\r\n loading:false\r\n });\r\n }\r\n else this.setState({loading:false})\r\n },\r\n (error: any) => {this.setState({ loading: false, errorMessage: error });}); \r\n }\r\n else this.setState({loading:false}); \r\n\r\n }\r\n\r\n filterObjects = (e: any) => {\r\n\r\n let updateList = this.state.items;\r\n\r\n updateList = updateList.filter(item => {\r\n return item.description.toLowerCase().search(\r\n e.target.value.toLowerCase()\r\n ) !== -1;\r\n });\r\n\r\n this.setState({\r\n itemsToDisplay: updateList\r\n });\r\n }\r\n\r\n filterChange = (e: any) => {\r\n let newFilters = this.state.lookupResourceDisplayFilters\r\n newFilters.forEach(element => {\r\n if (element.FieldName == e.target.name) {\r\n element.Value = e.target.value.toString()\r\n }\r\n });\r\n this.setState({lookupResourceDisplayFilters: newFilters})\r\n }\r\n\r\n toggleSearchBtnPressed = () => {\r\n this.setState({toggleSearch: !this.state.toggleSearch})\r\n }\r\n \r\n render() {\r\n // Come prima cosa renderizzo oggetti che mi serviranno in caso di lookupResource\r\n let toggleButton = undefined\r\n let filterFields = undefined\r\n let lookupLabel = undefined\r\n let modalFilters = undefined\r\n\r\n if (this.state.lookupResource /*&& this.state.lookupResource.LoadOnClick*/) {\r\n toggleButton = \r\n filterFields = this.state.lookupResourceDisplayFilters.map((filter: EsaedroResourceFilter) => {\r\n return (\r\n \r\n
\r\n \r\n \r\n
\r\n \r\n \r\n \r\n )\r\n })\r\n lookupLabel = \r\n\r\n modalFilters = \r\n Filtri Ricerca\r\n \r\n {filterFields} \r\n \r\n \r\n {' '}\r\n \r\n \r\n \r\n }\r\n\r\n // Render in caso di loading\r\n if (this.state.loading)\r\n {\r\n return (\r\n \r\n
\r\n Caricamento...\r\n \r\n \r\n )\r\n }\r\n\r\n // Se non ci sono itemsToDisplay gestisco i vari casi\r\n else if (!this.state.itemsToDisplay.length) {\r\n\r\n // Non ci sono perchè mancano dei campi richiesti - Metto una combo vuota in ogni caso\r\n if (this.filterFailed) {\r\n return (\r\n \r\n )\r\n }\r\n // Non ci sono perchè è una LoadOnClick - Metto il campo placeholder e renderizzo il tasto cerca\r\n else if (this.state.lookupResource && this.state.lookupResource.LoadOnClick){\r\n return (\r\n \r\n {toggleButton}\r\n {modalFilters} \r\n {lookupLabel}\r\n \r\n )\r\n }\r\n // Altrimenti presumo che non siano arrivati dati\r\n else {\r\n return (\r\n \r\n
\r\n Nessun dato disponibile... \r\n \r\n \r\n )\r\n }\r\n }\r\n // Se invece ci sono items, renderizzo la lookup\r\n else\r\n {\r\n let emptyMessage = \"Nessuna selezione...\"\r\n /* Alternativa */\r\n //let emptyMessage = \"Seleziona \" + {this.props.displayName}\r\n \r\n const elements =(this.state.itemsToDisplay!==undefined? this.state.itemsToDisplay.map( \r\n (item: EsaedroLookupItem) => { \r\n const sele=(item.value === this.props.value?true:false);\r\n return \r\n }\r\n ):'Non ci sono elementi da visualizzare...');\r\n\r\n if (this.state.lookupResource && this.state.lookupResource.LoadOnClick) {\r\n return (\r\n \r\n {modalFilters} \r\n \r\n {toggleButton} \r\n \r\n \r\n \r\n )\r\n }\r\n else return (\r\n \r\n {modalFilters} \r\n \r\n {toggleButton} \r\n \r\n \r\n \r\n \r\n )\r\n }\r\n }\r\n}\r\n","import React, { Component } from 'react'\r\nimport LoggedContext from '../BusinessObjects/LoggedContext'\r\nimport cubeApiClient from '../BusinessObjects/cubeApiService';\r\nimport { Container, Row, Col } from 'reactstrap';\r\nimport '../index.css';\r\n\r\ninterface EsaedroObjectDeleteProps {\r\n myObjType: string;\r\n myObjUrl: string;\r\n myObj: any;\r\n onReturn?(returnMsg?:string): void\r\n}\r\n\r\ninterface EsaedroObjectDeleteState {\r\n objToBeDeleted: any;\r\n errorMessage:string;\r\n}\r\n\r\nexport default class EsaedroObjectDelete extends Component {\r\n static contextType = LoggedContext\r\n context!: React.ContextType\r\n \r\n constructor(props: any) {\r\n super(props);\r\n\r\n this.state = {\r\n objToBeDeleted: '',\r\n errorMessage:'' \r\n };\r\n }\r\n\r\n componentDidMount() {\r\n\r\n this.setState({objToBeDeleted: this.props.myObj});\r\n \r\n if(this.context.userProfile == undefined) \r\n {\r\n this.setState({errorMessage:'utente non definito'});\r\n return;\r\n }\r\n \r\n if(this.context.userProfile.customer_ID == 0) \r\n {\r\n this.setState({errorMessage:'azienda non selezionata'});\r\n return;\r\n }\r\n \r\n }\r\n\r\n deleteObj = () => {\r\n\r\n const service = new cubeApiClient();\r\n const t = this.context.tokenAPI;\r\n\r\n service\r\n .deleteObject([this.state.objToBeDeleted] , this.props.myObjUrl, t)\r\n .then(() => {\r\n if (this.props.onReturn!=undefined) {\r\n let successMsg = \"Operazione avvenuta con successo!\"\r\n this.props.onReturn(successMsg)\r\n }\r\n },\r\n (error: any) => {\r\n let stringError = \"Errore nella cancellazione: \"+JSON.stringify(error)\r\n this.setState({errorMessage:stringError});;\r\n }); \r\n }\r\n\r\n returnToList = () => {\r\n if (this.props.onReturn!=undefined) {\r\n this.props.onReturn()\r\n }\r\n }\r\n\r\n render() {\r\n\r\n if(this.state.errorMessage!='')\r\n {\r\n return (\r\n \r\n \r\n
\r\n );\r\n }*/\r\n}","import React, { Component, Fragment } from 'react';\r\nimport { Image } from 'react-bootstrap';\r\nimport { Button, Col, Container, Row } from 'reactstrap';\r\nimport LoggedContext from '../BusinessObjects/LoggedContext';\r\nimport EsaedroResourceAttachment from '../Models/EsaedroResourceAttachment';\r\nimport { themeBackButton, themeCol3, themeCol9, themeFormInput, themeGroup } from '../Utils/EsaedroTheme';\r\n\r\ninterface IEsaedroAttachmentProps {\r\n attachment: string,\r\n attachmentFieldName: string,\r\n name: string,\r\n canLoad: boolean,\r\n canDelete: boolean,\r\n resourceAttachment?: EsaedroResourceAttachment,\r\n onChange?(event: any) : void\r\n onDelete?(resourceAttachment: EsaedroResourceAttachment) : void\r\n}\r\n\r\nexport default class EsaedroAttachment extends Component {\r\n\r\n static contextType = LoggedContext\r\n context!: React.ContextType\r\n \r\n constructor(props: IEsaedroAttachmentProps){\r\n super(props);\r\n\r\n this.state = {\r\n uploading: false\r\n };\r\n }\r\n\r\n removeImage = () => {\r\n // Controllo se è impostato l'handler per la delete e se il componente è associato ad un ResourceAttachment \r\n if (this.props.onDelete && this.props.resourceAttachment) {\r\n this.props.onDelete(this.props.resourceAttachment)\r\n }\r\n else {\r\n // Altrimenti ritorna un evento custom alla callback onChange (Utilizzato dalla ObjectEdit)\r\n let customEvent = new CustomEvent(\"DeleteFile\", {detail: this.props.name})\r\n if (this.props.onChange) this.props.onChange(customEvent)\r\n }\r\n } \r\n \r\n render() {\r\n const {attachment, attachmentFieldName, name} = this.props\r\n\r\n var description = this.props.resourceAttachment? \r\n this.props.resourceAttachment.Description \r\n : attachmentFieldName\r\n\r\n var deleteButton = this.props.canDelete? \r\n : undefined\r\n\r\n var newFileButton = this.props.canLoad? \r\n : Non è possibile aggiungere allegati per questa risorsa\r\n\r\n if (attachment != undefined && attachment != \"\")\r\n return (\r\n // TODO Controllare il tipo di attachment prima di renderizzare Images\r\n \r\n
\r\n \r\n \r\n
\r\n \r\n {deleteButton}\r\n \r\n \r\n )\r\n\r\n else \r\n return newFileButton\r\n }\r\n}","import React, { Component, Fragment } from 'react';\r\nimport { Button, Container, Row, UncontrolledAlert } from 'reactstrap';\r\nimport cubeApiClient from '../BusinessObjects/cubeApiService';\r\nimport LoggedContext from '../BusinessObjects/LoggedContext';\r\nimport EsaedroResourceAttachment from '../Models/EsaedroResourceAttachment';\r\nimport EsaedroAttachment from './EsaedroAttachment';\r\nimport EsaedroObjectDelete from './EsaedroObjectDelete';\r\n\r\n/************** COMPONENTE CHE MOSTRA GLI ALLEGATI DI UNA RISORSA *****************/\r\n/************** Da qui è solamente possibile visualizzarli ed eliminarli **********/\r\n\r\ninterface IEsaedroAttachmentsControllerProps {\r\n Resource_ID: number,\r\n Item_ID: number\r\n}\r\n\r\ninterface IEsaedroAttachmentsControllerState {\r\n loading: boolean,\r\n successMessage: string,\r\n errorMessage: string,\r\n attachments: EsaedroResourceAttachment[],\r\n attachmentToDelete: any\r\n}\r\n\r\nexport default class EsaedroAttachmentsController extends Component {\r\n\r\n static contextType = LoggedContext\r\n context!: React.ContextType\r\n \r\n constructor(props: IEsaedroAttachmentsControllerProps){\r\n super(props);\r\n\r\n this.state = {\r\n loading: false,\r\n successMessage: \"\",\r\n errorMessage: \"\",\r\n attachments: [],\r\n attachmentToDelete: null\r\n };\r\n}\r\n\r\n componentDidMount() {\r\n this.getObjectAttachments()\r\n }\r\n\r\n getObjectAttachments = () => {\r\n // Faccio una chiamata ai webservice con le immagini legate all'oggetto\r\n this.setState({loading: true})\r\n \r\n const service = new cubeApiClient();\r\n const t = this.context.tokenAPI;\r\n const requrl = 'api/sys/ResourcesAttachments?RecordSelection=' + \"Resource_ID=\" + this.props.Resource_ID + \"and Item_ID=\" + this.props.Item_ID\r\n\r\n service\r\n .getItems(requrl,t)\r\n .then((data: any) => {\r\n // Aggiorno i miei attachments\r\n if (data)\r\n {\r\n this.setState({\r\n attachments:data,\r\n loading:false\r\n })\r\n }\r\n else {\r\n this.setState({\r\n errorMessage:\"Errore nello scaricare gli allegati\",\r\n loading: false\r\n })\r\n }\r\n },\r\n (error: any) => {\r\n this.setState({ \r\n attachments:[],\r\n errorMessage: error,\r\n loading: false\r\n });\r\n });\r\n }\r\n\r\n onDeleteButtonPressed = (attachmentToRemove: EsaedroResourceAttachment) => {\r\n this.setState({attachmentToDelete: attachmentToRemove})\r\n }\r\n\r\n onAttachmentRemoved = (returnMessage: string) => {\r\n // Mostro il messaggio di successo e rendo nullo l'attachment da rimuovere\r\n this.setState({successMessage: returnMessage, attachmentToDelete: null})\r\n // Dopodichè ricarico gli allegati\r\n this.getObjectAttachments()\r\n }\r\n \r\n render() {\r\n const { loading, attachments, attachmentToDelete } = this.state\r\n\r\n const successMessageAlert = (\r\n (this.state.successMessage != '')?\r\n \r\n {this.state.successMessage}\r\n \r\n : undefined\r\n )\r\n\r\n const errorMessageAlert = (\r\n (this.state.errorMessage != '')?\r\n \r\n {this.state.errorMessage}\r\n \r\n : undefined\r\n \r\n )\r\n\r\n const content = (\r\n loading? \r\n
Caricamento...
\r\n :attachmentToDelete?\r\n \r\n \r\n :(attachments.length > 0)?\r\n attachments.map((attachment: EsaedroResourceAttachment, i: number) => \r\n \r\n \r\n \r\n \r\n \r\n )\r\n :Nessun allegato da visualizzare \r\n )\r\n \r\n return (\r\n \r\n {successMessageAlert}\r\n \r\n \r\n \r\n {errorMessageAlert}\r\n \r\n \r\n \r\n {content}\r\n \r\n )\r\n }\r\n}","class EsaedroResourceAttachment {\r\n \r\n public Resource_ID: number = 0;\r\n public Item_ID: number = 0;\r\n public Id: number = 0;\r\n public Description: string = \"\";\r\n public AttachmentType: string = \"image\";\r\n public Content: any\r\n\r\n constructor(resource_ID:number, item_ID:number, id: number, content: any, description?: string, attachmentType?: string) {\r\n this.Resource_ID=resource_ID\r\n this.Item_ID=item_ID\r\n this.Id=id\r\n this.Description=description?description:this.Resource_ID.toString()\r\n this.AttachmentType=attachmentType?attachmentType:\"image\"\r\n this.Content = content\r\n }\r\n}\r\n\r\nexport default EsaedroResourceAttachment;","import React, { Component, Fragment } from 'react';\r\nimport { Image } from 'react-bootstrap';\r\nimport { Button, Col, Container, Row, UncontrolledAlert } from 'reactstrap';\r\nimport cubeApiClient from '../BusinessObjects/cubeApiService';\r\nimport LoggedContext from '../BusinessObjects/LoggedContext';\r\nimport EsaedroResourceAttachment from '../Models/EsaedroResourceAttachment';\r\nimport { themeBackButton } from '../Utils/EsaedroTheme';\r\nimport EsaedroAttachment from './EsaedroAttachment';\r\n\r\n/************** COMPONENTE PER AGGIUNGERE ALLEGATI AD UNA RISORSA ********************************************************************/\r\n/************** Gestisce l'upload di uno o più allegati in memoria e infine li invia al CUBE, che li assegna ad una risorsa **********/\r\n\r\ninterface IEsaedroAttachmentLoaderProps {\r\n Resource_ID: number,\r\n Item_ID: number,\r\n onReturn?(ackMessage?: string): void\r\n}\r\n\r\ninterface IEsaedroAttachmentLoaderState {\r\n uploading: boolean,\r\n successMessage: string,\r\n errorMessage: string,\r\n attachments: EsaedroResourceAttachment[],\r\n}\r\n\r\nfunction Buttons (props: any) {\r\n return (\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n )\r\n}\r\n\r\nexport default class EsaedroAttachmentLoader extends Component {\r\n\r\n static contextType = LoggedContext\r\n context!: React.ContextType\r\n attachmentsUrl: string = \"api/sys/ResourcesAttachments\"\r\n \r\n constructor(props: IEsaedroAttachmentLoaderProps){\r\n super(props);\r\n\r\n this.state = {\r\n uploading: false,\r\n successMessage: \"\",\r\n errorMessage: \"\",\r\n attachments: [],\r\n };\r\n }\r\n\r\n onChange = (event: any) => {\r\n\r\n this.setState({ uploading: true })\r\n\r\n const files = Array.from(event.target.files)\r\n\r\n // Creo degli oggetti di tipo EsaedroImagesController e li aggiungo all'array di allegati\r\n files.forEach((file: any ) => {\r\n this.readAndAdd(file)\r\n })\r\n\r\n this.setState({ \r\n uploading: false\r\n })\r\n \r\n }\r\n\r\n readAndAdd = (file: File) => {\r\n var newImages = this.state.attachments\r\n var reader = new FileReader()\r\n\r\n reader.onload = () => {\r\n let imgUrl = reader.result\r\n let newFile = new EsaedroResourceAttachment(this.props.Resource_ID, this.props.Item_ID, 0, imgUrl)\r\n newImages.push(newFile)\r\n this.setState({ \r\n attachments: newImages\r\n })\r\n }\r\n reader.readAsDataURL(file)\r\n }\r\n\r\n removeImage = (attachment: EsaedroResourceAttachment) => {\r\n let i = this.state.attachments.indexOf(attachment)\r\n // Rimuove l'elemento i-esimo dall'array\r\n let newImages = this.state.attachments\r\n newImages.splice(i,1)\r\n this.setState({\r\n attachments: newImages\r\n })\r\n }\r\n\r\n returnToEdit = (event: any) => {\r\n // Per tornare alla Edit senza inviare le immagini\r\n if (this.props.onReturn!=undefined) {\r\n this.props.onReturn()\r\n }\r\n }\r\n\r\n sendImages = (event: any) => {\r\n // Qui mando le Risorse raccolte al cube. Capire se posso mandarle tutte insieme\r\n // Chiama il servizio di update\r\n\r\n const service = new cubeApiClient();\r\n event.preventDefault();\r\n\r\n this.setState({uploading:true})\r\n\r\n service\r\n .updateObjects(this.state.attachments, this.attachmentsUrl, this.context.tokenAPI)\r\n .then(() => {\r\n this.setState({ \r\n // Gestire il successo\r\n successMessage:' Allegati caricati con successo!',\r\n uploading: false\r\n });\r\n //alert(\"sto per tornare alla lista!\")\r\n if (this.props.onReturn!=undefined) {\r\n let successMsg = \"Allegati caricati con successo!\"\r\n this.props.onReturn(successMsg)\r\n }\r\n },\r\n (error: any) => {\r\n let stringError = \"Errore nel caricamento:\"+JSON.stringify(error)\r\n this.setState({ \r\n errorMessage: stringError,\r\n uploading: false \r\n });\r\n });\r\n \r\n }\r\n \r\n render() {\r\n const { uploading, attachments } = this.state\r\n\r\n const successMessageAlert = (\r\n (this.state.successMessage != '')?\r\n \r\n {this.state.successMessage}\r\n \r\n : undefined\r\n )\r\n\r\n const errorMessageAlert = (\r\n (this.state.errorMessage != '')?\r\n \r\n {this.state.errorMessage}\r\n \r\n : undefined\r\n )\r\n\r\n const content = (\r\n uploading? \r\n
\r\n case attachments.length > 0:\r\n return (\r\n // TODO Controllare il tipo di attachment prima di renderizzare Images\r\n \r\n \r\n \r\n \r\n \r\n )\r\n default:\r\n return \r\n }\r\n }\r\n\r\n return (\r\n
\r\n
\r\n {content()}\r\n
\r\n
\r\n )*/\r\n }\r\n}","import React, { Component, Fragment } from 'react';\r\nimport { Button, Col, Row } from 'reactstrap';\r\nimport LoggedContext from '../BusinessObjects/LoggedContext';\r\nimport { themeBackButton, themeCol3, themeCol9, themeFormInput, themeGroup, themeSaveButton } from '../Utils/EsaedroTheme';\r\n\r\ninterface IEsaedroJSONComponentProps {\r\n component: any\r\n fieldName: string\r\n canEdit: boolean\r\n suggestedKeys?: string\r\n onChange?(event: any) : void\r\n}\r\n\r\ninterface IEsaedroJSONComponentState {\r\n component: any\r\n componentFields: string[]\r\n newKeyLabel: string\r\n newKeyValue: string\r\n addingField: boolean\r\n}\r\n\r\nexport default class EsaedroJSONComponent extends Component {\r\n\r\n static contextType = LoggedContext\r\n context!: React.ContextType\r\n \r\n constructor(props: IEsaedroJSONComponentProps){\r\n super(props);\r\n\r\n this.state = {\r\n component: {},\r\n componentFields: [],\r\n newKeyLabel: \"\",\r\n newKeyValue: \"\",\r\n addingField: false\r\n };\r\n }\r\n\r\n componentDidMount(){\r\n const {component} = this.props\r\n\r\n // Già costruendo il component popolo le sue chiavi, ma controllo che sia effettivamente un JSON\r\n let isJson = this.isJSON(component)\r\n let jsonObject = isJson? JSON.parse(component) : component\r\n let keys = isJson? \r\n Object.keys(jsonObject)\r\n : []\r\n\r\n // Controllo se ha già tutte le chiavi che dovrebbe avere, altrimenti le aggiungo\r\n if (this.props.suggestedKeys) {\r\n // Se non ha chiavi allora aggiungo le chiavi proposte\r\n if (keys.length == 0) {\r\n keys = this.props.suggestedKeys.split(\"|\")\r\n }\r\n }\r\n\r\n this.setState({\r\n component: jsonObject,\r\n componentFields: keys,\r\n newKeyLabel: \"\",\r\n newKeyValue: \"\",\r\n addingField: false\r\n })\r\n }\r\n\r\n // Controlla che l'oggetto sia effettivamente un JSON\r\n isJSON = (object: any) : boolean => {\r\n try {\r\n JSON.parse(object)\r\n }\r\n catch (e)\r\n {\r\n return false\r\n }\r\n return true\r\n }\r\n\r\n addKey = () => {\r\n // Aggiunge una chiave all'oggetto\r\n const {component, componentFields, newKeyLabel, newKeyValue} = this.state\r\n let newKeys = componentFields\r\n let newComp = component\r\n newKeys.push(newKeyLabel)\r\n newComp[newKeyLabel] = newKeyValue\r\n\r\n this.setState({\r\n newKeyLabel: \"\",\r\n newKeyValue: \"\",\r\n addingField: false\r\n })\r\n\r\n if (this.props.onChange) {\r\n let customEvent = new CustomEvent(\"JSONObjectChanged\", {detail: {\"name\" : this.props.fieldName, \"value\" : JSON.stringify(newComp)}})\r\n this.props.onChange(customEvent)\r\n }\r\n }\r\n\r\n toggleAddField = () => {\r\n this.setState({addingField: !this.state.addingField})\r\n }\r\n\r\n handleChange = (event: any) => {\r\n const target = event.target\r\n const {component, componentFields} = this.state\r\n\r\n if (target.name == \"NewKey\") {\r\n this.setState({newKeyLabel: target.value})\r\n }\r\n \r\n else if (target.name == \"NewKeyValue\") {\r\n this.setState({newKeyValue: target.value})\r\n }\r\n\r\n else {\r\n let value = target.value\r\n var key = target.name;\r\n\r\n if (componentFields.length > 0) {\r\n let tempObj = component;\r\n tempObj[key] = value;\r\n\r\n if (this.props.onChange) {\r\n let customEvent = new CustomEvent(\"JSONObjectChanged\", {detail: {\"name\" : this.props.fieldName, \"value\" : JSON.stringify(tempObj)}})\r\n this.props.onChange(customEvent)\r\n }\r\n }\r\n else {\r\n let tempObj = component;\r\n tempObj = value; \r\n \r\n if (this.props.onChange) {\r\n let customEvent = new CustomEvent(\"JSONObjectChanged\", {detail: {\"name\" : this.props.fieldName, \"value\" : tempObj}})\r\n this.props.onChange(customEvent)\r\n }\r\n }\r\n }\r\n }\r\n\r\n handleRecursiveChange = (event: any) => {\r\n\r\n const {component} = this.state\r\n\r\n // Elabora il campo JSON, lo setta all'oggetto padre e poi manda il padre a chi ha renderizzato il component\r\n if (event.type == \"JSONObjectChanged\") {\r\n let value = event.detail[\"value\"]\r\n var name = event.detail[\"name\"]\r\n let tempObj = component;\r\n tempObj[name] = value;\r\n\r\n if (this.props.onChange) {\r\n let customEvent = new CustomEvent(\"JSONObjectChanged\", {detail: {\"name\" : this.props.fieldName, \"value\" : JSON.stringify(tempObj)}})\r\n this.props.onChange(customEvent)\r\n }\r\n }\r\n }\r\n\r\n renderJSONField = (fieldKey: string) : any => {\r\n\r\n const {component} = this.state\r\n return (\r\n this.isJSON(component[fieldKey]) ? \r\n \r\n
\r\n \r\n \r\n \r\n \r\n : undefined\r\n\r\n const addFieldButton = this.state.addingField ? \r\n undefined\r\n : \r\n \r\n \r\n\r\n\r\n return (\r\n this.state.addingField ? {content}{addFieldForm} \r\n : {content}{addFieldButton}\r\n )\r\n }\r\n}","import React, { Component, Fragment } from 'react'\r\nimport { Container, Row, Col, Alert, Button } from 'reactstrap';\r\nimport LoggedContext from '../BusinessObjects/LoggedContext'\r\nimport cubeApiClient from '../BusinessObjects/cubeApiService';\r\nimport ResourceField from '../Models/ResourceField';\r\n\r\nimport EsaedroLookup from './EsaedroLookup';\r\nimport EsaedroResourceFilter from '../Models/EsaedroResourceFilter';\r\nimport { themeCol3, themeCol4, themeCol9, themeGroup, themeSpinner, themeFormInput, themeBackButton, themeUpdateButton, themeCol6, themeCol6Right, themeSaveButton } from '../Utils/EsaedroTheme';\r\nimport { StickyContainer, Sticky } from 'react-sticky';\r\n\r\nimport EsaedroPDF from './EsaedroPDF'\r\nimport EsaedroResourceAttachment from '../Models/EsaedroResourceAttachment';\r\nimport EsaedroAttachmentsController from './EsaedroAttachmentsController';\r\nimport { threadId } from 'worker_threads';\r\nimport EsaedroAttachmentLoader from './EsaedroAttachmentLoader';\r\nimport EsaedroAttachment from './EsaedroAttachment';\r\nimport EsaedroJSONComponent from './EsaedroJSONComponent';\r\n\r\nexport interface EsaedroObjectEditProps {\r\n myObjType: string\r\n myObjUrl: string\r\n myObj?: any\r\n myObjResourceID?: number,\r\n isNew: boolean\r\n filters: string\r\n fixedFields?: EsaedroResourceFilter[]\r\n onReturn?(ackMessage?: string): void\r\n onCustomHandleChange?( objChanged: any, fieldName: string): void\r\n onCustomRenderField?( editedObject: any, field: ResourceField): void\r\n}\r\n\r\ninterface EsaedroObjectEditState {\r\n myObject: any; \r\n myObjectFields: ResourceField[];\r\n myObjectFilters: EsaedroResourceFilter[];\r\n hasFields: boolean;\r\n hasGroups: boolean;\r\n myObjectGroups: any[];\r\n errorMessage: string;\r\n loading: boolean;\r\n updating: boolean;\r\n addAttachments: boolean;\r\n showAttachments: boolean;\r\n}\r\n\r\nexport default class EsaedroObjectEdit extends Component {\r\n\r\n static contextType = LoggedContext\r\n context!: React.ContextType\r\n\r\n disableUpdateBtn: boolean = false\r\n \r\n // Mi creo le mappe per gestire le lookup come variabili fuori dallo stato\r\n // Nomi dei campi delle lookup che hanno campi da controllare\r\n lookupFieldsWithFieldsToCheck : string[] = []\r\n // Campi da controllare per ogni lookup (nome campo in chiave)\r\n lookupFieldsToCheck: Map = new Map()\r\n // Key incrementali delle lookup (nome campo in chiave) - Se incrementate triggerano il render sulla relativa lookup\r\n lookupKeys: Map = new Map()\r\n\r\n constructor(props: any) {\r\n super(props);\r\n\r\n this.state = { \r\n myObject: {},\r\n myObjectFields: [],\r\n myObjectFilters: [],\r\n hasFields: false,\r\n hasGroups: false,\r\n myObjectGroups: [],\r\n errorMessage:'',\r\n loading: false,\r\n updating: false,\r\n addAttachments: false,\r\n showAttachments: false\r\n };\r\n }\r\n\r\n componentDidMount() {\r\n\r\n this.setState({loading: true})\r\n\r\n if (this.props.filters)\r\n {\r\n let filtersList = this.props.filters.split('&')\r\n\r\n filtersList.map(element => {\r\n var v =element.split('=');\r\n this.state.myObjectFilters.push(new EsaedroResourceFilter(v[0],v[1],\"=\"));\r\n });\r\n }\r\n\r\n if (!this.props.isNew && this.props.myObj!=undefined) this.setState({myObject: this.props.myObj})\r\n \r\n if(this.context.userProfile == undefined) \r\n {\r\n this.setState({errorMessage:'utente non definito'});\r\n return;\r\n }\r\n\r\n if(this.context.userProfile.customer_ID == 0) \r\n {\r\n this.setState({errorMessage:'azienda non selezionata'});\r\n return;\r\n }\r\n\r\n const service = new cubeApiClient();\r\n \r\n const t = this.context.tokenAPI;\r\n\r\n // TODO fare funzione statica (in classe Utils?) che controlla se un oggetto è filtrabile dato un filtro o Array di filtri e poi filtrare eventualmente la richiesta\r\n\r\n // TODO check che se uno fa new e ci sono campi non visible non nullabili e senza default lui non potrà mai inserire il campo\r\n const requrl = this.props.isNew? 'api/sys/ResourcesFields?RecordSelection=' + encodeURIComponent(\"ResourceName='\" + this.props.myObjType + \"'\") : 'api/sys/ResourcesFields?RecordSelection=' + encodeURIComponent(\"ResourceName='\" + this.props.myObjType + \"' and Is_Visible=1\")\r\n \r\n //const groupsURL = 'api/sys/ResourcesFieldsGroups?RecordSelection=' + encodeURIComponent(\"ResourceName='\" + this.props.myObjType + \"'\") \r\n\r\n service\r\n .getItems(requrl,t)\r\n .then((data: any) => {\r\n // Chiedo di nuovo i campi\r\n if (data)\r\n {\r\n // Capire se mettere il resto qui dentro e se fare delle richieste parallele\r\n /*service\r\n .getItems(groupsURL,t)\r\n .then((groupsData: any) => {\r\n this.setState({\r\n myObjectGroups:groupsData,\r\n hasGroups: true\r\n })\r\n },\r\n (error: any) => {\r\n this.setState({ \r\n myObjectFields:[],\r\n errorMessage: error,\r\n loading: false\r\n });\r\n });*/\r\n\r\n // Devo fare due volte l'aggiornamento dello stato, perchè l'EmptyObject ha bisogno dei field aggiornati\r\n if (this.props.isNew) {\r\n\r\n // Creo le chiavi per le varie lookup\r\n data.forEach ((field :ResourceField) => {\r\n if (field.LookupName|| field.LookupValues) this.lookupKeys.set(field.FieldName, 0)\r\n })\r\n // Aggiorno lo stato due volte\r\n this.setState({ \r\n hasFields: true,\r\n myObjectFields: data\r\n })\r\n let newObject = this.createEmptyObject()\r\n this.setState({ \r\n myObject: newObject,\r\n loading: false\r\n })\r\n }\r\n else {\r\n // Creo le chiavi per le varie lookup\r\n data.forEach ((field :ResourceField) => {\r\n if (field.LookupName|| field.LookupValues) this.lookupKeys.set(field.FieldName, 0)\r\n })\r\n // Aggiorno lo stato\r\n this.setState({ \r\n hasFields: true,\r\n myObjectFields: data,\r\n loading: false\r\n }) \r\n }\r\n }\r\n else {\r\n this.setState({\r\n errorMessage:\"Errore nello scaricare i campi\",\r\n loading: false\r\n })\r\n }\r\n },\r\n (error: any) => {\r\n this.setState({ \r\n myObjectFields:[],\r\n errorMessage: error,\r\n loading: false\r\n });\r\n });\r\n }\r\n\r\n // Chiama il servizio di update\r\n updateObject = (event: any) => {\r\n\r\n const service = new cubeApiClient();\r\n event.preventDefault();\r\n\r\n const objectToEdit = this.state.myObject;\r\n\r\n this.setState({updating:true})\r\n\r\n service\r\n .updateObject(objectToEdit, this.props.myObjUrl, this.context.tokenAPI)\r\n .then(() => {\r\n this.setState({ \r\n // Gestire il successo?\r\n errorMessage:'',\r\n updating: false\r\n });\r\n //alert(\"sto per tornare alla lista!\")\r\n if (this.props.onReturn!=undefined) {\r\n let successMsg = \"Operazione avvenuta con successo!\"\r\n this.props.onReturn(successMsg)\r\n }\r\n },\r\n (error: any) => {\r\n // Rimane qui. Problema col timestamp?\r\n let stringError = \"Errore nel salvataggio:\"+JSON.stringify(error)\r\n //alert(stringError)\r\n this.setState({ \r\n errorMessage: stringError,\r\n updating: false \r\n });\r\n });\r\n }\r\n\r\n // Gestisce i cambiamenti in input e li salva nello stato dell'object, innescando il rendering\r\n handleChange = (event: any) => {\r\n\r\n // Controllo come prima cosa che non si tratti di un customEvent\r\n if (event.type == \"DeleteFile\") {\r\n \r\n value = undefined\r\n var name = event.detail;\r\n\r\n let tempObj = this.state.myObject;\r\n tempObj[name] = value;\r\n\r\n // Inserisco qui l'eventuale callback\r\n if (this.props.onCustomHandleChange) {\r\n this.props.onCustomHandleChange(tempObj, name)\r\n }\r\n this.setState({\r\n myObject: tempObj\r\n });\r\n }\r\n\r\n else if (event.type == \"JSONObjectChanged\") {\r\n \r\n value = event.detail[\"value\"]\r\n var name = event.detail[\"name\"]\r\n let tempObj = this.state.myObject;\r\n tempObj[name] = value;\r\n\r\n // Inserisco qui l'eventuale callback\r\n if (this.props.onCustomHandleChange) {\r\n this.props.onCustomHandleChange(tempObj, name)\r\n }\r\n this.setState({\r\n myObject: tempObj\r\n });\r\n }\r\n\r\n else {\r\n const target = event.target;\r\n \r\n var value = undefined\r\n \r\n \r\n // Se è un file mi comporto diversamente\r\n if (target.type == \"file\") {\r\n var reader = new FileReader()\r\n reader.onload = () => {\r\n let imgUrl = reader.result\r\n value = imgUrl\r\n var name = target.name;\r\n\r\n let tempObj = this.state.myObject;\r\n tempObj[name] = value;\r\n\r\n // Inserisco qui l'eventuale callback\r\n if (this.props.onCustomHandleChange) {\r\n this.props.onCustomHandleChange(tempObj, name)\r\n }\r\n this.setState({\r\n myObject: tempObj\r\n });\r\n }\r\n reader.readAsDataURL(event.target.files[0])\r\n }\r\n\r\n else {\r\n\r\n if (target.type == 'checkbox') {\r\n value = target.checked\r\n }\r\n\r\n else value = target.value\r\n\r\n var name = target.name;\r\n \r\n let tempObj = this.state.myObject;\r\n tempObj[name] = value;\r\n\r\n // Inserisco qui l'eventuale callback\r\n if (this.props.onCustomHandleChange) {\r\n this.props.onCustomHandleChange(tempObj, name)\r\n }\r\n\r\n // Se è una lookup faccio un controllo sui campi da controllare. Se sono cambiati cambio la chiave a quella lookup, incrementandola nella relativa mappa\r\n if (target.type === 'select-one') {\r\n this.lookupFieldsWithFieldsToCheck.forEach ((field: string) => {\r\n var fieldsToCheck = this.lookupFieldsToCheck.get(field)\r\n if (fieldsToCheck) {\r\n for(var i=0;i< fieldsToCheck.length;i++)\r\n {\r\n if (fieldsToCheck[i]==name) {\r\n let newKey = this.lookupKeys.get(field)\r\n if (newKey == undefined) newKey = 0\r\n this.lookupKeys.set(field, newKey+1)\r\n }\r\n }\r\n }\r\n })\r\n }\r\n\r\n this.setState({\r\n myObject: tempObj\r\n });\r\n }\r\n }\r\n }\r\n\r\n // Esce dall'edit e torna alla lista di oggetti (ObjectList)\r\n returnToList = () => {\r\n if (this.props.onReturn!=undefined) {\r\n this.props.onReturn()\r\n }\r\n }\r\n\r\n // Gestise il ritorno dal componente per inserire attachments\r\n // TODO modificare\r\n onReturnFromAttachmentsController = (returnMessage: string) => {\r\n //TODO capire se stampare il messaggio da qualche parte\r\n // Svuoto gli attachments in modo che se li riapro me li ricarica\r\n //this.setState({myObjectAttachments:[]})\r\n this.toggleAddAttachments()\r\n }\r\n\r\n // Mostra il component per aggiungere allegati\r\n toggleAddAttachments = () => {\r\n this.setState({addAttachments: !this.state.addAttachments})\r\n }\r\n\r\n // Mostra il component per aggiungere allegati\r\n toggleShowAttachments = () => {\r\n this.setState({showAttachments: !this.state.showAttachments})\r\n }\r\n\r\n lookupLoadedFieldsToCheck = (fieldName: string, fieldsToCheck: any[]) => {\r\n // Setto i fields to check nella mappa\r\n if (!this.lookupFieldsWithFieldsToCheck.includes(fieldName)) this.lookupFieldsWithFieldsToCheck.push(fieldName)\r\n this.lookupFieldsToCheck.set(fieldName, fieldsToCheck)\r\n }\r\n\r\n render() {\r\n\r\n var errorMessage = (this.state.errorMessage>'')? \r\n ({this.state.errorMessage})\r\n : undefined\r\n\r\n if (this.state.loading)\r\n {\r\n return (\r\n \r\n
\r\n Aggiornamento in corso... \r\n \r\n \r\n )\r\n }\r\n\r\n else if (this.state.addAttachments) {\r\n return (\r\n \r\n \r\n )\r\n }\r\n\r\n else if (this.state.hasFields)\r\n {\r\n this.disableUpdateBtn = false\r\n\r\n // Bool per passaggio veloce da Sticky a no. Potrebbe essere in un parametro o essere tolto in futuro\r\n let isSticky = true\r\n\r\n let addAttachmentsToggleButton = this.state.addAttachments ? \r\n \r\n : \r\n\r\n let showAttachmentsToggleButton = this.state.myObject.AttachmentCount > 0? \r\n this.state.showAttachments ? \r\n \r\n : \r\n : undefined\r\n\r\n\r\n // Mostra gli allegati della risorsa\r\n let attachments = this.state.showAttachments ?\r\n \r\n \r\n : undefined\r\n\r\n let updateButton = this.state.myObject.disableEdit ?\r\n undefined\r\n : \r\n\r\n // Creo la barra di bottoni Sticky, ovvero che segue lo scroll della pagina\r\n let sticky = \r\n \r\n {({ style }) => (\r\n
\r\n \r\n \r\n \r\n \r\n Caricamento...\r\n \r\n \r\n )\r\n \r\n }\r\n\r\n // Funzione che si occupa di renderizzare ogni singolo campo in base al tipo e ai suoi parametri\r\n renderField = (field: ResourceField) => {\r\n\r\n // Qui la lista è filtrata a monte in caso di update, va gestita in caso di insert - TODO capire come gestirla\r\n if (this.props.isNew && !field.Is_Visible && !field.Is_Key && !field.Is_Nullable) return\r\n\r\n // Questi campi non devono mai essere visibili\r\n if (field.FieldName == 'dat_obsoleto' || \r\n field.FieldName == 'cod_utente_cre' || \r\n field.FieldName == 'dat_utente_cre' || \r\n field.FieldName == 'cod_utente_mod' || \r\n field.FieldName == 'dat_utente_mod') return\r\n\r\n if (this.props.isNew && !field.Is_Visible && (field.Is_Key || field.Is_Nullable)) {\r\n field.Field_Label = \"ERRORE - Campo chiave o non nullabile\"\r\n field.Readonly = true\r\n }\r\n\r\n // Se è di tipo Object List non devo mostrarlo\r\n if (field.Reffered_Resource_Type == 1 || field.Is_Decode || field.Is_Identity) return\r\n\r\n // Questi campi vanno sempre ignorati e mai visualizzati\r\n if (field.FieldName == \"ts_update\" || field.FieldName == \"flg_isdeleted\" || field.FieldName == \"dat_ultvar\") return\r\n \r\n // Qui scorro i fixed fields per trovare l'elenco dei campi non editabili\r\n if (this.props.fixedFields) {\r\n let i : number\r\n for (i=0; i\r\n
\r\n \r\n \r\n
\r\n \r\n \r\n {validationError}\r\n \r\n \r\n )\r\n }\r\n\r\n // Controllo se è un pdf e nel caso gli assegno il Field_Type 400\r\n if (field.Field_Type == 200 && field.ContentType == \"pdf\") field.Field_Type = 400 \r\n \r\n // Checkbox\r\n switch (field.Field_Type) {\r\n case 1:\r\n case 2:\r\n return (\r\n \r\n
\r\n \r\n \r\n
\r\n \r\n {validationError}\r\n \r\n \r\n )\r\n\r\n case 4:\r\n case 15:\r\n case 33:\r\n // Datetime\r\n return (\r\n \r\n
\r\n \r\n \r\n
\r\n \r\n {validationError}\r\n \r\n \r\n )\r\n case 31:\r\n // Date - Controllare MOMENT\r\n return (\r\n \r\n
\r\n \r\n \r\n
\r\n \r\n {validationError}\r\n \r\n \r\n )\r\n case 32:\r\n // Time - Controllare MOMENT\r\n return (\r\n \r\n
\r\n \r\n \r\n
\r\n \r\n {validationError}\r\n \r\n \r\n )\r\n\r\n case 400:\r\n // PDF - Assegnato a monte\r\n // Creo il component per il PDF\r\n //return \r\n return ( \r\n \r\n
\r\n \r\n {validationError}\r\n \r\n \r\n )\r\n }\r\n }\r\n\r\n // Valida i campi e genera i messaggi da mostrare in tempo reale sotto al campo stesso\r\n validateField = (field: ResourceField) => {\r\n // TODO Lookup\r\n // Ritorna null se il campo è valido -> governa il tasto update\r\n // Come gestire la stringa vuota???\r\n var valueToCheck = this.state.myObject[field.FieldName]\r\n \r\n if (field.Is_Key && valueToCheck!==0 && valueToCheck!==false && valueToCheck===undefined) return (\r\n \r\n Questo campo è chiave e dunque obbligatorio\r\n \r\n ) \r\n if (!field.Is_Nullable && valueToCheck!==false && valueToCheck!==0 && valueToCheck===undefined) return (\r\n \r\n Questo campo non può essere nullo\r\n \r\n )\r\n\r\n if (field.Required && valueToCheck!==false && valueToCheck!==0 && (valueToCheck===undefined || valueToCheck=='')) return (\r\n \r\n Questo campo è obbligatorio\r\n \r\n )\r\n\r\n if (valueToCheck) {\r\n // Controllo la lunghezza\r\n if (field.Field_Size > 0 && valueToCheck.length > field.Field_Size) return (\r\n \r\n Questo campo supera la lunghezza massima consentita\r\n \r\n )\r\n //Se è un numero controllo che ci siano solo cifre\r\n if ((field.Field_Type == 0 || field.Field_Type == 5 || field.Field_Type == 6 || field.Field_Type == 8 || field.Field_Type == 13 ) && isNaN(valueToCheck)) return (\r\n \r\n Questo campo deve essere numerico\r\n \r\n )\r\n }\r\n \r\n return null\r\n }\r\n\r\n // In caso di New, crea un oggetto nuovo secondo la lista di proprietà (fields) ricevuta\r\n createEmptyObject = (): any => {\r\n\r\n // customer ID \r\n var objToRet: any = {}\r\n if (this.state.hasFields)\r\n {\r\n\r\n objToRet.customer_ID = this.context.userProfile.customer_ID\r\n\r\n this.state.myObjectFields.map((field: ResourceField) => {\r\n \r\n switch (field.Field_Type) {\r\n case 1:\r\n case 2:\r\n objToRet[field.FieldName] = field.DefaultValue\r\n ?field.DefaultValue==\"1\"\r\n ?true\r\n :field.DefaultValue==\"0\"\r\n ?false\r\n :field.DefaultValue\r\n :false\r\n break\r\n \r\n default:\r\n objToRet[field.FieldName] = field.DefaultValue?field.DefaultValue:undefined\r\n }\r\n\r\n // Qui scorro i fixed fields per trovare l'elenco dei campi fixed e settarli\r\n if (this.props.fixedFields) {\r\n let i : number\r\n for (i=0; i