-
Notifications
You must be signed in to change notification settings - Fork 211
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create app sample registering custom actions (#167)
* PF-1292 - Create app sample registering custom actions * Adding custom actions app sample * Formatting code * Removing package-lock.json
- Loading branch information
Showing
11 changed files
with
5,008 additions
and
4,599 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.js | ||
.next | ||
|
||
# testing | ||
/coverage | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
.idea | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# local env files | ||
.env | ||
dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
## Custom Actions | ||
|
||
** ℹ Note**: | ||
|
||
- We recommend a Chromium-based web browser for local development with HTTP. \ | ||
Safari enforces HTTPS; therefore, it doesn't allow localhost through HTTP. | ||
- For more information, visit our [developer documentation](https://developers.miro.com). | ||
|
||
### How to start locally | ||
|
||
- Run `npm i` to install dependencies. | ||
- Run `npm start` to start developing. \ | ||
Your URL should be similar to this example: | ||
|
||
``` | ||
http://localhost:3000 | ||
``` | ||
|
||
- Paste the URL under **App URL** in your | ||
[app settings](https://developers.miro.com/docs/build-your-first-hello-world-app#step-3-configure-your-app-in-miro). | ||
- Open a board; you should see your app in the app toolbar or in the **Apps** | ||
panel. | ||
|
||
### How to build the app | ||
|
||
- Run `npm run build`. \ | ||
This generates a static output inside [`dist/`](./dist), which you can host on a static hosting | ||
service. | ||
|
||
### Folder structure | ||
|
||
<!-- The following tree structure is just an example --> | ||
|
||
``` | ||
. | ||
├── src | ||
│ ├── assets | ||
│ │ └── style.css | ||
│ ├── app.ts // The code for the app lives here | ||
│ └── index.ts // The code for the app entry point lives here | ||
├── app.html // The app itself. It's loaded on the board inside the 'appContainer' | ||
└── index.html // The app entry point. This is what you specify in the 'App URL' box in the Miro app settings | ||
``` | ||
|
||
### About the app | ||
|
||
This sample app provides you with boilerplate setup and configuration that you can further customize to build your own app. | ||
|
||
<!-- describe shortly the purpose of the sample app --> | ||
|
||
Built using [`create-miro-app`](https://www.npmjs.com/package/create-miro-app). | ||
|
||
This app uses [Vite](https://vitejs.dev/). \ | ||
If you want to modify the `vite.config.js` configuration, see the [Vite documentation](https://vitejs.dev/guide/). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<script src="https://miro.com/app/static/sdk/v2/miro.js"></script> | ||
<title>Custom Actions</title> | ||
</head> | ||
<body> | ||
<div id="root"> | ||
<h1>Custom actions home</h1> | ||
</div> | ||
|
||
<script type="module" src="/src/app.ts"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// https://vitejs.dev/guide/features.html#typescript-compiler-options | ||
/// <reference types="vite/client" /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<script src="https://miro.com/app/static/sdk/v2/miro.js"></script> | ||
<title>Custom Actions</title> | ||
</head> | ||
<body> | ||
<div id="root"> | ||
<h1>Custom actions</h1> | ||
</div> | ||
<script type="module" src="/src/index.ts"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"name": "custom-actions", | ||
"version": "0.1.0", | ||
"license": "MIT", | ||
"scripts": { | ||
"start": "vite", | ||
"build": "vite build", | ||
"serve": "vite preview" | ||
}, | ||
"dependencies": { | ||
"mirotone": "5" | ||
}, | ||
"devDependencies": { | ||
"@mirohq/websdk-types": "latest", | ||
"typescript": "4.9.5", | ||
"vite": "3.0.3" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
import type { CustomAction, CustomEvent, Frame } from "@mirohq/websdk-types"; | ||
|
||
const actionHandler = (action: string) => async (props: CustomEvent) => { | ||
const content = props.items.map((w) => w.id).join(" - "); | ||
const message = `Clicked on ${action} => ${content}`; | ||
await miro.board.notifications.showInfo(message); | ||
}; | ||
|
||
export async function init() { | ||
await miro.board.ui.on( | ||
"custom:translate-content", | ||
actionHandler("translate-content") | ||
); | ||
await miro.board.ui.on( | ||
"custom:align-to-grid", | ||
actionHandler("align-to-grid") | ||
); | ||
|
||
const translateAction: CustomAction = { | ||
event: "translate-content", | ||
ui: { | ||
label: { | ||
en: "Translate content", | ||
de: "Traduzir conteúdo", | ||
es: "Traducir contenido", | ||
}, | ||
icon: "chat-two", | ||
description: { | ||
en: "Translate the content of your element", | ||
de: "Übersetzen Sie den Inhalt Ihres Elements", | ||
es: "Traduce el contenido de tu elemento", | ||
}, | ||
position: 1, | ||
}, | ||
predicate: { | ||
$or: [ | ||
// Matching multiple types | ||
{ | ||
type: "preview", | ||
}, | ||
{ | ||
type: "frame", | ||
}, | ||
{ | ||
type: "text", | ||
}, | ||
{ | ||
type: "card", | ||
}, | ||
{ | ||
type: "sticky_note", | ||
}, | ||
// Matching nested properties with dot notation | ||
{ | ||
type: "shape", | ||
shape: "circle", | ||
"style.color": "#1a1a1a", | ||
}, | ||
// Images that have landscape aspect ratio | ||
{ | ||
type: "image", | ||
$where: "this.width > this.height", | ||
}, | ||
// Embed widget with a given URL matching the Regex | ||
{ type: "embed", url: { $regex: ".*vimeo.com.*" } }, | ||
// App owned app_card | ||
{ type: "app_card", owned: true }, | ||
// Connectors with both start and end connected to them | ||
{ | ||
type: "connector", | ||
start: { | ||
$exists: true, | ||
}, | ||
end: { | ||
$exists: true, | ||
}, | ||
}, | ||
], | ||
}, | ||
}; | ||
|
||
await miro.board.ui.on("custom:active-action", (props: CustomEvent) => { | ||
props.items.map((w) => w.setMetadata("status", "active")); | ||
}); | ||
await miro.board.ui.on("custom:inactive-action", (props: CustomEvent) => { | ||
props.items.map((w) => w.setMetadata("status", "inactive")); | ||
}); | ||
|
||
const activeAction: CustomAction = { | ||
event: "active-action", | ||
ui: { | ||
label: "Activate", | ||
icon: "chat-dashes-lines-two", | ||
description: "Set card to active", | ||
position: 1, | ||
}, | ||
predicate: { | ||
type: "card", | ||
$or: [ | ||
{ | ||
"metadata.status": { | ||
$exists: false, | ||
}, | ||
}, | ||
{ | ||
"metadata.status": "inactive", | ||
}, | ||
], | ||
}, | ||
}; | ||
|
||
const inactiveAction: CustomAction = { | ||
event: "inactive-action", | ||
ui: { | ||
label: "Inactivate", | ||
icon: "chat-lines-cross", | ||
description: "Set card to inactive", | ||
position: 1, | ||
}, | ||
predicate: { | ||
type: "card", | ||
"metadata.status": "active", | ||
}, | ||
}; | ||
|
||
const votingHandler = async (props: CustomEvent) => { | ||
const voting = await miro.board.experimental.getVotingResults(); | ||
const boardInfo = await miro.board.getInfo(); | ||
|
||
if (!voting.length) { | ||
await miro.board.notifications.showInfo("No voting results available"); | ||
} | ||
|
||
const votingWithResults = voting.filter((v) => v.results.length > 0); | ||
const [parent] = props.items as Frame[]; | ||
|
||
votingWithResults.map(async (voting) => { | ||
const title = await miro.board.createText({ | ||
x: parent.x, | ||
y: parent.y, | ||
width: 500, | ||
content: voting.title, | ||
style: { | ||
fontSize: 80, | ||
}, | ||
}); | ||
|
||
await parent.add(title); | ||
title.x = 400; | ||
title.y = 200; | ||
|
||
await title.sync(); | ||
|
||
const itemsResult = voting.results.map(async (item, i) => { | ||
try { | ||
const boardItem = await miro.board.createStickyNote({ | ||
x: parent.x, | ||
y: parent.y, | ||
content: `Item: ${item.itemId} => Votes: ${item.count}`, | ||
linkedTo: `/app/board/${boardInfo.id}/?moveToWidget=${item.itemId}`, | ||
}); | ||
|
||
await parent.add(boardItem); | ||
boardItem.x = 200 * (i + 1); | ||
boardItem.y = 400; | ||
await boardItem.sync(); | ||
} catch (error) { | ||
console.error(error); | ||
} | ||
}); | ||
|
||
await Promise.allSettled(itemsResult); | ||
|
||
await miro.board.viewport.zoomTo([parent]); | ||
}); | ||
}; | ||
|
||
await miro.board.ui.on("custom:get-voting-results", votingHandler); | ||
|
||
const votingResults = { | ||
event: "get-voting-results", | ||
ui: { | ||
label: "Get voting results", | ||
icon: "trophy", | ||
description: "Create sticky notes with voting results", | ||
}, | ||
predicate: { | ||
type: "frame", | ||
}, | ||
}; | ||
|
||
await miro.board.experimental.action.register(activeAction); | ||
await miro.board.experimental.action.register(inactiveAction); | ||
await miro.board.experimental.action.register(translateAction); | ||
await miro.board.experimental.action.register(votingResults); | ||
} | ||
|
||
init(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"compilerOptions": { | ||
"target": "esnext", | ||
"module": "esnext", | ||
"lib": ["esnext", "dom"], | ||
"jsx": "preserve", | ||
"moduleResolution": "node", | ||
"strict": true, | ||
"sourceMap": true, | ||
"resolveJsonModule": true, | ||
"esModuleInterop": true, | ||
"noEmit": true, | ||
"noUnusedLocals": true, | ||
"noUnusedParameters": true, | ||
"noImplicitReturns": true, | ||
"skipLibCheck": true, | ||
"forceConsistentCasingInFileNames": true, | ||
"typeRoots": ["./node_modules/@types", "./node_modules/@mirohq"], | ||
"allowJs": true, | ||
"incremental": true, | ||
"isolatedModules": true | ||
}, | ||
"include": ["src", "pages", "*.ts"], | ||
"exclude": ["node_modules"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import path from "path"; | ||
import fs from "fs"; | ||
import dns from "dns"; | ||
import { defineConfig } from "vite"; | ||
|
||
// https://vitejs.dev/config/server-options.html#server-host | ||
dns.setDefaultResultOrder("verbatim"); | ||
|
||
// make sure vite picks up all html files in root, needed for vite build | ||
const allHtmlEntries = fs | ||
.readdirSync(".") | ||
.filter((file) => path.extname(file) === ".html") | ||
.reduce((acc, file) => { | ||
acc[path.basename(file, ".html")] = path.resolve(__dirname, file); | ||
|
||
return acc; | ||
}, {}); | ||
|
||
// https://vitejs.dev/config/ | ||
export default defineConfig({ | ||
build: { | ||
rollupOptions: { | ||
input: allHtmlEntries, | ||
}, | ||
}, | ||
server: { | ||
port: 3000, | ||
}, | ||
}); |
Oops, something went wrong.
1d8de70
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
app-examples-wordle – ./examples/wordle
app-examples-wordle.vercel.app
app-examples-wordle-git-main-anthonyroux.vercel.app
app-examples-wordle-anthonyroux.vercel.app
1d8de70
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
webhooks-manager – ./examples/webhooks-manager
webhooks-manager-git-main-miro-web.vercel.app
webhooks-manager-miro-web.vercel.app
webhooks-manager-sepia.vercel.app