From b0ae8c20ab15849c88071104ac7a89df8325c2df Mon Sep 17 00:00:00 2001 From: wandyezj Date: Sun, 7 Apr 2024 18:17:50 -0700 Subject: [PATCH] Tutorial (#18) - Add Tutorial - Move some docs around. - Add some ideas. - Add test for local in production manifests. --- .vscode/cspell.json | 3 +- config/webpack.config.js | 12 ++++- docs/about.md | 18 ++------ docs/architecture.md | 2 +- docs/ideas.md | 59 ++++++++++++++++++++++++ docs/principles.md | 14 ++++++ docs/todo.md | 49 ++++++++++++++++---- docs/tutorial.md | 83 ++++++++++++++++++++++++++++++++++ docs/vocabulary.md | 13 ++++++ tests/distConstants.ts | 8 ++++ tests/getLocalDistIndexData.ts | 4 +- tests/manifest.spec.ts | 16 +++++++ 12 files changed, 253 insertions(+), 28 deletions(-) create mode 100644 docs/ideas.md create mode 100644 docs/principles.md create mode 100644 docs/tutorial.md create mode 100644 docs/vocabulary.md create mode 100644 tests/distConstants.ts create mode 100644 tests/manifest.spec.ts diff --git a/.vscode/cspell.json b/.vscode/cspell.json index ea8b5b9..4fb4610 100644 --- a/.vscode/cspell.json +++ b/.vscode/cspell.json @@ -16,7 +16,8 @@ "minifier", "prettierrc", "Sideload", - "Sideloading" + "Sideloading", + "taskpane" ], // flagWords - list of words to be always considered incorrect // This is useful for offensive words and common spelling errors. diff --git a/config/webpack.config.js b/config/webpack.config.js index 0622c84..db2d6af 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -4,6 +4,16 @@ const CopyWebpackPlugin = require("copy-webpack-plugin"); const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin"); //const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); const { Marked } = require("marked"); + + +// Options + +/** + * In Dev mode, when starting, open the edit, run, and blocks in the browser + */ +const optionDevOpenBrowserTabs = true; + + const marked = new Marked(); marked.use({ gfm: true, @@ -137,7 +147,7 @@ module.exports = async (env, options) => { if (options.mode === "development") { config.devServer = { ...config.devServer, - open: [], //["/edit.html", "/run.html", "/blocks.html"], + open: optionDevOpenBrowserTabs ? ["/edit.html", "/run.html", "/blocks.html"] : [], port: 3000, server: { type: "https", diff --git a/docs/about.md b/docs/about.md index c8ebc86..1cd9008 100644 --- a/docs/about.md +++ b/docs/about.md @@ -1,22 +1,14 @@ # About +- [Tutorial](./tutorial.md) + +## Internal Docs + +- [Principles](./setup.md) - [Setup](./setup.md) - [Tech Stack](./tech-stack.md) - [Architecture](./architecture.md) - [Dependencies](./dependencies.md) - [GitHub Pages Setup](./pages-environment.md) -## Principles -- [Open Source](https://en.wikipedia.org/wiki/Open_source) -- [Public Domain](https://en.wikipedia.org/wiki/Public_domain) -- [Free Software](https://www.gnu.org/philosophy/free-sw.en.html) -- Cross Platform - - Runs in any up to date chromium browser. - - Downloadable as a single file that can be run offline. -- Secure - - Minimal dependencies to minimize attack surface and chance of supply chain attacks. -- Private - - No telemetry is sent from page code. - - No external data is loaded. - - No back end servers. diff --git a/docs/architecture.md b/docs/architecture.md index 5d06624..ad0088d 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -36,7 +36,7 @@ Each snip has: - ts - the code that is run -### Libraries +### References http links diff --git a/docs/ideas.md b/docs/ideas.md new file mode 100644 index 0000000..33bb196 --- /dev/null +++ b/docs/ideas.md @@ -0,0 +1,59 @@ +# Ideas + +A collection of ideas that might improve the Build Add-In experience. + + +## Random + +- Github Issues Tab + - Clear set of labels for issues with description of what they mean and how they should be used. + - Interact with customers often. +- Clear issue labels + - Minimize labels to less than twenty too hard to keep track of otherwise. + - key component names (run, edit, compile, monaco, blocks) + - question - someone has a question, ideally it should be answered in documentation. + - suggestion- someone has a suggestion for something + - wont-fix + - P0, P1, P2 + - by-design + - duplicate + - stale / old - not looking at this because too old and not relevant +- Be clear on intended use and what scenarios are supported + - Refer to these scenarios when people ask for things outside of those scenarios. +- Clear local development documentation +- Have a set of pre canned responses +- Philosophy of do it well or don't do it. +- What is the difference between closing issues as not planned and closing them? When should you use either option? +- Is it possible to have the monaco shortcuts mirror vs code? +- Have an updates tab that displays a changelog of what has recently changed. +- Explanation of libraries tab + - Explain that it only loads js, css, and types files as is. + - We do not do any complex logic like trying to load a npm package. If you want to do that build a full website with a build system. +- Allow office.js and Office.d.ts to load from the localhost when there isn't internet. + +- copy manifests to standard C:\share for testing on native, and prefix with the add-in name. + +- Can I allow custom buttons to active specific snips? + +- arbitrary snip import from URLs - show message if not successful +- export as publish zip with: + - html file with {html, css, js} embedded or simply as separate files? + - manifest.xml + - default icon + - snip.json + - readme with instructions of how to publish on GitHub, clone simple repository put all files in, create site etc.., replace url in manifest etc, upload to store + + +- Make sure to validate any imported data. - Should probably be extended to anything in indexedDB as well. Assume any data where ever it's from is evil. + +- Enable embedding snips in documents, possibly by adding custom xml tags and searching for them. +- double check any library urls +- provide firm guidance on what each piece does with an info box + +- hotkeys - allow creation of a limited number of custom hotkeys. Only allow JS to execute. Requires shared runtime? + + +Tests + +- What happens with snips with really long names? +- Capture tab key in monaco editor instead of moving around to buttons \ No newline at end of file diff --git a/docs/principles.md b/docs/principles.md new file mode 100644 index 0000000..461738d --- /dev/null +++ b/docs/principles.md @@ -0,0 +1,14 @@ +# Principles + +- [Open Source](https://en.wikipedia.org/wiki/Open_source) +- [Public Domain](https://en.wikipedia.org/wiki/Public_domain) +- [Free Software](https://www.gnu.org/philosophy/free-sw.en.html) +- Cross Platform + - Runs in any up to date chromium browser. + - Downloadable as a single file that can be run offline. +- Secure + - Minimal dependencies to minimize attack surface and chance of supply chain attacks. +- Private + - No telemetry is sent from page code. + - No external data is loaded. + - No back end servers. \ No newline at end of file diff --git a/docs/todo.md b/docs/todo.md index 09d7e1a..09a8085 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -15,16 +15,13 @@ ## Phase - Multiple Files -- [ ] multiple local snip +- [X] multiple local snip - [X] storage scheme - [X] storage system - [indexedDB basic pattern](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB#basic_pattern) - [X] multi snip display and selection - [X] Style the snips to display (display name, in order of last modified.) - [Card](https://react.fluentui.dev/?path=/docs/components-card-card--default) -- [ ] Second page for samples [Multi-Level Drawer](https://react.fluentui.dev/?path=/docs/components-drawer--default#multiple-levels) -- [ ] More graceful delete and new. After delete open library to selecting new snip to open. -- [ ] remove ... from card or have dropdown to delete / pin ## Phase - Publish @@ -34,7 +31,7 @@ - [X] Manifest - Cross Application - [X] Manifest - Ribbon Tab - (Extension) - [ ] Store Publish - - [ ] Catchy Name (Build?) + - [X] Catchy Name = `Build` Add-In - [AppSource publishing](https://learn.microsoft.com/en-us/partner-center/marketplace/submit-to-appsource-via-partner-center) - [Offer Overview](https://partner.microsoft.com/en-us/dashboard/marketplace-offers/overview) - [X] Description Short @@ -54,14 +51,21 @@ ## Phase - Important -- [ ] Warn before delete +- [ ] Confirmation dialog before delete - [ ] display compile errors - typescript pre emit diagnostics require program construction -## Phase - Fix +## Phase - Multiple Files - Advanced -- [ ] Copy to clipboard functionality is broken. It looks like the permissions were recently removed from the iframe policy? `` - - [X] Workaround - use the command API +In the Local Snips drawer. + +- [ ] Select Multiple + - [ ] Allow download of select snips to a snips.json file. + - [ ] Allow import of select snips from a snip.json file. + - [ ] Allow delete of select Local Snips +- [ ] More graceful delete and new. + - After delete open Local Snips drawer to selecting new snip to open. +- [ ] Allow pin of snips to the top of the Local Snips drawer. ## Phase - UI Polish @@ -69,12 +73,20 @@ - [X] Resizable Editor that adjusts to screen size - [ ] Find a better way to do this. The current way works but is not ideal. using 100vh on the container CSS and 90vh on the editor CSS. +## Phase - Samples + +- [ ] Second page for samples [Multi-Level Drawer](https://react.fluentui.dev/?path=/docs/components-drawer--default#multiple-levels) ## Phase - test - [ ] always an open snip - [ ] always something to run +## Phase - Long Term Fix + +- [ ] Copy to clipboard functionality is broken. It looks like the permissions were recently removed from the iframe policy? `` + - [X] Workaround - use the command API + ## Phase - Nice - [ ] global log function to ease debugging and silencing @@ -99,8 +111,24 @@ - [X] dependencies.md - why each dependency - how is each dependency used +- [X] vocabulary.md + - names and definition for every item - [ ] deployment infrastructure + +## Phase - Accessibility + +## Phase - Localize + +i18n + +- [ ] localize dates and times [MDN Intl API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) +- [ ] Open Source Machine Translation Tool? +- [ ] Copy Translations + - https://github.com/microsoft/vscode-loc + - https://github.com/microsoft/vscode-l10n + + ## Phase - Blocks - [ ] Dynamic Blocks @@ -108,4 +136,5 @@ - [ ] New block validation - [ ] Remove block from end - [ ] Block Library -- [ ] Include block steps in a snip \ No newline at end of file +- [ ] Include block steps in a snip + diff --git a/docs/tutorial.md b/docs/tutorial.md new file mode 100644 index 0000000..e6ae3cb --- /dev/null +++ b/docs/tutorial.md @@ -0,0 +1,83 @@ +# Tutorial + +The Build Add-In is a tool to allow you to create snips to extend Word, Excel, and PowerPoint using the Office.js API. + +Each snip consists of TypeScript, HTML, and CSS. + +The Build Add-In provides a way to create, edit, run and share these snips. + +## Quick Tutorial + +Create, edit, and run your first snip. + +1. Open the _Edit Taskpane_ + 1. Click the `Build` tab on the ribbon. + 1. Click the `Edit` button. + 1. Wait for the _Edit taskpane_ to open on the right of the document. +1. Create a new default snip, In the _Edit Taskpane_ + 1. Click the `Open Snip` Icon to open the `Local Snips` drawer and view all local snips. (There shouldn't be any yet) + 1. In the `Local Snip` drawer, click `New Snip`. + 1. You should see a snip named `Default Snip` appear. + 1. Click the new Default Snip +1. Edit the Snip + 1. Rename the snip + 1. Edit the snips HTML + 1. Click the `HTML` tab in the _Edit taskpane_ + 1. In the HTML editor add a new Paragraph `

Hello World!

` +1. Run the snip + 1. Click the `Build` tab on the ribbon. + 1. Click the `Run` button. + 1. Wait for the _Run taskpane_ to open on the right of the document. + 1. Wait for snip to load. + +## Features + +- [Create](#create) +- [Run](#run) +- [Edit](#edit) +- [Share](#share) +- [Backup](#backup) + +### Create + +To create a snip: + +1. Click the `Build` tab on the ribbon. +1. Click the `Edit` button. +1. Wait for the _Edit taskpane_ to open on the right of the document. +1. Click the Plus Icon to create a new default snip + +### Run + +To run the currently open snip: + +1. Click the `Build` tab on the ribbon. +1. Click the `Run` button. +1. Wait for the _Run taskpane_ to open on the right of the document. + +The current snip open in the _Edit taskpane_ will run. + +The `Run taskpane` will load the CSS, HTML, and JavaScript from the snip into the window. + +### Edit + +In the `Edit taskpane`: + +- `Open Snip` - Open a snip to edit. +- Select the snip file to edit by clicking `TS`,`HTML`, or `CSS`. +- Use the editor to modify the file, your changes will automatically save as you edit. + +### Share + +Snips are saved in local storage. You can backup and share your snips in the `Edit taskpane`. + +- Click `Copy to clipboard` to get a copy of currently open snip for sharing. +- Click `Import` to load a copied snip, it will open a dialog you can paste a snips text into. + +#### Backup + +In `Local Snips drawer` in the `Edit taskpane`. + +- Click `Download All Snips` to download a snips.json file with a copy of all local snips. +- Click `Upload Snips` to upload a new copy of all snips in a snips.json file. + diff --git a/docs/vocabulary.md b/docs/vocabulary.md new file mode 100644 index 0000000..eafe0ac --- /dev/null +++ b/docs/vocabulary.md @@ -0,0 +1,13 @@ +# Vocabulary + +- Snip + - A complete extension, consisting of Ts, HTML, CSS, and Libraries. +- Edit taskpane + - The pane opened by the ribbons Edit button. +- Run taskpane + - The pane opened by the ribbons Run button. +- Local Snips + - Snips that are stored in client side storage IndexedDB in the local browser. +- Local Snips drawer + - Drawer in the Edit Taskpane that allows management of local snips. + diff --git a/tests/distConstants.ts b/tests/distConstants.ts new file mode 100644 index 0000000..04cacdc --- /dev/null +++ b/tests/distConstants.ts @@ -0,0 +1,8 @@ +import path from "path"; +import { getRootDirectory } from "./getRootDirectory"; + +export const localDistPath = path.resolve(getRootDirectory(), "dist"); + +export const localDistManifestsPath = path.resolve(localDistPath, "manifests"); +export const localDistManifestProductionPath = path.resolve(localDistManifestsPath, "production.xml"); +export const localDistManifestProductionOutlookPath = path.resolve(localDistManifestsPath, "production.outlook.xml"); diff --git a/tests/getLocalDistIndexData.ts b/tests/getLocalDistIndexData.ts index d0b9390..86051e7 100644 --- a/tests/getLocalDistIndexData.ts +++ b/tests/getLocalDistIndexData.ts @@ -1,11 +1,11 @@ import * as fs from "fs"; import path from "path"; -import { getRootDirectory } from "./getRootDirectory"; +import { localDistPath } from "./distConstants"; /** * Local generated page from build */ -const mainPageLocalDistDataPath = path.resolve(getRootDirectory(), "dist", "index.html"); +const mainPageLocalDistDataPath = path.resolve(localDistPath, "index.html"); export function getLocalDistIndexData() { if (!fs.existsSync(mainPageLocalDistDataPath)) { diff --git a/tests/manifest.spec.ts b/tests/manifest.spec.ts new file mode 100644 index 0000000..90855a4 --- /dev/null +++ b/tests/manifest.spec.ts @@ -0,0 +1,16 @@ +import { test, expect } from "@playwright/test"; +import { localDistManifestProductionPath, localDistManifestProductionOutlookPath } from "./distConstants"; +import * as fs from "fs"; +import path from "path"; + +test("Production manifests are free of (local)", async () => { + const productionManifests = [localDistManifestProductionPath, localDistManifestProductionOutlookPath]; + productionManifests.forEach((manifestPath) => { + const data = fs.readFileSync(manifestPath); + // check for presence of (local) which should not happen. + + const expectLocal = false; + const hasLocal = data.includes("(local)"); + expect(hasLocal, `${path.basename(manifestPath)} replaces local`).toBe(expectLocal); + }); +});