-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #31 from ramarao9/allow-note-attachment
add changes for the UseNoteAttachment property
- Loading branch information
Showing
6 changed files
with
3,432 additions
and
4,317 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,4 +11,6 @@ | |
|
||
# msbuild output directories | ||
/bin | ||
/obj | ||
/obj | ||
.DS_Store | ||
~/Library/Microsoft/PowerAppsCli/usersettings.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,18 @@ | ||
import * as React from "react"; | ||
import { IInputs } from "./generated/ManifestTypes" | ||
import {useDropzone} from 'react-dropzone' | ||
import { useDropzone } from 'react-dropzone' | ||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' | ||
import { IconProp } from '@fortawesome/fontawesome-svg-core'; | ||
import { faSpinner } from '@fortawesome/free-solid-svg-icons' | ||
|
||
export interface UploadProps { | ||
id: string; | ||
entityName:string; | ||
entitySetName:string; | ||
controlToRefresh:string|null; | ||
uploadIcon:string; | ||
context: ComponentFramework.Context<IInputs>|undefined; | ||
id: string; | ||
entityName: string; | ||
entitySetName: string; | ||
controlToRefresh: string | null; | ||
uploadIcon: string; | ||
useNoteAttachment: boolean; | ||
context: ComponentFramework.Context<IInputs> | undefined; | ||
} | ||
|
||
export interface FileInfo { | ||
|
@@ -20,152 +22,151 @@ export interface FileInfo { | |
} | ||
|
||
export const AttachmentUploader: React.FC<UploadProps> = (uploadProps: UploadProps) => { | ||
|
||
const [uploadIcn,setuploadIcn]=React.useState(uploadProps.uploadIcon); | ||
const [totalFileCount, setTotalFileCount] = React.useState(0); | ||
const [currentUploadCount, setCurrentUploadCount] = React.useState(0); | ||
const translate = (name:string) => uploadProps.context?.resources.getString(name); | ||
|
||
const onDrop = React.useCallback((acceptedFiles:any) => { | ||
|
||
if(acceptedFiles && acceptedFiles.length){ | ||
setTotalFileCount(acceptedFiles.length); | ||
} | ||
|
||
|
||
const toBase64 = async (file:any) => new Promise((resolve, reject) => { | ||
const reader = new FileReader(); | ||
reader.readAsDataURL(file); | ||
reader.onload = () => resolve(reader.result); | ||
reader.onabort = () => reject(); | ||
reader.onerror = error => reject(error); | ||
}); | ||
|
||
const uploadFileToRecord = async (id: string, entity: string,entitySetName:string, | ||
fileInfo: FileInfo,context: ComponentFramework.Context<IInputs>)=>{ | ||
|
||
let isActivityMimeAttachment = (entity.toLowerCase() === "email" || entity.toLowerCase() === "appointment"); | ||
let attachmentRecord: ComponentFramework.WebApi.Entity = {}; | ||
if (isActivityMimeAttachment) { | ||
attachmentRecord["[email protected]"] = `/activitypointers(${id})`; | ||
attachmentRecord["body"] = fileInfo.body; | ||
} | ||
else { | ||
attachmentRecord[`objectid_${entity}@odata.bind`] = `/${entitySetName}(${id})`; | ||
attachmentRecord["documentbody"] = fileInfo.body; | ||
} | ||
|
||
if(fileInfo.type && fileInfo.type!==""){ | ||
attachmentRecord["mimetype"] =fileInfo.type; | ||
} | ||
|
||
attachmentRecord["filename"] = fileInfo.name; | ||
attachmentRecord["objecttypecode"] = entity; | ||
let attachmentEntity = isActivityMimeAttachment ? "activitymimeattachment" : "annotation"; | ||
await context.webAPI.createRecord(attachmentEntity, attachmentRecord) | ||
} | ||
|
||
const [uploadIcn, setuploadIcn] = React.useState(uploadProps.uploadIcon); | ||
const [totalFileCount, setTotalFileCount] = React.useState(0); | ||
const [currentUploadCount, setCurrentUploadCount] = React.useState(0); | ||
const translate = (name: string) => uploadProps.context?.resources.getString(name); | ||
|
||
const uploadFilesToCRM = async (files: any) => { | ||
|
||
|
||
try{ | ||
for(let i=0;i<acceptedFiles.length;i++) | ||
{ | ||
setCurrentUploadCount(i); | ||
let file=acceptedFiles[i] as any; | ||
let base64Data=await toBase64(acceptedFiles[i]); | ||
let base64DataStr=base64Data as string; | ||
let base64IndexOfBase64 = base64DataStr.indexOf(';base64,') + ';base64,'.length; | ||
var base64 = base64DataStr.substring(base64IndexOfBase64); | ||
let fileInfo:FileInfo ={name:file.name,type:file.type,body:base64}; | ||
let entityId = uploadProps.id; | ||
let entityName = uploadProps.entityName; | ||
|
||
if (entityId == null || entityId === "") {//this happens when the record is created and the user tries to upload | ||
let currentPageContext = uploadProps.context as any; | ||
currentPageContext = currentPageContext ? currentPageContext["page"] : undefined; | ||
entityId = currentPageContext.entityId; | ||
entityName = currentPageContext.entityTypeName; | ||
} | ||
|
||
await uploadFileToRecord(entityId,entityName,uploadProps.entitySetName, fileInfo,uploadProps.context!!); | ||
} | ||
} | ||
catch(e: any){ | ||
let errorMessagePrefix=(acceptedFiles.length===1) ? translate("error_while_uploading_attachment") : translate("error_while_uploading_attachments"); | ||
let errOptions={message:`${errorMessagePrefix} ${e.message}`}; | ||
uploadProps.context?.navigation.openErrorDialog(errOptions) | ||
const onDrop = React.useCallback((acceptedFiles: any) => { | ||
|
||
if (acceptedFiles && acceptedFiles.length) { | ||
setTotalFileCount(acceptedFiles.length); | ||
} | ||
|
||
|
||
const toBase64 = async (file: any) => new Promise((resolve, reject) => { | ||
const reader = new FileReader(); | ||
reader.readAsDataURL(file); | ||
reader.onload = () => resolve(reader.result); | ||
reader.onabort = () => reject(); | ||
reader.onerror = error => reject(error); | ||
}); | ||
|
||
const uploadFileToRecord = async (id: string, entity: string, entitySetName: string, | ||
fileInfo: FileInfo, context: ComponentFramework.Context<IInputs>) => { | ||
|
||
let isActivityMimeAttachment = !uploadProps.useNoteAttachment && (entity.toLowerCase() === "email" || entity.toLowerCase() === "appointment"); | ||
let attachmentRecord: ComponentFramework.WebApi.Entity = {}; | ||
if (isActivityMimeAttachment) { | ||
attachmentRecord["[email protected]"] = `/activitypointers(${id})`; | ||
attachmentRecord["body"] = fileInfo.body; | ||
} | ||
else { | ||
attachmentRecord[`objectid_${entity}@odata.bind`] = `/${entitySetName}(${id})`; | ||
attachmentRecord["documentbody"] = fileInfo.body; | ||
} | ||
|
||
if (fileInfo.type && fileInfo.type !== "") { | ||
attachmentRecord["mimetype"] = fileInfo.type; | ||
} | ||
|
||
attachmentRecord["filename"] = fileInfo.name; | ||
attachmentRecord["objecttypecode"] = entity; | ||
let attachmentEntity = isActivityMimeAttachment ? "activitymimeattachment" : "annotation"; | ||
await context.webAPI.createRecord(attachmentEntity, attachmentRecord) | ||
} | ||
|
||
|
||
const uploadFilesToCRM = async (files: any) => { | ||
|
||
|
||
try { | ||
for (let i = 0; i < acceptedFiles.length; i++) { | ||
setCurrentUploadCount(i); | ||
let file = acceptedFiles[i] as any; | ||
let base64Data = await toBase64(acceptedFiles[i]); | ||
let base64DataStr = base64Data as string; | ||
let base64IndexOfBase64 = base64DataStr.indexOf(';base64,') + ';base64,'.length; | ||
var base64 = base64DataStr.substring(base64IndexOfBase64); | ||
let fileInfo: FileInfo = { name: file.name, type: file.type, body: base64 }; | ||
let entityId = uploadProps.id; | ||
let entityName = uploadProps.entityName; | ||
|
||
if (entityId == null || entityId === "") {//this happens when the record is created and the user tries to upload | ||
let currentPageContext = uploadProps.context as any; | ||
currentPageContext = currentPageContext ? currentPageContext["page"] : undefined; | ||
entityId = currentPageContext.entityId; | ||
entityName = currentPageContext.entityTypeName; | ||
} | ||
|
||
setTotalFileCount(0); | ||
let xrmObj: any = (window as any)["Xrm"]; | ||
if (xrmObj && xrmObj.Page && uploadProps.controlToRefresh) { | ||
var controlToRefresh = xrmObj.Page.getControl(uploadProps.controlToRefresh); | ||
if (controlToRefresh) { | ||
controlToRefresh.refresh(); | ||
} | ||
} | ||
await uploadFileToRecord(entityId, entityName, uploadProps.entitySetName, fileInfo, uploadProps.context!!); | ||
} | ||
} | ||
catch (e: any) { | ||
let errorMessagePrefix = (acceptedFiles.length === 1) ? translate("error_while_uploading_attachment") : translate("error_while_uploading_attachments"); | ||
let errOptions = { message: `${errorMessagePrefix} ${e.message}` }; | ||
uploadProps.context?.navigation.openErrorDialog(errOptions) | ||
} | ||
|
||
setTotalFileCount(0); | ||
let xrmObj: any = (window as any)["Xrm"]; | ||
if (xrmObj && xrmObj.Page && uploadProps.controlToRefresh) { | ||
var controlToRefresh = xrmObj.Page.getControl(uploadProps.controlToRefresh); | ||
if (controlToRefresh) { | ||
controlToRefresh.refresh(); | ||
} | ||
} | ||
} | ||
|
||
|
||
uploadFilesToCRM(acceptedFiles); | ||
uploadFilesToCRM(acceptedFiles); | ||
|
||
|
||
|
||
|
||
}, [totalFileCount,currentUploadCount]) | ||
|
||
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop }) | ||
}, [totalFileCount, currentUploadCount]) | ||
|
||
|
||
if (uploadProps.id==null ||uploadProps.id === "") { | ||
return ( | ||
<div className={"defaultContentCont"}> | ||
{translate("save_record_to_enable_content")} | ||
</div> | ||
); | ||
} | ||
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop }) | ||
|
||
|
||
if (uploadProps.id == null || uploadProps.id === "") { | ||
return ( | ||
<div className={"defaultContentCont"}> | ||
{translate("save_record_to_enable_content")} | ||
</div> | ||
); | ||
} | ||
|
||
let fileStats = null; | ||
if (totalFileCount > 0) { | ||
fileStats = ( | ||
<div className={"filesStatsCont uploadDivs"}> | ||
<div> | ||
<FontAwesomeIcon icon={faSpinner as IconProp} inverse size="2x" spin /> | ||
</div> | ||
<div className={"uploadStatusText"}> | ||
{translate("uploading")} ({currentUploadCount}/{totalFileCount}) | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
|
||
|
||
return ( | ||
<div className={"dragDropCont"}> | ||
<div className={"dropZoneCont uploadDivs"} {...getRootProps()} style={{ backgroundColor: isDragActive ? '#F8F8F8' : 'white' }}> | ||
<input {...getInputProps()} /> | ||
<div> | ||
<img className={"uploadImgDD"} src={uploadIcn} alt="Upload" /> | ||
</div> | ||
<div> | ||
{ | ||
isDragActive ? | ||
<p>{translate("drop_files_here")}</p> : | ||
<p>{translate("drop_files_here_or_click_to_upload")}</p> | ||
} | ||
</div> | ||
</div> | ||
|
||
{fileStats} | ||
|
||
|
||
|
||
</div> | ||
) | ||
|
||
let fileStats = null; | ||
if (totalFileCount > 0) { | ||
fileStats = ( | ||
<div className={"filesStatsCont uploadDivs"}> | ||
<div> | ||
<FontAwesomeIcon icon={faSpinner} inverse size="2x" spin /> | ||
</div> | ||
<div className={"uploadStatusText"}> | ||
{translate("uploading")} ({currentUploadCount}/{totalFileCount}) | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
|
||
|
||
return ( | ||
<div className={"dragDropCont"}> | ||
<div className={"dropZoneCont uploadDivs"} {...getRootProps()} style={{ backgroundColor: isDragActive ? '#F8F8F8' : 'white' }}> | ||
<input {...getInputProps()} /> | ||
<div> | ||
<img className={"uploadImgDD"} src={uploadIcn} alt="Upload" /> | ||
</div> | ||
<div> | ||
{ | ||
isDragActive ? | ||
<p>{translate("drop_files_here")}</p> : | ||
<p>{translate("drop_files_here_or_click_to_upload")}</p> | ||
} | ||
</div> | ||
</div> | ||
|
||
{ fileStats } | ||
|
||
|
||
|
||
</div> | ||
) | ||
|
||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.