OfficeDev / office-js

A repo and NPM package for Office.js, corresponding to a copy of what gets published to the official "evergreen" Office.js CDN, at https://appsforoffice.microsoft.com/lib/1/hosted/office.js.
https://learn.microsoft.com/javascript/api/overview
Other
669 stars 95 forks source link

Office.context.ui.messageParent is not sending message to parent #3463

Open jorgk3 opened 1 year ago

jorgk3 commented 1 year ago

I'm developing an add-on for mail decryption. The "mainline" of the add-in communicates with a local decryption server, then displays the result in a dialogue window. I found that Office.context.ui.messageParent() doesn't trigger the listener in the add-on mainline reliably. It works the first time when selecting and decrypting the first message, but not on any subsequent messages.

Here's the code:

Mainline:

// Decrypt received message
async function decrypt(event) {
  console.log("=== decrypt: event", event);
  let mailbox = Office.context.mailbox;
  let mailboxItem = mailbox.item;

  let message = {};
  message.subject = mailboxItem.subject;
  message.from = mailboxItem.from;
  message.to = mailboxItem.to;
  message.cc = mailboxItem.cc;
  // The following doesn't yield anything, we need to get the body via EWS and decrypt it.
  // mailboxItem.body.getAsync(Office.CoercionType.Text, {}, (result) => console.log("=== body", result));
  message.body = { text: "could not retrieve" };
  let mimeTextResult = await getMimeMessageViaEWS(mailbox, mailboxItem);
  let mimeText;
  if (mimeTextResult.status == "succeeded") {
    let tagPos = mimeTextResult.value.indexOf("<t:MimeContent CharacterSet=\"UTF-8\">");
    mimeText = mimeTextResult.value.substring(tagPos + 36);
    tagPos = mimeText.indexOf("</t:MimeContent>");
    mimeText = mimeText.substring(0, tagPos);
    mimeText = atob(mimeText);
  }
  // console.log(mimeText);
  let pEpMsg = await pEpController.cache_mime_decode_message(mimeText);
  let pEpMsgDecrypted = await pEpController.cache_decrypt_message(pEpMsg);
  message.subject = pEpMsgDecrypted.shortmsg;
  message.body = { text: pEpMsgDecrypted.longmsg, html: pEpMsgDecrypted.longmsg_formatted };

  let gotCallback = false;
  Office.context.ui.displayDialogAsync("https://localhost:44384/MessageRead.html", {
    displayInIframe: true, promptBeforeOpen: false, height: 60, width: 60,
  }, async (openDialogResult) => {
    let dialog = openDialogResult.value;
    console.log("=== We got the dialogue", openDialogResult);
    dialog.addEventHandler(Office.EventType.DialogMessageReceived, (arg) => {
      console.log("Sending this to the dialogue", message);
      dialog.messageChild(JSON.stringify(message));
      gotCallback = true;
      // If we don't call `event.completed();` here, we get this in the UI:
      // <add-in> is working on your <name> request. Dismiss.
      // If we call `event.completed();` here, the dialogue can't be closed any more.
      // So that's a lose-lose situation :-(
      // event.completed();
    });
    console.log("=== listener attached");
    await new Promise(r => setTimeout(r, 2000));
    if (!gotCallback) {
      console.log("=== we didn't get the callback");
      dialog.messageChild(JSON.stringify(message));
    }
  });
}

Dialog code:

Office.onReady(() => {
  console.log("onReady()!");
  Office.context.ui.addHandlerAsync(Office.EventType.DialogParentMessageReceived, onMessageFromParent, onRegisterMessageComplete);
});

async function onRegisterMessageComplete(asyncResult) {
  if (asyncResult.status !== Office.AsyncResultStatus.Succeeded) {
    reportError(asyncResult.error.message);
  } else {
    console.log("onMessageFromParent registered");
    Office.context.ui.messageParent("Ready", { targetOrigin: "*" });
    console.log("Ready sent!");
  }
}

