Skip to content

Commit

Permalink
Added support for timeline email attachments
Browse files Browse the repository at this point in the history
  • Loading branch information
DynamicsNinja committed Jun 11, 2019
1 parent 2662fb4 commit bac658d
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 30 deletions.
4 changes: 3 additions & 1 deletion GalleryFieldControl/ControlManifest.Input.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<manifest>
<control namespace="Fic" constructor="GalleryFieldControl" version="1.1.0" display-name-key="GalleryFieldControl_Display_Key" description-key="GalleryFieldControl_Desc_Key" control-type="standard">
<control namespace="Fic" constructor="GalleryFieldControl" version="1.2.0" display-name-key="Fic.GalleryFieldControl" description-key="Fic.GalleryFieldControl" control-type="standard">
<property name="sampleProperty" display-name-key="Property_Display_Key" description-key="Property_Desc_Key" of-type="SingleLine.Text" usage="bound" required="true" />
<property name="thumbnailHeight" display-name-key="Thumbnail Height(px)" description-key="Thumbnail Height(px)" of-type="Whole.None" usage="input" required="false" />
<property name="thumbnailWidth" display-name-key="Thumbnail Width(px)" description-key="Thumbnail Width(px)" of-type="Whole.None" usage="input" required="false" />
<resources>
<code path="index.ts" order="1"/>
<css path="css/GalleryFieldControl.css" order="1"/>
Expand Down
18 changes: 10 additions & 8 deletions GalleryFieldControl/css/GalleryFieldControl.css
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
.Fic\.GalleryFieldControl .thumbnail img {
border: 1px solid #ddd;
border-radius: 4px;
border: 1px solid #ddd;
border-radius: 4px;
padding: 5px;
width: 150px;
height: 150px;
}

.Fic\.GalleryFieldControl .thumbnail img:hover {
box-shadow: 0 0 2px 1px rgba(0, 140, 186, 0.5);
cursor: pointer;
Expand All @@ -20,7 +18,6 @@
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 162px;
text-align: center;
}

Expand All @@ -30,8 +27,13 @@

.Fic\.GalleryFieldControl .preview-img {
max-width: 100%;
margin-top: 10px;
}

.Fic\.GalleryFieldControl .section-header {
margin: 5px 0px 5px 0px;
}



.Fic\.GalleryFieldControl .files-group {
border-bottom: 1px solid rgb(216, 216, 216);
}
118 changes: 97 additions & 21 deletions GalleryFieldControl/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ export class GalleryFieldControl implements ComponentFramework.StandardControl<I

private _context: ComponentFramework.Context<IInputs>;
private _container: HTMLDivElement;
private _mainDiv: HTMLDivElement;

private _thumbnailHeight: number | null;
private _thumbnailWidth: number | null;

private _notesContainer: HTMLDivElement;
private _timelineEmailsContainer: HTMLDivElement;

private _previewImage: HTMLImageElement;

private _thumbnailClicked: EventListenerOrEventListenerObject;
Expand All @@ -53,15 +59,45 @@ export class GalleryFieldControl implements ComponentFramework.StandardControl<I
this._context = context;
this._container = container;

this._thumbnailHeight = context.parameters.thumbnailHeight == undefined ? null : context.parameters.thumbnailHeight.raw;
this._thumbnailWidth = context.parameters.thumbnailWidth == undefined ? null : context.parameters.thumbnailWidth.raw;

let reference: EntityReference = new EntityReference(
(<any>context).page.entityTypeName,
(<any>context).page.entityId
)

this._thumbnailClicked = this.ThumbnailClicked.bind(this);
this._clearPreviewImage = this.ClearPreviewImage.bind(this);

let mainDiv = document.createElement("div");
mainDiv.classList.add("carousel");
let notesContainer = document.createElement("div");
notesContainer.classList.add("files-group");
this._notesContainer = notesContainer;

let notesHeader = document.createElement("div");
notesHeader.textContent = reference.typeName == "email" ? "Attachments" : "Notes";
notesHeader.classList.add("section-header");
notesContainer.appendChild(notesHeader);

let notes = document.createElement("div");
notesContainer.appendChild(notes);


this._mainDiv = mainDiv;
let timelineEmailsContainer = document.createElement("div");
timelineEmailsContainer.classList.add("files-group");
this._timelineEmailsContainer = timelineEmailsContainer;

this._container.appendChild(mainDiv);
let timelineEmailsHeader = document.createElement("div");
timelineEmailsHeader.textContent = "Timeline Emails";
timelineEmailsHeader.classList.add("section-header");
timelineEmailsContainer.appendChild(timelineEmailsHeader);

let timelineEmails = document.createElement("div");
timelineEmailsContainer.appendChild(timelineEmails);


