Skip to content

Commit

Permalink
Merge pull request #37 from nebulabroadcast/rundown_view
Browse files Browse the repository at this point in the history
Experimental: Scheduling in the web interface
  • Loading branch information
martastain authored Oct 20, 2024
2 parents 2313bee + e7e80cf commit a80fcd5
Show file tree
Hide file tree
Showing 43 changed files with 1,566 additions and 89 deletions.
1 change: 1 addition & 0 deletions backend/api/rundown/get_rundown.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ async def get_rundown(request: RundownRequestModel) -> RundownResponseModel:
id_asset=id_asset,
id_bin=id_bin,
id_event=id_event,
id_folder=asset["id_folder"] if asset else None,
duration=duration,
status=istatus,
transfer_progress=transfer_progress,
Expand Down
1 change: 1 addition & 0 deletions backend/api/rundown/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class RundownRow(ResponseModel):
title: str | None = Field(None)
subtitle: str | None = Field(None)
id_asset: int | None = Field(None)
id_folder: int | None = Field(None)
asset_mtime: float | None = Field(None)
status: ObjectStatus | None = Field(None)
transfer_progress: int | None = Field(None)
Expand Down
4 changes: 2 additions & 2 deletions backend/schema/meta-aliases-cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
["atmosphere" , "Atmosféra" , null , ""],
["video/index" , "Index video stopy" , "Index video" , ""],
["video/height" , "Výška" , null , "Výška obrazu v pixelech"],
["mark_out" , "Mark out" , "Out" , ""],
["mark_out" , "Mark out" , "Mark out" , ""],
["description/original" , "Původní popis" , "Pův. popis" , ""],
["language" , "Jazyk" , null , ""],
["audio/r128/lra/t" , "LRA T" , null , ""],
Expand All @@ -127,7 +127,7 @@
["audio/r128/lra/l" , "LRA L" , null , ""],
["id/main" , "IDEC" , null , ""],
["subtitle/original" , "Původní podtitul" , "Pův. podtitul" , "Podtitul díla v původním jazyce"],
["mark_in" , "Mark in" , "In" , ""],
["mark_in" , "Mark in" , "Mark out" , ""],
["commercial/client" , "Klient" , null , "Zadavatel reklamy"],
["title/original" , "Původní název" , "Pův. název" , "Název díla v původním jazyce"],
["id_storage" , "Úložiště" , null , ""],
Expand Down
4 changes: 2 additions & 2 deletions backend/schema/meta-aliases-en.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
["atmosphere" , "Atmosphere" , null , "Feeling summarising the atmosphere"],
["video/index" , "Video track index" , "Video index" , ""],
["video/height" , "Height" , null , ""],
["mark_out" , "Mark out" , null , "The point in time the content proposed for editorial use starts"],
["mark_out" , "Mark out" , "Mark out" , "The point in time the content proposed for editorial use starts"],
["description/original" , "Original description" , "Orig. description" , ""],
["language" , "Language" , null , "Language version of the asset"],
["audio/r128/lra/t" , "LRA T" , null , ""],
Expand All @@ -127,7 +127,7 @@
["audio/r128/lra/l" , "LRA L" , null , ""],
["id/main" , "IDEC" , null , "An unambiguous reference to the resource within a given context"],
["subtitle/original" , "Original subtitle" , "Orig. subtitle" , ""],
["mark_in" , "Mark in" , "In" , "The point in time the content proposed for editorial use ends"],
["mark_in" , "Mark in" , "Mark in" , "The point in time the content proposed for editorial use ends"],
["commercial/client" , "Client" , null , ""],
["title/original" , "Original title" , "Orig. title" , ""],
["id_storage" , "Storage" , null , ""],
Expand Down
2 changes: 2 additions & 0 deletions backend/setup/defaults/meta_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,13 @@
"broadcast_time": {
"ns": "v",
"type": T.DATETIME,
"mode": "time",
"format": "%H:%M:%S",
},
"scheduled_time": {
"ns": "v",
"type": T.DATETIME,
"mode": "time",
"format": "%H:%M:%S",
},
"rundown_difference": {
Expand Down
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
},
"dependencies": {
"@devbookhq/splitter": "^1.4.0",
"@dnd-kit/core": "^6.0.8",
"@reduxjs/toolkit": "^1.8.5",
"@wfoxall/timeframe": "^1.2.0",
"axios": "^1.6.7",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const App = () => {
.then((response) => {
setInitData(response.data)
nebula.settings = response.data.settings
nebula.experimental = response.data.experimental || false
nebula.plugins = response.data.frontend_plugins || []
nebula.scopedEndpoints = response.data.scoped_endpoints || []
nebula.user = response.data.user || {}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/ContextMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ const ContextMenu = ({ target, options }) => {
icon={option.icon}
onClick={() => {
setContextData({ ...contextData, visible: false })
option.onClick && option.onClick()
option.onClick && option.onClick(contextData)
}}
/>
</span>
Expand Down
22 changes: 19 additions & 3 deletions frontend/src/components/Dialog.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useEffect, useRef } from 'react'
import styled from 'styled-components'
import clsx from 'clsx'

const StyledDialog = styled.dialog`
color: var(--color-text);
Expand All @@ -15,13 +16,28 @@ const StyledDialog = styled.dialog`
max-height: 80%;
border: none;
// Animated parameters
transition: all 0.3s ease;
opacity: 0;
transform: scale(0.9);
&::backdrop {
background-color: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(2px);
background-color: rgba(0, 0, 0, 0);
backdrop-filter: none;
}
&[open] {
opacity: 1;
transform: scale(1);
&::backdrop {
background-color: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(2px);
}
}
// Guts
header,
footer {
padding: 12px 6px;
Expand Down Expand Up @@ -97,7 +113,7 @@ const Dialog = ({

return (
<StyledDialog
className={className}
className={clsx(className, 'enter-active')}
style={style}
ref={dialogRef}
onClick={onShadeClick}
Expand Down
9 changes: 5 additions & 4 deletions frontend/src/components/Fields.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ const DateTime = styled.div`
flex-direction: row;
gap: 8px;
align-items: center;
font-size: 0.9rem;
> span:first-child {
color: ${(props) => props.theme.colors.textDim};
font-size: 1rem;
color: ${(props) => props.theme.colors.textDim};
> span:last-child {
color: ${(props) => props.theme.colors.text};
}
`

Expand Down Expand Up @@ -39,7 +40,7 @@ const Timestamp = ({ timestamp, mode, ...props }) => {

return (
<DateTime {...props}>
<span>{localDate}</span>
{!(mode === 'time') && <span>{localDate}</span>}
{!(mode === 'date') && <span>{localTime}</span>}
</DateTime>
)
Expand Down
16 changes: 16 additions & 0 deletions frontend/src/components/Icon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import styled from 'styled-components'

const StyledIcon = styled.span`
user-select: none !important;
user-drag: none !important;
`

const Icon = ({ icon, style }) => {
return (
<StyledIcon className="icon material-symbols-outlined" style={style}>
{icon}
</StyledIcon>
)
}

export default Icon
62 changes: 62 additions & 0 deletions frontend/src/components/InputColor.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { useMemo } from 'react'
import styled from 'styled-components'
import defaultTheme from './theme'
import BaseInput from './BaseInput'

const BaseColorInput = styled(BaseInput)`
width: 30px;
`

const COLOR_PRESETS = [
'#dc8a78',
'#dd7878',
'#ea76cb',
'#8839ef',
'#d20f39',
'#e64553',
'#fe640b',
'#df8e1d',
'#40a02b',
'#179299',
'#04a5e5',
'#209fb5',
'#1e66f5',
'#7287fd',
'#4c4f69',
]

const InputColor = ({ value, onChange, tooltip, ...props }) => {
/*
Nebula stores color as integer so we need to convert it to hex
*/

const hexValue = useMemo(() => {
if (!value) return '#7287fd'
return `#${value.toString(16).padStart(6, '0')}`
}, [value])

const setColor = (hex) => {
if (!hex) return null
onChange(parseInt(hex.slice(1), 16))
}

return (
<>
<BaseColorInput
type="color"
value={hexValue}
title={tooltip}
list="presetColors"
onChange={(e) => setColor(e.target.value)}
{...props}
/>
<datalist id="presetColors">
{COLOR_PRESETS.map((color) => (
<option key={color} value={color} />
))}
</datalist>
</>
)
}

export default InputColor
44 changes: 44 additions & 0 deletions frontend/src/components/RangeSlider.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { forwardRef } from 'react'
import styled from 'styled-components'
import defaultTheme from './theme'

const StyledRange = styled.input`
border: 0;
border-radius: ${(props) => props.theme.inputBorderRadius};
background: ${(props) => props.theme.inputBackground};
-webkit-appearance: none;
appearance: none;
background: transparent;
cursor: pointer;
width: 150px;
outline: none;
&::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 14px;
height: 14px;
border-radius: 50%;
background: ${(props) => props.theme.colors.surface08};
}
&::-webkit-slider-runnable-track {
width: 100%;
cursor: pointer;
background: ${(props) => props.theme.colors.surface04};
border-radius: 8px;
}
`

StyledRange.defaultProps = {
theme: defaultTheme,
type: 'range',
}

const RangeSlider = forwardRef((props, ref) => {
return <StyledRange ref={ref} type="range" {...props} />
})

export default RangeSlider
23 changes: 13 additions & 10 deletions frontend/src/components/index.jsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
export { default as Table } from './table'
export { default as Button } from './Button'
export { default as Canvas } from './Canvas'
export { default as DatePicker } from './DatePicker'
export { default as Dialog } from './Dialog'
export { default as Dropdown } from './Dropdown'
export { default as ErrorBanner } from './ErrorBanner'
export { default as Loader } from './Loader'
export { default as Progress } from './Progress'
export { default as Select } from './Select'
export { default as SelectDialog } from './SelectDialog'
export { default as Icon } from './Icon'
export { default as InputColor } from './InputColor'
export { default as InputDatetime } from './InputDatetime'
export { default as InputInteger } from './InputInteger'
export { default as InputNumber } from './InputNumber'
export { default as InputPassword } from './InputPassword'
export { default as InputSwitch } from './InputSwitch'
export { default as InputText } from './InputText'
export { default as InputTimecode } from './InputTimecode'
export { default as InputSwitch } from './InputSwitch'
export { default as TextArea } from './TextArea'
export { default as Button } from './Button'
export { default as DatePicker } from './DatePicker'
export { default as Canvas } from './Canvas'
export { default as Loader } from './Loader'
export { default as Progress } from './Progress'
export { default as RadioButton } from './RadioButton'
export { default as RangeSlider } from './RangeSlider'
export { default as Select } from './Select'
export { default as SelectDialog } from './SelectDialog'
export { default as Table } from './table'
export { default as TextArea } from './TextArea'

export { DateTime, Timestamp } from './Fields'
export { Form, FormRow } from './Form'
Expand Down
28 changes: 26 additions & 2 deletions frontend/src/components/table/cells.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { useMemo } from 'react'
import { useDraggable } from '@dnd-kit/core'
import clsx from 'clsx'

const HeaderCell = ({ name, width, title, sortDirection, onSort }) => {
let sortArrowElement = null
Expand Down Expand Up @@ -47,8 +49,21 @@ const DataRow = ({
onRowClick,
rowHighlightColor,
rowHighlightStyle,
rowClass,
selected = false,
}) => {
const { attributes, listeners, setNodeRef, transform, isDragging } =
useDraggable({
id: rowData.id,
data: {
id: rowData.id,
type: 'asset',
duration: rowData.duration,
title: rowData.title,
subtitle: rowData.subtitle,
},
})

const handleClick = (event) => {
if (event.type === 'contextmenu' || event.button === 2) {
// if we're right-clicking, and the row is already selected,
Expand All @@ -58,13 +73,19 @@ const DataRow = ({

if (onRowClick) onRowClick(rowData, event)
}
const rowStyle = {}

const rowStyle = {
opacity: isDragging ? 0.5 : 1,
}

let rowClassName = ''

// Left-border highlight color
let highlightColor = null
let highlightStyle = null
if (rowHighlightColor) highlightColor = rowHighlightColor(rowData)
if (rowHighlightStyle) highlightStyle = rowHighlightStyle(rowData)
if (rowClass) rowClassName = rowClass(rowData)
if (highlightColor) rowStyle['borderLeftColor'] = highlightColor
if (highlightStyle) rowStyle['borderLeftStyle'] = highlightStyle

Expand Down Expand Up @@ -95,9 +116,12 @@ const DataRow = ({

return (
<tr
ref={setNodeRef}
onClick={handleClick}
onContextMenu={handleClick}
className={selected ? 'selected' : ''}
{...attributes}
{...listeners}
className={clsx(selected && 'selected', rowClassName)}
style={rowStyle}
>
{rowContent}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/table/container.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const TableWrapper = styled.div`
display: block;
z-index: 0;
width: 0;
opacity: 0;
opacity: 0;
content: "";
}
}
Expand Down
Loading

0 comments on commit a80fcd5

Please sign in to comment.