function onMessageFromParent(arg) {
  // Write message property values to the task pane
  // console.log(arg.message);
...

Here's a screenshot of all the debugging output when it works:

image

Here's a screenshot of the debugging output when it doesn't work.

image

exextoc commented 1 year ago

@jorgk3 We are unable to repro this issue. We need more information to investigate further-

  1. What is build no. of New Outlook?
  2. Does the issue repro for you on OWA? If Yes, what is build no?
  3. Is it consistent repro after first time?
  4. Can you share sample addin manifest where issue reproes?
jorgk3 commented 1 year ago

Thanks for the quick reply. I'll see whether I can dummy-up the calls to our local decryption server and supply a full add-on that reproduces the issue.

As for the questions:

  1. Hmm, I'm running that on Outlook.com (O365).
  2. What do you mean by OWA (Outlook Web Access) in this case? Is Outlook.com considered to be OWA or do you mean an on-premises OWA?
  3. Yes, the callback is received on the first message, not on subsequent ones. It also keeps working when running the add-on on the first message again.
  4. See comment above. This will take some time.
jorgk3 commented 1 year ago

Creating the dummy was easier than I thought: https://github.com/jorgk3/OfficeDevPrivate/blob/main/planckForOLWeb.zip So click on the first message, run "planck for Outlook web" from the "three dots" menu, then select a different message and do the same. Check output in the browser console. @exextoc invited to the private repo.

exextoc commented 1 year ago

@jorgk3 Thanks for sharing the repo. We are still unable to repro the bug. Can you please share a video of the bug so that we can confirm the behaviour?

jorgk3 commented 1 year ago

Here you go. Please compare the console output with the code.

You will notice that the dialogue is only populated after 2 seconds when the timeout triggers.

Are you saying that when you run the sample, it behaves differently?

exextoc commented 1 year ago

@jorgk3 We are able to repro the issue now. It has been put on our backlog. We, unfortunately, have no timelines to share at this point. Internal tracking id: Eg: Office: 215905

Stereodark commented 1 year ago

I experienced the same issue, it would be good to know when this can be fixed

nicolasHul commented 9 months ago

I am also experiencing the same issue.. I can't seem to find backlogitem 215905, what is the current status?

kbrilla commented 9 months ago

Same here, nothing I try works. Event tried to log some incoming messages to parent with

const listener = (event) => {
      if (event.data) {
        const data = JSON.parse(event.data);
        if (data && 'dialogMessage' in data) {
          console.log(data);
        }
      }
    };

    window.addEventListener('message', listener, false);

This code works in Outlook for Mac on desktop as a workaround that Office.EventType.DialogMessageReceived event is not recived on dialog object but does not work on Office online.

messageParent does not return any errors for me.

listener was added to both iframe and top window

kbrilla commented 8 months ago

Any updates @exextoc? This issue is waiting since Jully. Current state of things does not allow user to login through dialog like recomended in documentation.

kbrilla commented 8 months ago

Ok I know what problem partially is and have workaround for anyone who want to use it. As for the problem it is that in outllok on desktop event that is sent to addin is in form of an stringlified JSON with dialogMessage field but in case of OWA it is sent as plain text exacly as sent throught messageParent.

 const listener = (event: MessageEvent) => {
      if (event.data) {
        console.debug(event);
        try {
          const data = JSON.parse(event.data) as object;
          if (data && 'dialogMessage' in data) {
            const dialogMessage = data.dialogMessage as { messageContent: string };
            const messageContent = dialogMessage.messageContent;
            if (messageContent) {
              this.handleMessageContent(messageContent);
            } else {
              console.error('no message content');
            }
          this.closeAndClearDialog(); //we need to manually close the dialog so save instance of it in some property
          }
        } catch (err) {
          console.debug('dialogMessage is not an object');
          const data = event.data as unknown;
          if (typeof data === 'string') {
            if (data) {
             this.handleMessageContent(messageContent);
              this.closeAndClearDialog(); //we need to manually close the dialog so save instance of it in some property
            } else {
              console.error('no message content');
            }
          }
        }
      }
    };

    window.addEventListener('message', listener, false);
dahuja10 commented 2 months ago

@jorgk3 We are investigating this issue, but this add-in is no longer available. We are unable to reproduce this issue without the add-in, can you please share the sample add-in so that we can look into this.

jorgk3 commented 2 months ago

this add-in is no longer available

What is no longer available? See https://github.com/OfficeDev/office-js/issues/3463#issuecomment-1609008464

dahuja10 commented 1 month ago

@jorgk3 we are able to repro the issue and are working on resolving it.