this._container.appendChild(notesContainer);
this._container.appendChild(timelineEmailsContainer);

let previewImg = document.createElement("img");
previewImg.classList.add("preview-img");
Expand All @@ -71,12 +107,8 @@ export class GalleryFieldControl implements ComponentFramework.StandardControl<I

this._container.appendChild(previewImg);

let reference: EntityReference = new EntityReference(
(<any>context).page.entityTypeName,
(<any>context).page.entityId
)

this.GetFiles(reference).then(result => this.RenderThumbnails(result));
this.GetFiles(reference).then(result => this.RenderThumbnails(result, notes));
this.GetEmailAttachemntsFromTimeline(reference).then(result => this.RenderThumbnails(result, timelineEmails));
}


Expand Down Expand Up @@ -104,21 +136,62 @@ export class GalleryFieldControl implements ComponentFramework.StandardControl<I
// Add code to cleanup control if necessary
}


private async GetFiles(ref: EntityReference): Promise<AttachedFile[]> {
let attachmentType = ref.typeName == "email" ? "activitymimeattachment": "annotation";
let attachmentType = ref.typeName == "email" ? "activitymimeattachment" : "annotation";
let fetchXml =
"<fetch>" +
" <entity name='"+attachmentType+"'>" +
" <filter>" +
" <condition attribute='objectid' operator='eq' value='" + ref.id + "'/>" +
" </filter>" +
" </entity>" +
"</fetch>";
"<fetch>" +
" <entity name='" + attachmentType + "'>" +
" <filter>" +
" <condition attribute='objectid' operator='eq' value='" + ref.id + "'/>" +
" </filter>" +
" </entity>" +
"</fetch>";

let query = '?fetchXml=' + encodeURIComponent(fetchXml);

try {
const result = await this._context.webAPI.retrieveMultipleRecords(attachmentType, query);
if (result.entities.length == 0) { this._notesContainer.hidden = true; }
let items = [];
for (let i = 0; i < result.entities.length; i++) {
let record = result.entities[i];
let fileName = <string>record["filename"];
let mimeType = <string>record["mimetype"];
let content = <string>record["body"] || <string>record["documentbody"];
let fileSize = <number>record["filesize"];

if (!this.supportedMimeTypes.includes(mimeType)) { continue; }

let file = new AttachedFile(fileName, mimeType, content, fileSize);
items.push(file);
}
return items;
}
catch (error) {
return [];
}
}

private async GetEmailAttachemntsFromTimeline(ref: EntityReference) {

let fetchXml =
"<fetch>" +
" <entity name='activitymimeattachment'>" +
" <link-entity name='email' from='activityid' to='objectid'>" +
" <filter>" +
" <condition attribute='regardingobjectid' operator='eq' value='{" + ref.id + "}'/>" +
" </filter>" +
" </link-entity>" +
" </entity>" +
"</fetch>";


let query = '?fetchXml=' + encodeURIComponent(fetchXml);

try {
const result = await this._context.webAPI.retrieveMultipleRecords("activitymimeattachment", query);
if (result.entities.length == 0) { this._timelineEmailsContainer.hidden = true; }
let items = [];
for (let i = 0; i < result.entities.length; i++) {
let record = result.entities[i];
Expand All @@ -139,7 +212,7 @@ export class GalleryFieldControl implements ComponentFramework.StandardControl<I
}
}

private RenderThumbnails(files: AttachedFile[]) {
private RenderThumbnails(files: AttachedFile[], container: HTMLDivElement) {
for (let index = 0; index < files.length; index++) {
const file = files[index];

Expand All @@ -151,19 +224,22 @@ export class GalleryFieldControl implements ComponentFramework.StandardControl<I

let imageDiv = document.createElement("img");
imageDiv.src = 'data:' + file.mimeType + ';base64, ' + file.fileContent;
imageDiv.height = this._thumbnailHeight == null ? 150 : this._thumbnailHeight;
imageDiv.width = this._thumbnailWidth == null ? 150 : this._thumbnailWidth;
imageDiv.addEventListener("click", this._thumbnailClicked);

thumbnailDiv.appendChild(imageDiv);

let fileNameDiv = document.createElement("div");
fileNameDiv.classList.add("file-name");
fileNameDiv.style.width = (this._thumbnailWidth == null ? 162 : this._thumbnailWidth+12).toString() + "px";
fileNameDiv.textContent = file.fileName;
fileNameDiv.onclick = (e => { this.DownloadFile(file); });

itemContainer.appendChild(thumbnailDiv);
itemContainer.appendChild(fileNameDiv);

this._mainDiv.appendChild(itemContainer);
container.appendChild(itemContainer);
}
}

Expand Down

0 comments on commit bac658d

Please sign in to comment.