From 4933376671520d85d069211bf72d1431a12db7b2 Mon Sep 17 00:00:00 2001 From: Andrew Nichols Date: Thu, 22 Mar 2018 12:11:25 -0700 Subject: [PATCH 1/3] Change outlook support to limit samples to the loaded endpoint --- src/client/app/effects/snippet.ts | 10 +++++++++- src/client/app/helpers/environment.ts | 5 +++++ src/client/public/functions.ts | 8 ++++++-- src/interfaces/playground.d.ts | 1 + 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/client/app/effects/snippet.ts b/src/client/app/effects/snippet.ts index d01341f5..49b6b484 100644 --- a/src/client/app/effects/snippet.ts +++ b/src/client/app/effects/snippet.ts @@ -18,6 +18,14 @@ import { isEmpty, isNil, find, assign, reduce, forIn, isEqual } from 'lodash'; import * as sha1 from 'crypto-js/sha1'; import { Utilities, HostType } from '@microsoft/office-js-helpers'; +function playlistUrl() { + let host = environment.current.host.toLowerCase(); + if (environment.current.endpoint !== null) { + host += `-${environment.current.endpoint}`; + } + return `${environment.current.config.samplesUrl}/playlists/${host}.yaml`; +} + @Injectable() export class SnippetEffects { constructor( @@ -173,7 +181,7 @@ export class SnippetEffects { .map((action: Snippet.LoadTemplatesAction) => action.payload) .mergeMap(source => { if (source === 'LOCAL') { - let snippetJsonUrl = `${environment.current.config.samplesUrl}/playlists/${environment.current.host.toLowerCase()}.yaml`; + let snippetJsonUrl = playlistUrl(); return this._request.get(snippetJsonUrl, ResponseTypes.YAML); } else { diff --git a/src/client/app/helpers/environment.ts b/src/client/app/helpers/environment.ts index 5ea45529..853889a8 100644 --- a/src/client/app/helpers/environment.ts +++ b/src/client/app/helpers/environment.ts @@ -64,6 +64,7 @@ class Environment { host: null, platform: null, + endpoint: null, runtimeSessionTimestamp: (new Date()).getTime().toString() }; @@ -164,6 +165,7 @@ class Environment { commands: any/* whether app-commands are available, relevant for Office Add-ins */, mode: string /* and older way of opening Script Lab to a particular host */, host: string /* same as "mode", also needed here so that overrides can also have this parameter */, + endpoint: string /* Defines which type of outlook experience is active */, wacUrl: string, tryIt: any, }; @@ -200,6 +202,9 @@ class Environment { } if (isValidHost(pageParams.mode)) { this.appendCurrent({ host: pageParams.mode.toUpperCase() }); + if (pageParams.endpoint) { + this.appendCurrent({endpoint: pageParams.endpoint.toLowerCase()}); + } return true; } } diff --git a/src/client/public/functions.ts b/src/client/public/functions.ts index 042c0780..cb9ac166 100644 --- a/src/client/public/functions.ts +++ b/src/client/public/functions.ts @@ -3,7 +3,11 @@ const { safeExternalUrls } = PLAYGROUND; Office.initialize = () => { const tutorialUrl = `${window.location.origin}/tutorial.html`; - const codeUrl = `${window.location.origin}/?mode=${Utilities.host}`; + function codeUrl() { + const item = Office.context.mailbox.item as Office.MessageRead; + const endpoint = `${item.itemType}${item.itemId !== undefined ? 'read' : 'compose'}`; + return `${window.location.origin}/?mode=${Utilities.host}&endpoint=${endpoint}`; + } const launchInDialog = (url: string, event?: any, options?: { width?: number, height?: number, displayInIframe?: boolean }) => { options = options || {}; @@ -34,7 +38,7 @@ Office.initialize = () => { launchInDialog(`${window.location.origin}/external-page.html?destination=${encodeURIComponent(url)}`, event, options); }; - (window as any).launchCode = (event) => launchInDialog(codeUrl, event, { width: 75, height: 75, displayInIframe: false }); + (window as any).launchCode = (event) => launchInDialog(codeUrl(), event, { width: 75, height: 75, displayInIframe: false }); (window as any).launchTutorial = (event) => launchInDialog(tutorialUrl, event, { width: 35, height: 45 }); diff --git a/src/interfaces/playground.d.ts b/src/interfaces/playground.d.ts index 5a624ec6..c848ee97 100644 --- a/src/interfaces/playground.d.ts +++ b/src/interfaces/playground.d.ts @@ -211,6 +211,7 @@ interface ICurrentPlaygroundInfo { config: Readonly; host: Readonly; platform: Readonly; + endpoint: Readonly; /** A timestamp specifically for the in-memory session (i.e., * even more short-term than sessionStorage, which has a lifetime-of-tab duration; From ece5a5b1117ea2ecc3b08744c2caae1ccd8038e7 Mon Sep 17 00:00:00 2001 From: Andrew Nichols Date: Mon, 2 Apr 2018 10:00:33 -0700 Subject: [PATCH 2/3] Pass off to laptop --- config/env.config.js | 78 +++++----- src/client/app/actions/snippet.ts | 2 +- src/client/app/components/snippet.info.ts | 140 +++++++++++++++++- src/client/app/containers/editor.mode.ts | 13 +- src/client/app/effects/snippet.ts | 5 +- src/client/app/helpers/utilities.ts | 7 + src/client/app/strings/chinese-simplified.ts | 5 + src/client/app/strings/english.ts | 5 + src/client/app/strings/german.ts | 5 + src/client/app/strings/spanish.ts | 5 + src/client/assets/styles/common.scss | 1 + .../assets/styles/components/checkbox.scss | 66 +++++++++ src/interfaces/client-strings.ts | 5 + src/interfaces/playground.d.ts | 1 + 14 files changed, 296 insertions(+), 42 deletions(-) create mode 100644 src/client/assets/styles/components/checkbox.scss diff --git a/config/env.config.js b/config/env.config.js index 6fec4cb4..b170b53b 100644 --- a/config/env.config.js +++ b/config/env.config.js @@ -14,25 +14,32 @@ const localStorageKeys = { experimentationFlags: 'playground_experimentation_flags', trustedSnippets: 'playground_trusted_snippets', customFunctionsLastHeartbeatTimestamp: 'playground_custom_functions_last_heartbeat_timestamp', - customFunctionsLastUpdatedCodeTimestamp: 'playground_custom_functions_last_updated_code_timestamp', - customFunctionsCurrentlyRunningTimestamp: 'playground_custom_functions_currently_running_timestamp', + customFunctionsLastUpdatedCodeTimestamp: + 'playground_custom_functions_last_updated_code_timestamp', + customFunctionsCurrentlyRunningTimestamp: + 'playground_custom_functions_currently_running_timestamp', logLastHeartbeatTimestamp: 'playground_log_last_heartbeat_timestamp', lastPerfNumbersTimestamp: 'playground_last_perf_numbers_timestamp', - language: 'playground_language' + language: 'playground_language', }; const sessionStorageKeys = { environmentCache: 'playground_cache', - intelliSenseCache: 'playground_intellisense' + intelliSenseCache: 'playground_intellisense', }; const build = (() => { return { name: startCase(name), version: version, - timestamp: moment().utc().valueOf(), - humanReadableTimestamp: moment().utc().format('YYYY-MM-DD HH:mm a') + ' UTC', - author: author + timestamp: moment() + .utc() + .valueOf(), + humanReadableTimestamp: + moment() + .utc() + .format('YYYY-MM-DD HH:mm a') + ' UTC', + author: author, }; })(); @@ -47,7 +54,7 @@ const config = { editorUrl: 'https://localhost:3000', tokenUrl: 'https://localhost:3200/auth', runnerUrl: 'https://localhost:3200', - samplesUrl: 'https://raw.githubusercontent.com/OfficeDev/office-js-snippets/deploy-beta', + samplesUrl: 'https://localhost/snippets', feedbackUrl: 'https://github.com/OfficeDev/script-lab/issues', thirdPartyAADAppClientId, }, @@ -70,7 +77,8 @@ const config = { tokenUrl: 'https://bornholm-runner-insiders.azurewebsites.net/auth', runnerUrl: 'https://bornholm-runner-insiders.azurewebsites.net', samplesUrl: 'https://raw.githubusercontent.com/OfficeDev/office-js-snippets/deploy-beta', - feedbackUrl: 'https://forms.office.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR_IQfl6RcdlChED7PZI6qXNURUo2UFBUR1YxMkwxWFBLUTRMUE9HRENOWi4u', + feedbackUrl: + 'https://forms.office.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR_IQfl6RcdlChED7PZI6qXNURUo2UFBUR1YxMkwxWFBLUTRMUE9HRENOWi4u', thirdPartyAADAppClientId, }, production: { @@ -83,7 +91,7 @@ const config = { samplesUrl: 'https://raw.githubusercontent.com/OfficeDev/office-js-snippets/deploy-prod', feedbackUrl: 'https://github.com/OfficeDev/script-lab/issues', thirdPartyAADAppClientId, - } + }, }; // NOTE: Any changes to this data structure should also be copied to `playground.d.ts` @@ -92,37 +100,41 @@ const safeExternalUrls = { ask: 'https://stackoverflow.com/questions/tagged/office-js', excel_api: 'https://dev.office.com/reference/add-ins/excel/excel-add-ins-reference-overview', word_api: 'https://dev.office.com/reference/add-ins/word/word-add-ins-reference-overview', - onenote_api: 'https://dev.office.com/reference/add-ins/onenote/onenote-add-ins-javascript-reference', + onenote_api: + 'https://dev.office.com/reference/add-ins/onenote/onenote-add-ins-javascript-reference', outlook_api: 'https://docs.microsoft.com/en-us/outlook/add-ins/reference', powepoint_api: 'https://dev.office.com/docs/add-ins/powerpoint/powerpoint-add-ins', project_api: 'https://dev.office.com/reference/add-ins/shared/projectdocument.projectdocument', - generic_api: 'https://dev.office.com/reference/add-ins/javascript-api-for-office' + generic_api: 'https://dev.office.com/reference/add-ins/javascript-api-for-office', }; const experimentationFlagsDefaults = { customFunctions: false, - customFunctionsShowDebugLog: false + customFunctionsShowDebugLog: false, }; class RedirectPlugin { apply(compiler) { - compiler.plugin('compilation', (compilation) => { - compilation.plugin('html-webpack-plugin-before-html-processing', (htmlPluginData, callback) => { - let headOpeningTag = ''; - let htmlHead = htmlPluginData.html.match(headOpeningTag); - - let { originEnvironmentUrl, redirectEnvironmentUrl } = localStorageKeys; - - const validRedirectLocations = []; - for (var envName in config) { - validRedirectLocations.push(config[envName].editorUrl); - } + compiler.plugin('compilation', compilation => { + compilation.plugin( + 'html-webpack-plugin-before-html-processing', + (htmlPluginData, callback) => { + let headOpeningTag = ''; + let htmlHead = htmlPluginData.html.match(headOpeningTag); + + let { originEnvironmentUrl, redirectEnvironmentUrl } = localStorageKeys; + + const validRedirectLocations = []; + for (var envName in config) { + validRedirectLocations.push(config[envName].editorUrl); + } - if (htmlHead && htmlHead.length > 0) { - htmlHead = htmlHead.index; - htmlPluginData.html = htmlPluginData.html.slice(0, htmlHead) + - headOpeningTag + - ` + if (htmlHead && htmlHead.length > 0) { + htmlHead = htmlHead.index; + htmlPluginData.html = + htmlPluginData.html.slice(0, htmlHead) + + headOpeningTag + + ` ` + - htmlPluginData.html.slice(htmlHead + headOpeningTag.length); + htmlPluginData.html.slice(htmlHead + headOpeningTag.length); + } + callback(null, htmlPluginData); } - callback(null, htmlPluginData); - }); + ); }); } } - exports.build = build; exports.config = config; exports.safeExternalUrls = safeExternalUrls; diff --git a/src/client/app/actions/snippet.ts b/src/client/app/actions/snippet.ts index f2f48964..cada29f4 100644 --- a/src/client/app/actions/snippet.ts +++ b/src/client/app/actions/snippet.ts @@ -72,7 +72,7 @@ export class ImportSuccessAction implements Action { export class UpdateInfoAction implements Action { readonly type = SnippetActionTypes.UPDATE_INFO; - constructor(public payload: { id: string, name?: string, description?: string, gist?: string, gistOwnerId?: string }) { } + constructor(public payload: { id: string, name?: string, description?: string, gist?: string, gistOwnerId?: string, endpoints?: string[] }) { } } export class RunAction implements Action { diff --git a/src/client/app/components/snippet.info.ts b/src/client/app/components/snippet.info.ts index 3ae26b1e..440fc4e1 100644 --- a/src/client/app/components/snippet.info.ts +++ b/src/client/app/components/snippet.info.ts @@ -1,5 +1,5 @@ import { Component, Input, ChangeDetectionStrategy, Output, EventEmitter } from '@angular/core'; -import { getGistUrl, environment, storage } from '../helpers'; +import { getGistUrl, environment, storage, outlookEndpoints } from '../helpers'; import { Strings } from '../strings'; import { isNil } from 'lodash'; @@ -19,19 +19,51 @@ import { isNil } from 'lodash'; +
+ +
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
- + {{strings.gistUrlLinkLabel}}
+
- -
@@ -45,6 +77,13 @@ export class SnippetInfo { strings = Strings(); + get buttonClasses() { + return { + 'ms-Button ms-Button--primary': true, + 'is-disabled': this.saveDisabled, + }; + } + get showGistUrl() { if (!this.snippet.gist) { return false; @@ -67,4 +106,93 @@ export class SnippetInfo { let host = this.snippet.host.toLowerCase(); return `${environment.current.config.editorUrl}/#/view/${host}/gist/${this.snippet.gist}`; } + + // Outlook Specific tooling + + get inOutlook() { + return this.snippet.host.toLowerCase() === 'outlook'; + } + + get MailRead() { + if (this.snippet.endpoints === undefined) { + return false; + } + return this.snippet.endpoints.indexOf(outlookEndpoints.MailRead) !== -1; + } + + @Input() + set MailRead(checked: boolean) { + this.snippet.endpoints = this.snippet.endpoints ? this.snippet.endpoints : []; + if (checked) { + if (this.snippet.endpoints.indexOf(outlookEndpoints.MailRead) === -1) { + this.snippet.endpoints.push(outlookEndpoints.MailRead); + } + } else { + this.snippet.endpoints = this.snippet.endpoints.filter(endpoint => endpoint !== outlookEndpoints.MailRead); + } + } + + get MailCompose() { + if (this.snippet.endpoints === undefined) { + return false; + } + return this.snippet.endpoints.indexOf(outlookEndpoints.MailCompose) !== -1; + } + + @Input() + set MailCompose(checked: boolean) { + this.snippet.endpoints = this.snippet.endpoints ? this.snippet.endpoints : []; + if (checked) { + if (this.snippet.endpoints.indexOf(outlookEndpoints.MailCompose) === -1) { + this.snippet.endpoints.push(outlookEndpoints.MailCompose); + } + } else { + this.snippet.endpoints = this.snippet.endpoints.filter(endpoint => endpoint !== outlookEndpoints.MailCompose); + } + } + + get AppointmentOrganizer() { + if (this.snippet.endpoints === undefined) { + return false; + } + return this.snippet.endpoints.indexOf(outlookEndpoints.AppointmentOrganizer) !== -1; + } + + @Input() + set AppointmentOrganizer(checked: boolean) { + this.snippet.endpoints = this.snippet.endpoints ? this.snippet.endpoints : []; + if (checked) { + if (this.snippet.endpoints.indexOf(outlookEndpoints.AppointmentOrganizer) === -1) { + this.snippet.endpoints.push(outlookEndpoints.AppointmentOrganizer); + } + } else { + this.snippet.endpoints = this.snippet.endpoints.filter(endpoint => endpoint !== outlookEndpoints.AppointmentOrganizer); + } + } + + get AppointmentAttendee() { + if (this.snippet.endpoints === undefined) { + return false; + } + return this.snippet.endpoints.indexOf(outlookEndpoints.AppointmentAttendee) !== -1; + } + + @Input() + set AppointmentAttendee(checked: boolean) { + this.snippet.endpoints = this.snippet.endpoints ? this.snippet.endpoints : []; + if (checked) { + if (this.snippet.endpoints.indexOf(outlookEndpoints.AppointmentAttendee) === -1) { + this.snippet.endpoints.push(outlookEndpoints.AppointmentAttendee); + } + } else { + this.snippet.endpoints = this.snippet.endpoints.filter(endpoint => endpoint !== outlookEndpoints.AppointmentAttendee); + } + } + + @Input() + get saveDisabled() { + // In outlook, at least one endpoint must be enabled, so we disable the save button unless at least one is checked. + return this.inOutlook && !(this.MailRead || this.MailCompose || this.AppointmentAttendee || this.AppointmentOrganizer); + } + } diff --git a/src/client/app/containers/editor.mode.ts b/src/client/app/containers/editor.mode.ts index 0867c3a0..eefa43c3 100644 --- a/src/client/app/containers/editor.mode.ts +++ b/src/client/app/containers/editor.mode.ts @@ -44,7 +44,7 @@ import { Subscription } from 'rxjs/Subscription'; - + @@ -56,6 +56,7 @@ export class EditorMode { snippet: ISnippet; isEmpty: boolean; isDisabled: boolean; + showInfo: boolean; strings = Strings(); @@ -63,6 +64,7 @@ export class EditorMode { private sharingSub: Subscription; private errorsSub: Subscription; + constructor( private _store: Store, private _effects: UIEffects, @@ -72,6 +74,11 @@ export class EditorMode { this.snippetSub = this._store.select(fromRoot.getCurrent).subscribe(snippet => { this.isEmpty = snippet == null; this.snippet = snippet; + const inOutlook = this.snippet !== null && this.snippet.host.toLowerCase() === 'outlook'; + const outlookNeedsEndpoints = inOutlook && (this.snippet.endpoints === undefined || this.snippet.endpoints.length === 0); + if (outlookNeedsEndpoints) { + this.showInfo = true; + } }); this.sharingSub = this._store.select(fromRoot.getSharing).subscribe(sharing => { @@ -83,6 +90,10 @@ export class EditorMode { this.parseEditorRoutingParams(); } + get shouldShowInfo() { + return this.showInfo; + } + get isAddinCommands() { return environment.current.isAddinCommands; } diff --git a/src/client/app/effects/snippet.ts b/src/client/app/effects/snippet.ts index d01341f5..4d3551ed 100644 --- a/src/client/app/effects/snippet.ts +++ b/src/client/app/effects/snippet.ts @@ -192,7 +192,7 @@ export class SnippetEffects { updateInfo$: Observable = this.actions$ .ofType(Snippet.SnippetActionTypes.UPDATE_INFO) .map(({ payload }) => { - let { id, name, description, gist, gistOwnerId } = payload; + let { id, name, description, gist, gistOwnerId, endpoints } = payload; let snippet: ISnippet = storage.lastOpened; if (storage.snippets.contains(id)) { snippet = storage.snippets.get(id); @@ -210,6 +210,9 @@ export class SnippetEffects { if (!isNil(gistOwnerId)) { snippet.gistOwnerId = gistOwnerId; } + if (!isNil(endpoints)) { + snippet.endpoints = endpoints; + } /* updates snippet */ storage.snippets.insert(id, snippet); diff --git a/src/client/app/helpers/utilities.ts b/src/client/app/helpers/utilities.ts index 3e0e0a7f..66ebe83f 100644 --- a/src/client/app/helpers/utilities.ts +++ b/src/client/app/helpers/utilities.ts @@ -15,6 +15,13 @@ const officeHostsToAppNames = { 'WORD': 'Word' }; +export const outlookEndpoints = { + MailRead: 'messageread', + MailCompose: 'messagecompose', + AppointmentOrganizer: 'appointmentcompose', + AppointmentAttendee: 'appointmentread', +}; + export function isValidHost(host: string) { host = host.toUpperCase(); return isOfficeHost(host) || (host === 'WEB'); diff --git a/src/client/app/strings/chinese-simplified.ts b/src/client/app/strings/chinese-simplified.ts index 16c34160..772dfcdb 100644 --- a/src/client/app/strings/chinese-simplified.ts +++ b/src/client/app/strings/chinese-simplified.ts @@ -192,6 +192,11 @@ export function getChineseSimplifiedStrings(): ClientStringsPerLanguage { // Outlook-only strings noRunInOutlook: getEnglishSubstitutesForNotYetTranslated().noRunInOutlook, + extensionPointsLabel: getEnglishSubstitutesForNotYetTranslated().extensionPointsLabel, + mailRead: getEnglishSubstitutesForNotYetTranslated().mailRead, + mailCompose: getEnglishSubstitutesForNotYetTranslated().mailCompose, + appointmentOrganizer: getEnglishSubstitutesForNotYetTranslated().appointmentOrganizer, + appointmentAttendee: getEnglishSubstitutesForNotYetTranslated().appointmentAttendee, // import.ts strings diff --git a/src/client/app/strings/english.ts b/src/client/app/strings/english.ts index 3e2ce697..9855b2d7 100644 --- a/src/client/app/strings/english.ts +++ b/src/client/app/strings/english.ts @@ -195,6 +195,11 @@ export function getEnglishStrings(): ClientStringsPerLanguage { // Outlook-only strings noRunInOutlook: /** NEEDS STRING REVIEW **/ `You cannot run your snippet from the code window in Outlook. Please open the "Run" pane in Outlook to run your snippet.`, + extensionPointsLabel: /** NEEDS STRING REVIEW **/ `Supported Extension Points`, + mailRead: /** NEEDS STRING REVIEW **/ `Mail Read`, + mailCompose: /** NEEDS STRING REVIEW **/ `Mail Compose`, + appointmentOrganizer: /** NEEDS STRING REVIEW **/ `Appointment Organizer`, + appointmentAttendee: /** NEEDS STRING REVIEW **/ `Appointment Attendee`, // import.ts strings diff --git a/src/client/app/strings/german.ts b/src/client/app/strings/german.ts index f986f93f..9028dfd3 100644 --- a/src/client/app/strings/german.ts +++ b/src/client/app/strings/german.ts @@ -194,6 +194,11 @@ export function getGermanStrings(): ClientStringsPerLanguage { // Outlook-only strings noRunInOutlook: 'Das Code-Schnipsel kann in Outlook nicht aus dem Code-Fenster heraus ausgeführt werden. Bitte öffnen Sie den Aufgabenbereich zur Code-Ausführung und rufen Sie das Schnipsel von dort aus auf.', + extensionPointsLabel: getEnglishSubstitutesForNotYetTranslated().extensionPointsLabel, + mailRead: getEnglishSubstitutesForNotYetTranslated().mailRead, + mailCompose: getEnglishSubstitutesForNotYetTranslated().mailCompose, + appointmentOrganizer: getEnglishSubstitutesForNotYetTranslated().appointmentOrganizer, + appointmentAttendee: getEnglishSubstitutesForNotYetTranslated().appointmentAttendee, // import.ts strings diff --git a/src/client/app/strings/spanish.ts b/src/client/app/strings/spanish.ts index 24b40d3f..4519b384 100644 --- a/src/client/app/strings/spanish.ts +++ b/src/client/app/strings/spanish.ts @@ -189,6 +189,11 @@ export function getSpanishStrings(): ClientStringsPerLanguage { // Outlook-only strings noRunInOutlook: getEnglishSubstitutesForNotYetTranslated().noRunInOutlook, + extensionPointsLabel: getEnglishSubstitutesForNotYetTranslated().extensionPointsLabel, + mailRead: getEnglishSubstitutesForNotYetTranslated().mailRead, + mailCompose: getEnglishSubstitutesForNotYetTranslated().mailCompose, + appointmentOrganizer: getEnglishSubstitutesForNotYetTranslated().appointmentOrganizer, + appointmentAttendee: getEnglishSubstitutesForNotYetTranslated().appointmentAttendee, // import.ts strings diff --git a/src/client/assets/styles/common.scss b/src/client/assets/styles/common.scss index 71bce6b8..56c19ab6 100644 --- a/src/client/assets/styles/common.scss +++ b/src/client/assets/styles/common.scss @@ -2,6 +2,7 @@ @import 'mixins'; @import 'components/spinner'; @import 'components/command'; +@import 'components/checkbox'; * { margin: 0; diff --git a/src/client/assets/styles/components/checkbox.scss b/src/client/assets/styles/components/checkbox.scss new file mode 100644 index 00000000..0a79b97e --- /dev/null +++ b/src/client/assets/styles/components/checkbox.scss @@ -0,0 +1,66 @@ + /* Customize the label (the container) */ + .container { + display: block; + position: relative; + padding-left: 35px; + margin-bottom: 12px; + cursor: pointer; + font-size: 22px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + height: 25px; + } + + /* Hide the browser's default checkbox */ + .container input { + position: absolute; + opacity: 0; + cursor: pointer; + } + + /* Create a custom checkbox */ + .checkmark { + position: absolute; + top: 5px; + left: 0; + height: 20px; + width: 20px; + background-color: #eee; + } + + /* On mouse-over, add a grey background color */ + .container:hover input ~ .checkmark { + background-color: #ccc; + } + + /* When the checkbox is checked, add a blue background */ + .container input:checked ~ .checkmark { + background-color: #2196F3; + } + + /* Create the checkmark/indicator (hidden when not checked) */ + .checkmark:after { + content: ""; + position: absolute; + display: none; + } + + /* Show the checkmark when checked */ + .container input:checked ~ .checkmark:after { + display: block; + } + + /* Style the checkmark/indicator */ + .container .checkmark:after { + left: 9px; + top: 5px; + width: 5px; + height: 10px; + border: solid white; + border-width: 0 3px 3px 0; + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); + } \ No newline at end of file diff --git a/src/interfaces/client-strings.ts b/src/interfaces/client-strings.ts index d7761b1e..838c4b5f 100644 --- a/src/interfaces/client-strings.ts +++ b/src/interfaces/client-strings.ts @@ -171,6 +171,11 @@ interface ClientStringsPerLanguage { // Outlook-only strings noRunInOutlook: string; + extensionPointsLabel: string; + mailRead: string; + mailCompose: string; + appointmentOrganizer: string; + appointmentAttendee: string; // import.ts strings diff --git a/src/interfaces/playground.d.ts b/src/interfaces/playground.d.ts index 5a624ec6..1dd1b4fa 100644 --- a/src/interfaces/playground.d.ts +++ b/src/interfaces/playground.d.ts @@ -16,6 +16,7 @@ interface ITemplate { /** author: export-only */ author?: string; host: string; + endpoints?: string[]; /** api_set: export-only (+ check at first level of import) */ api_set?: { [index: string]: number From b90ee8e2ace88b3503720b023cdc7ff50c60de71 Mon Sep 17 00:00:00 2001 From: Andrew Nichols Date: Mon, 2 Apr 2018 10:09:42 -0700 Subject: [PATCH 3/3] Remove env config change --- config/env.config.js | 78 +++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 45 deletions(-) diff --git a/config/env.config.js b/config/env.config.js index b170b53b..6fec4cb4 100644 --- a/config/env.config.js +++ b/config/env.config.js @@ -14,32 +14,25 @@ const localStorageKeys = { experimentationFlags: 'playground_experimentation_flags', trustedSnippets: 'playground_trusted_snippets', customFunctionsLastHeartbeatTimestamp: 'playground_custom_functions_last_heartbeat_timestamp', - customFunctionsLastUpdatedCodeTimestamp: - 'playground_custom_functions_last_updated_code_timestamp', - customFunctionsCurrentlyRunningTimestamp: - 'playground_custom_functions_currently_running_timestamp', + customFunctionsLastUpdatedCodeTimestamp: 'playground_custom_functions_last_updated_code_timestamp', + customFunctionsCurrentlyRunningTimestamp: 'playground_custom_functions_currently_running_timestamp', logLastHeartbeatTimestamp: 'playground_log_last_heartbeat_timestamp', lastPerfNumbersTimestamp: 'playground_last_perf_numbers_timestamp', - language: 'playground_language', + language: 'playground_language' }; const sessionStorageKeys = { environmentCache: 'playground_cache', - intelliSenseCache: 'playground_intellisense', + intelliSenseCache: 'playground_intellisense' }; const build = (() => { return { name: startCase(name), version: version, - timestamp: moment() - .utc() - .valueOf(), - humanReadableTimestamp: - moment() - .utc() - .format('YYYY-MM-DD HH:mm a') + ' UTC', - author: author, + timestamp: moment().utc().valueOf(), + humanReadableTimestamp: moment().utc().format('YYYY-MM-DD HH:mm a') + ' UTC', + author: author }; })(); @@ -54,7 +47,7 @@ const config = { editorUrl: 'https://localhost:3000', tokenUrl: 'https://localhost:3200/auth', runnerUrl: 'https://localhost:3200', - samplesUrl: 'https://localhost/snippets', + samplesUrl: 'https://raw.githubusercontent.com/OfficeDev/office-js-snippets/deploy-beta', feedbackUrl: 'https://github.com/OfficeDev/script-lab/issues', thirdPartyAADAppClientId, }, @@ -77,8 +70,7 @@ const config = { tokenUrl: 'https://bornholm-runner-insiders.azurewebsites.net/auth', runnerUrl: 'https://bornholm-runner-insiders.azurewebsites.net', samplesUrl: 'https://raw.githubusercontent.com/OfficeDev/office-js-snippets/deploy-beta', - feedbackUrl: - 'https://forms.office.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR_IQfl6RcdlChED7PZI6qXNURUo2UFBUR1YxMkwxWFBLUTRMUE9HRENOWi4u', + feedbackUrl: 'https://forms.office.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR_IQfl6RcdlChED7PZI6qXNURUo2UFBUR1YxMkwxWFBLUTRMUE9HRENOWi4u', thirdPartyAADAppClientId, }, production: { @@ -91,7 +83,7 @@ const config = { samplesUrl: 'https://raw.githubusercontent.com/OfficeDev/office-js-snippets/deploy-prod', feedbackUrl: 'https://github.com/OfficeDev/script-lab/issues', thirdPartyAADAppClientId, - }, + } }; // NOTE: Any changes to this data structure should also be copied to `playground.d.ts` @@ -100,41 +92,37 @@ const safeExternalUrls = { ask: 'https://stackoverflow.com/questions/tagged/office-js', excel_api: 'https://dev.office.com/reference/add-ins/excel/excel-add-ins-reference-overview', word_api: 'https://dev.office.com/reference/add-ins/word/word-add-ins-reference-overview', - onenote_api: - 'https://dev.office.com/reference/add-ins/onenote/onenote-add-ins-javascript-reference', + onenote_api: 'https://dev.office.com/reference/add-ins/onenote/onenote-add-ins-javascript-reference', outlook_api: 'https://docs.microsoft.com/en-us/outlook/add-ins/reference', powepoint_api: 'https://dev.office.com/docs/add-ins/powerpoint/powerpoint-add-ins', project_api: 'https://dev.office.com/reference/add-ins/shared/projectdocument.projectdocument', - generic_api: 'https://dev.office.com/reference/add-ins/javascript-api-for-office', + generic_api: 'https://dev.office.com/reference/add-ins/javascript-api-for-office' }; const experimentationFlagsDefaults = { customFunctions: false, - customFunctionsShowDebugLog: false, + customFunctionsShowDebugLog: false }; class RedirectPlugin { apply(compiler) { - compiler.plugin('compilation', compilation => { - compilation.plugin( - 'html-webpack-plugin-before-html-processing', - (htmlPluginData, callback) => { - let headOpeningTag = ''; - let htmlHead = htmlPluginData.html.match(headOpeningTag); - - let { originEnvironmentUrl, redirectEnvironmentUrl } = localStorageKeys; - - const validRedirectLocations = []; - for (var envName in config) { - validRedirectLocations.push(config[envName].editorUrl); - } + compiler.plugin('compilation', (compilation) => { + compilation.plugin('html-webpack-plugin-before-html-processing', (htmlPluginData, callback) => { + let headOpeningTag = ''; + let htmlHead = htmlPluginData.html.match(headOpeningTag); + + let { originEnvironmentUrl, redirectEnvironmentUrl } = localStorageKeys; - if (htmlHead && htmlHead.length > 0) { - htmlHead = htmlHead.index; - htmlPluginData.html = - htmlPluginData.html.slice(0, htmlHead) + - headOpeningTag + - ` + const validRedirectLocations = []; + for (var envName in config) { + validRedirectLocations.push(config[envName].editorUrl); + } + + if (htmlHead && htmlHead.length > 0) { + htmlHead = htmlHead.index; + htmlPluginData.html = htmlPluginData.html.slice(0, htmlHead) + + headOpeningTag + + ` ` + - htmlPluginData.html.slice(htmlHead + headOpeningTag.length); - } - callback(null, htmlPluginData); + htmlPluginData.html.slice(htmlHead + headOpeningTag.length); } - ); + callback(null, htmlPluginData); + }); }); } } + exports.build = build; exports.config = config; exports.safeExternalUrls = safeExternalUrls;