I am trying to add a button to the AppointmentOrganizerCommandSurface in Outlook just like Giphy is added in this image, but instead, my My Office Add-in is added to the menu.
I would like to add an action button with my custom icon next to the Giphy action.
I tried manipulating manifest.xml. I went through the documentation and followed the steps, but I was unable to figure out what is going on.
Here is the manifest:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0" xmlns:mailappor="http://schemas.microsoft.com/office/mailappversionoverrides/1.0" xsi:type="MailApp">
<Id>61262617-dad8-4e84-a9e4-89b1bab3e6e7</Id>
<Version>1.0.0.0</Version>
<ProviderName>Contoso</ProviderName>
<DefaultLocale>en-US</DefaultLocale>
<DisplayName DefaultValue="My Office Add-In"/>
<Description DefaultValue="A template to get started."/>
<IconUrl DefaultValue="https://localhost:3000/assets/icon-64.png"/>
<HighResolutionIconUrl DefaultValue="https://localhost:3000/assets/icon-128.png"/>
<SupportUrl DefaultValue="https://www.contoso.com/help"/>
<AppDomains>
<AppDomain>https://www.contoso.com</AppDomain>
</AppDomains>
<Hosts>
<Host Name="Mailbox"/>
</Hosts>
<Requirements>
<Sets>
<Set Name="Mailbox" MinVersion="1.1"/>
</Sets>
</Requirements>
<FormSettings>
<Form xsi:type="ItemRead">
<DesktopSettings>
<SourceLocation DefaultValue="https://localhost:3000/taskpane.html"/>
<RequestedHeight>250</RequestedHeight>
</DesktopSettings>
</Form>
</FormSettings>
<Permissions>ReadWriteItem</Permissions>
<Rule xsi:type="RuleCollection" Mode="Or">
<Rule xsi:type="ItemIs" ItemType="Message" FormType="Read"/>
</Rule>
<DisableEntityHighlighting>false</DisableEntityHighlighting>
<VersionOverrides xmlns="http://schemas.microsoft.com/office/mailappversionoverrides" xsi:type="VersionOverridesV1_0">
<Requirements>
<bt:Sets DefaultMinVersion="1.3">
<bt:Set Name="Mailbox"/>
</bt:Sets>
</Requirements>
<Hosts>
<Host xsi:type="MailHost">
<DesktopFormFactor>
<FunctionFile resid="Commands.Url"/>
<ExtensionPoint xsi:type="AppointmentOrganizerCommandSurface">
<OfficeTab id="TabDefault">
<Group id="msgReadGroup">
<Label resid="GroupLabel"/>
<Control xsi:type="Button" id="msgReadOpenPaneButton">
<Label resid="TaskpaneButton.Label"/>
<Supertip>
<Title resid="TaskpaneButton.Label"/>
<Description resid="TaskpaneButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ShowTaskpane">
<SourceLocation resid="Taskpane.Url"/>
</Action>
</Control>
<Control xsi:type="Button" id="ActionButton">
<Label resid="ActionButton.Label"/>
<Supertip>
<Title resid="ActionButton.Label"/>
<Description resid="ActionButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>action</FunctionName>
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="Icon.16x16" DefaultValue="https://localhost:3000/assets/icon-16.png"/>
<bt:Image id="Icon.32x32" DefaultValue="https://localhost:3000/assets/icon-32.png"/>
<bt:Image id="Icon.80x80" DefaultValue="https://localhost:3000/assets/icon-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="Commands.Url" DefaultValue="https://localhost:3000/commands.html"/>
<bt:Url id="Taskpane.Url" DefaultValue="https://localhost:3000/taskpane.html"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="GroupLabel" DefaultValue="Contoso Add-in"/>
<bt:String id="TaskpaneButton.Label" DefaultValue="Show Taskpane"/>
<bt:String id="ActionButton.Label" DefaultValue="Perform an action"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="TaskpaneButton.Tooltip" DefaultValue="Opens a pane displaying all available properties."/>
<bt:String id="ActionButton.Tooltip" DefaultValue="Perform an action when clicked."/>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</OfficeApp>
Thank you in advance.
You need to pin your add-in in the outlook to acheive the same.
You can pin an add-in so it's easily available when you're composing an email message.
Select Settings> View all Outlook settings > Mail > Customize actions.
Select the check box for the add-in that you want to see when you’re composing a message.
as everyone dev. using ionic stack, also we are moving into the new wkwebview due to the Apple requirements.
We already provide a build to ios without any kind of warning ( about uiwebview old code ) but we're still encountering a problem performing SOME POST calls.
Settings
We have already set cors server side ( Apache ) like below:
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>com.hrd.auth.tomcat7.cors.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>app://myapp, http://localhost:9090</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>Content-Type,X-Requested-With,Accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,User-Agent,DEVICE_ID</param-value>
</init-param>
<init-param>
<param-name>cors.exposed.headers</param-name>
<param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
</init-param>
<init-param>
<param-name>cors.support.credentials</param-name>
<param-value>true</param-value>
</init-param>
<!-- <init-param>
<param-name>cors.preflight.maxage</param-name>
<param-value>10</param-value>
</init-param> -->
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Here below instead, the current APP configuration:
<description>An app from company S.r.l.</description>
<author email="sviluppo#mycompany.com" href="https://www.mycompany.com/"> Contact us </author>
<content src="index.html" />
<!-- Permissions -->
<access origin="*" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<allow-intent href="tel:*" />
<allow-intent href="sms:*" />
<allow-intent href="mailto:*" />
<allow-intent href="geo:*" />
<!-- Preferences -->
<preference name="webviewbounce" value="false" />
<preference name="KeyboardResize" value="false" />
<preference name="BackupWebStorage" value="none" />
<preference name="DisallowOverscroll" value="true" />
<preference name="AutoHideSplashScreen" value="true" />
<preference name="StatusBarStyle" value="lightcontent" />
<preference name="ShowSplashScreenSpinner" value="false" />
<preference name="FadeSplashScreenDuration" value="1500" />
<preference name="StatusBarOverlaysWebView" value="false" />
<preference name="KeyboardDisplayRequiresUserAction" value="false"/>
<!-- Hooks -->
<hook src="www/hooks/fwk-after-prepare-hooks.js" type="after_prepare" />
<hook src="www/hooks/fwk-after-plugin-add-hooks.js" type="after_plugin_add" />
<hook src="www/hooks/fwk-after-prepare-copy-build-extra-hooks.js" type="after_prepare" />
<hook src="www/hooks/fwk-after-compile-hooks.js" type="after_compile" />
<hook src="www/hooks/fwk-before-build-hooks.js" type="before_build" />
<!-- iOS -->
<platform name="ios">
<!-- CORS -->
<preference name="scheme" value="app" />
<preference name="iosScheme" value="app" />
<preference name="hostname" value="myapp" />
<!-- Resouces -->
<resource-file src="www/GoogleService-Info.plist" />
<icon height="20" src="www/res/icon/ios/Icon-20.png" width="20" />
...
</platform>
<!-- PLUGINS LIST -->
<!-- LIST -->
<!-- Don't modify this plugins list because it's generate-->
<plugin name="cordova-plugin-app-version" spec="0.1.9"/>
<plugin name="cordova-plugin-calendar" spec="4.6.0"/>
<plugin name="cordova-plugin-call-number" spec="1.0.1"/>
<plugin name="cordova-plugin-camera" spec="4.1.0">
<variable name="CAMERA_USAGE_DESCRIPTION" value="Allow_the_app_to_use_your_camera" />
<variable name="PHOTOLIBRARY_USAGE_DESCRIPTION" value="Allow_the_app_to_access_your_photos" />
</plugin>
<plugin name="cordova-plugin-compat" spec="1.2.0"/>
<plugin name="cordova-plugin-device" spec="1.1.7"/>
<plugin name="cordova-plugin-facebook4" spec="6.2.0">
<variable name="APP_ID" value="2553981324652029" />
<variable name="APP_NAME" value="com.mycompany.myapp" />
</plugin>
<plugin name="cordova-plugin-file" spec="6.0.2"/>
<plugin name="cordova-plugin-inappbrowser" spec="4.0.0"/>
<plugin name="cordova-plugin-ionic-keyboard" spec="2.2.0"/>
<plugin name="cordova-plugin-media-capture" spec="3.0.3">
<variable name="PHOTOLIBRARY_USAGE_DESCRIPTION" value="Allow_the_app_to_access_your_photos" />
</plugin>
<plugin name="cordova-plugin-network-information" spec="1.3.4"/>
<plugin name="cordova-plugin-splashscreen" spec="5.0.3"/>
<plugin name="cordova-plugin-statusbar" spec="2.4.2"/>
<plugin name="cordova-plugin-whitelist" spec="1.3.3"/>
<plugin name="cordova-plugin-sign-in-with-apple" spec="0.1.0"/>
<plugin name="cordova-plugin-wkwebview-inject-cookie" spec="1.0.6"/>
<engine name="ios" spec="6.1.0" />
Problem
The APP performs a successful POST call for login, with the following xhr details
"{\"method\":\"POST\",
\"post\":\"{
\\\"username\\\":\\\"username\\\",
\\\"password\\\":\\\"password\\\"
}\",
\"url\":\"http://192.168.1.129:8080/go/rest/security/appLogin/MY_APP_LOGIN\",
\"headers\":{\"Content-Type\":\"application/json\",
\"DEVICE_ID\":\"a91d602c140079f2e848f39e33a6ca88\",
\"Accept\":\"application/json,text/plain,*/*\"},
\"withCredentials\":true}"
BUT, in this call ( performed after having been authenticated ), is failing:
"{\"method\":\"POST\",
\"post\":\"{
\\\"test\\\":\\\"test\\\"
}\",
\"url\":\"http://192.168.1.129:8080/go/rest/security/userInfo\",
\"headers\":{
\"Accept\":\"application/json,text/plain,*/*\",
\"Content-Type\":\"application/json;charset=utf-8\"
},
\"withCredentials\":true}"
Environment Configuration
ionic-bundle that contains following stack
** ionic.js 1.3.2
** angularJS 1.5.3
cordova 9.0.0
cordova-ios 6.1.0
Have someone any idea for why that kind of call fails?
FAQ
Unlike the first one ( login call ) the second one doesn't reach server CorsFilter.java class, so call "not exit from the APP"
Our widget environment, unlike the mobile one, has been fixed for POST calls just putting inside call payload mocked data, in order to complain w3c browser specifications.
Very many thanks in advance
Simone
We discovered issues about calls not reaching server CorsFilters.java class ( so impossibile to get some debug instance ).
Reading our sever log we discovered this row
192.168.x.x - - [02/Sep/2020:17:40:09 +0200] "OPTIONS /go/rest/security/userInfo HTTP/1.1" 401 7361 4286
This is a know well problems about preflight POST request so - we just add in our web.xml conf. file the following property
<web-resource-collection>
<web-resource-name>REST</web-resource-name>
<description>REST services</description>
<url-pattern>/rest/*</url-pattern>
<http-method-omission>OPTIONS</http-method-omission> <<--- add this row
</web-resource-collection>
In this way, all OPTIONS request were'll be accepted and NOT rejected!
Hope this will help someone with a weeks headache ;)
Simon
I'm working with a Java application that integrates log4j. For a new development I would need that instead of generating a file I will generate two, one per country that is accessed from the application web. Both would have the same log records that are found throughout my application.
I configured the configuration using an .xml file:
<!-- Appenders -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="jeveris: %d{dd MMM yyyy HH:mm:ss,SSS} %-5p %c - %m%n" />
</layout>
</appender>
<appender name="One-Console" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="Console.log" />
<param name="Append" value="true" />
<param name="MaxFileSize" value="2MB" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="%d{dd MMM yyyy HH:mm:ss,SSS} %-5p %c - %m%n" />
</layout>
</appender>
<category name="com.example.one.web">
<level value="debug" />
<appender-ref ref="One-Console" />
</category>
<root>
<appender-ref ref="console" />
<level value="debug" />
</root>
</log4j:configuration>
Could someone guide me, tell me if it is possible or help me find the solution?
Thank you.
If you want 2+ log files that will print the same content, then you could fine 2 different files in your tag like so:
<configuration status="OFF">
<Properties>
<Property name="log-path">/your/file/path/</Property>
<Property name="log-country-name1">Country1</Property>
<Property name="log-country-name2">Country2</Property>
<!-- more if necessary -->
<Property name="log-pattern">%d{ISO8601} %-5p [%t|%c{1}] %m\n</Property>
<Property name="rollover-strategy-max">5</Property>
<Property name="rolling-size-based">10 MB</Property>
</Properties>
<appenders>
<!--uncomment following if want to print to console as well -->
<!-- <Console name="Console" target="SYSTEM_OUT">
<PatternLayout>
<pattern>${log-pattern}</pattern>
</PatternLayout>
</Console> -->
<RollingFile name="INFO" fileName="${log-path}/${log-country-name1}-logger.log" filePattern="${log-path}/${log-project-name}-debug-%d-%i.log.zip">
<PatternLayout>
<pattern>${log-pattern}</pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="${rolling-size-based}" />
</Policies>
<DefaultRolloverStrategy max="${rollover-strategy-max}" />
</RollingFile>
<RollingFile name="INFO" fileName="${log-path}/UpdaterLocal-logger.log" filePattern="${log-path}/${log-country-name2}-debug-%d-%i.log.zip">
<PatternLayout>
<pattern>${log-pattern}</pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="${rolling-size-based}" />
</Policies>
<DefaultRolloverStrategy max="${rollover-strategy-max}" />
</RollingFile>
</appenders>
<Loggers>
<logger name="io.switchfour" level="trace" additivity="false">
<AppenderRef ref="INFO" level="info" />
</logger>
</Loggers>
The above will create /your/file/path/Country1-logger.log and /your/file/path/Country2-logger.log and will write all entries that are INFO or higher to both files. Your log file should be identical.
<camel:errorHandler id="myErrorHandler" type="LoggingErrorHandler" level="ERROR" logName="myLoggingErrorHandler"/>
<camel:camelContext errorHandlerRef="myErrorHandler" trace="true">
<camel:route> <!-- errorHandlerRef="myErrorHandler" -->
<camel:from uri="file://src/resources?fileName=bookstore.xml" />
<camel:split>
<camel:xpath>//book/[#category='WEB']/author/text()</camel:xpath>
<camel:log message="Main route: '${body}'" />
</camel:split>
<!-- <camel:to uri="stream:out"/> -->
</camel:route>
</camel:camelContext>
Errors are getting logged but not with the name myLoggingErrorHandler as should be. That is how they were without using errorHandler. Please guide.
I pass a filename to ant script via
ant -Dfilepath=/foo/bar/foobar.suffix
I want to copy it to a destination and if it is a .js file generate a compiled version of it.
This works but currently the compile task runs on all files not just .js file.
How do I exclude non .js files in the "runjscompile" task?
In a fileset I would do this (but I don't get how to apply this on the task):
<fileset dir="${foo}" casesensitive="yes">
<exclude name="**/*.min.js" />
<include name="**/*.js" />
</fileset>
My build.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project name="test" basedir="." default="build">
<taskdef name="jscomp" classname="com.google.javascript.jscomp.ant.CompileTask" classpath="/home/bar/bin/compiler.jar" />
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="/usr/share/java/ant-contrib.jar" />
</classpath>
</taskdef>
<property name="serverRoot" value="/home/bar/server/public_html" />
<property name="foo" value="${serverRoot}/foo/" />
<property name="workspaceRoot"
value="/home/bar/Zend/workspaces/DefaultWorkspace/" />
<property name="foo_service" value="${workspaceRoot}/foo_service/" />
<property name="filepath" value="${filepath}" />
<target name="build" depends="transferFile, runjscompile" />
<target name="transferFile" description="overwrite old file">
<basename property="filename" file="${filepath}" />
<dirname property="path" file="${filepath}" />
<pathconvert property="path.fragment" pathsep="${line.separator}">
<propertyresource name="path" />
<mapper type="regexp" from="^/[^/]+/(.*)" to="\1" />
</pathconvert>
<echo message="copy ${workspaceRoot}${filepath} to ${foo}${path.fragment}${filename}" />
<copy file="${workspaceRoot}${filepath}" tofile="${foo}${path.fragment}${filename}"
overwrite="true" force="true" />
<property name="destFile" value="${foo}${path.fragment}${filename}" />
</target>
<target name="runjscompile">
<echo message="compile ${destFile}" />
<basename property="file" file="${destFile}" />
<basename property="prefix" file="${destFile}" suffix=".js" />
<dirname property="directory" file="${destFile}" />
<echo message="Compressing file ${file} to ${directory}/${prefix}.min.js" />
<jscomp compilationLevel="simple" debug="false" output="${directory}/${prefix}.min.js" forceRecompile="true">
<sources dir="${directory}">
<file name="${file}" />
</sources>
</jscomp>
</target>
</project>
Add another target which checks the file suffix with a <condition> and sets a property if it matches, then make the jscompile target conditional on that. Following your fileset example you probably want something like:
<target name="check.js">
<condition property="do.jscompile">
<!-- check for filepath that ends .js but not .min.js -->
<matches string="${filepath}" pattern=".*(?<!\.min)\.js$$" />
</condition>
</target>
<target name="build" depends="check.js, transferFile, runjscompile" />
<target name="runjscompile" if="do.jscompile">