diff --git a/CHANGELOG.md b/CHANGELOG.md
index e9eb32c..c2425bc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,8 @@
## 1.0.0-beta.9 - [UNRELEASED]
### Added
- Support for named urls when sharing links to workspaces
+- Ability to convert items to other types by right-clicking
+- Ancestor items in context menus now stay tinted when their child menus are opened
### Fixed
- An issue where the inspector started to scroll horisontally on overflow
- Closing electron windows may cause a loop preventing user defaults from being saved
diff --git a/app/components/ContextMenuItem/index.jsx b/app/components/ContextMenuItem/index.jsx
index 791bc5e..082a271 100644
--- a/app/components/ContextMenuItem/index.jsx
+++ b/app/components/ContextMenuItem/index.jsx
@@ -20,7 +20,15 @@ const MOUSE_LEAVE_DELAY_MS = 150
export const ContextMenuItem = ({ text, children = [], onClick = () => {} }) => {
const elRef = React.useRef()
+
+ /*
+ Delayed hover is used for preventing unmounting of
+ child menus when the cursor leaves the item,
+ regular hover is used for tinting the item
+ */
+ const [delayedHover, setDelayedHover] = React.useState(false)
const [hover, setHover] = React.useState(false)
+
const childArr = Array.isArray(children) ? children : [children]
const timeoutRef = React.useRef()
@@ -29,12 +37,14 @@ export const ContextMenuItem = ({ text, children = [], onClick = () => {} }) =>
if (timeoutRef.current) {
clearTimeout(timeoutRef.current)
}
+ setDelayedHover(true)
setHover(true)
}
function handleMouseLeave () {
+ setHover(false)
timeoutRef.current = setTimeout(() => {
- setHover(false)
+ setDelayedHover(false)
}, MOUSE_LEAVE_DELAY_MS)
}
@@ -45,6 +55,7 @@ export const ContextMenuItem = ({ text, children = [], onClick = () => {} }) =>
}
function handleFocus (e) {
+ setDelayedHover(true)
setHover(true)
}
@@ -53,7 +64,7 @@ export const ContextMenuItem = ({ text, children = [], onClick = () => {} }) =>
return (
onClick()}
@@ -69,7 +80,7 @@ export const ContextMenuItem = ({ text, children = [], onClick = () => {} }) =>
}
{
- hover && childArr.length > 0
+ delayedHover && childArr.length > 0
? (
{children}
diff --git a/app/components/ContextMenuItem/style.css b/app/components/ContextMenuItem/style.css
index 6bc2622..6b5af8e 100644
--- a/app/components/ContextMenuItem/style.css
+++ b/app/components/ContextMenuItem/style.css
@@ -29,7 +29,8 @@
--base-color: black;
}
-.ContextMenuItem:hover > .ContextMenuItem-text {
+.ContextMenuItem:hover > .ContextMenuItem-text,
+.ContextMenuItem.is-hovered > .ContextMenuItem-text {
background: rgb(228, 228, 228);
}
diff --git a/package-lock.json b/package-lock.json
index 92b88c3..0df8d58 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4171,23 +4171,23 @@
"license": "MIT"
},
"node_modules/body-parser": {
- "version": "1.20.3",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
- "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
+ "version": "1.20.4",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz",
+ "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==",
"license": "MIT",
"dependencies": {
- "bytes": "3.1.2",
+ "bytes": "~3.1.2",
"content-type": "~1.0.5",
"debug": "2.6.9",
"depd": "2.0.0",
- "destroy": "1.2.0",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "on-finished": "2.4.1",
- "qs": "6.13.0",
- "raw-body": "2.5.2",
+ "destroy": "~1.2.0",
+ "http-errors": "~2.0.1",
+ "iconv-lite": "~0.4.24",
+ "on-finished": "~2.4.1",
+ "qs": "~6.14.0",
+ "raw-body": "~2.5.3",
"type-is": "~1.6.18",
- "unpipe": "1.0.0"
+ "unpipe": "~1.0.0"
},
"engines": {
"node": ">= 0.8",
@@ -4203,12 +4203,41 @@
"ms": "2.0.0"
}
},
+ "node_modules/body-parser/node_modules/http-errors": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
+ "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "~2.0.0",
+ "inherits": "~2.0.4",
+ "setprototypeof": "~1.2.0",
+ "statuses": "~2.0.2",
+ "toidentifier": "~1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/body-parser/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
+ "node_modules/body-parser/node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@@ -6310,39 +6339,39 @@
}
},
"node_modules/express": {
- "version": "4.21.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
- "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
+ "version": "4.22.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
+ "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
- "body-parser": "1.20.3",
- "content-disposition": "0.5.4",
+ "body-parser": "~1.20.3",
+ "content-disposition": "~0.5.4",
"content-type": "~1.0.4",
- "cookie": "0.7.1",
- "cookie-signature": "1.0.6",
+ "cookie": "~0.7.1",
+ "cookie-signature": "~1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
- "finalhandler": "1.3.1",
- "fresh": "0.5.2",
- "http-errors": "2.0.0",
+ "finalhandler": "~1.3.1",
+ "fresh": "~0.5.2",
+ "http-errors": "~2.0.0",
"merge-descriptors": "1.0.3",
"methods": "~1.1.2",
- "on-finished": "2.4.1",
+ "on-finished": "~2.4.1",
"parseurl": "~1.3.3",
- "path-to-regexp": "0.1.12",
+ "path-to-regexp": "~0.1.12",
"proxy-addr": "~2.0.7",
- "qs": "6.13.0",
+ "qs": "~6.14.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
- "send": "0.19.0",
- "serve-static": "1.16.2",
+ "send": "~0.19.0",
+ "serve-static": "~1.16.2",
"setprototypeof": "1.2.0",
- "statuses": "2.0.1",
+ "statuses": "~2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
@@ -10488,12 +10517,12 @@
"license": "MIT"
},
"node_modules/qs": {
- "version": "6.13.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
- "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
+ "version": "6.14.1",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
+ "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
"license": "BSD-3-Clause",
"dependencies": {
- "side-channel": "^1.0.6"
+ "side-channel": "^1.1.0"
},
"engines": {
"node": ">=0.6"
@@ -10556,20 +10585,49 @@
}
},
"node_modules/raw-body": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
- "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz",
+ "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==",
"license": "MIT",
"dependencies": {
- "bytes": "3.1.2",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "unpipe": "1.0.0"
+ "bytes": "~3.1.2",
+ "http-errors": "~2.0.1",
+ "iconv-lite": "~0.4.24",
+ "unpipe": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
+ "node_modules/raw-body/node_modules/http-errors": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
+ "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "~2.0.0",
+ "inherits": "~2.0.4",
+ "setprototypeof": "~1.2.0",
+ "statuses": "~2.0.2",
+ "toidentifier": "~1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/raw-body/node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/react": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
diff --git a/plugins/rundown/app/components/RundownList/index.jsx b/plugins/rundown/app/components/RundownList/index.jsx
index 4a74947..28535c2 100644
--- a/plugins/rundown/app/components/RundownList/index.jsx
+++ b/plugins/rundown/app/components/RundownList/index.jsx
@@ -281,9 +281,7 @@ export function RundownList ({
console.warn('Dropped spec is missing type')
return
}
- const itemId = await bridge.items.createItem(spec.type)
-
- bridge.items.applyItem(itemId, spec)
+ const itemId = await bridge.items.createItem(spec.type, spec?.data)
bridge.commands.executeCommand('rundown.moveItem', rundownId, newIndex, itemId)
} catch (_) {
console.warn('Tried to drop an invalid spec')
diff --git a/plugins/rundown/app/components/RundownListItem/index.jsx b/plugins/rundown/app/components/RundownListItem/index.jsx
index 70a2925..be51318 100644
--- a/plugins/rundown/app/components/RundownListItem/index.jsx
+++ b/plugins/rundown/app/components/RundownListItem/index.jsx
@@ -128,6 +128,11 @@ export function RundownListItem ({
label: 'Add after',
children: contextMenu.generateAddContextMenuItems(types, typeId => handleAdd(typeId))
},
+ {
+ type: 'item',
+ label: 'Convert to',
+ children: contextMenu.generateAddContextMenuItems(types, typeId => handleConvertTo(typeId))
+ },
{
type: 'item',
label: 'Create reference',
@@ -189,6 +194,16 @@ export function RundownListItem ({
bridge.commands.executeCommand('rundown.moveItem', rundownId, index + 1, itemId)
}
+ async function handleConvertTo (typeId) {
+ if (!item?.id) {
+ return
+ }
+
+ await bridge.items.applyItem(item?.id, {
+ type: typeId
+ })
+ }
+
async function handleCreateReference () {
const newItemId = await bridge.items.createItem('bridge.types.reference')