* refactor: align header columns

* refactor: improve scrollbar visibility

* refactor: center align table elements

* refactor: make param elements stateful

* fix: issue with collapsed elements not loosing value

* fix: prevent search params containing multiple alias references

* fix: the issue where a file disappears if it is both migrated and recovered in the same load operation (#1744)

* refactor: disable group action for elements in groups

* refactor: move context menu items into the event element (#1747)

* feat: sheet import new features for v4 (#1730)

* import milestone

* fixup! import milestone

* test: milestone import

* add entries to group

stop on new group or on group-end type

* fixup! add entries to group

* cleanup

* add event target duration

* link start if undefined

* add skip import type

* extract some to the excel paresing functions

* tweaks to presentation

* move file

---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>

* fix: notify runtimeStore of events bieng groupd

* fix: improve authentication and stage detection in demo

* chore: ship logo with project

* fix: client is referenced by name

* fix: prevent reflow in event editor

* fix: stale render on selected event due to ref mismatch

* Create/Load/Delete multiple rundowns (#1696)

* refactor: restore last loaded rundown

* refactor: initialise rundown in ProjectService

* feat: allow switching rundowns

ensure on coordination between the db object and the working object

server provide list of rundowns

implement switch in the UI

implement delete

implement new rundown button

* fix: render order for floating button

* refactor: appropriate names to service

* refactor: rundown endpoints

* refactor: save last loaded rundown ID

* refactor: rundown management UI

* refactor: emit refetch all on project load

---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>

* feat: recover single event subscription

* fixup! feat: sheet import new features for v4 (#1730)

* fix: prevent dropping a group inside another

* fixup! refactor: move context menu items into the event element (#1747)

* fix: prevent stale references to custom fields

* fix: propagate updates to all rundowns

* refactor: client rundown metadata (#1728)

* generate metadata in the hook

* move test

* ensure there is always a last element

* use for-loop

* update metadata in useEfect

* fully extract metadata generation

* use direct assignment

* cleanup

---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>

* refactor: small imporvement and tests for coerce functions (#1752)

* refactor: small imporvement and tests for coerce functions

add test `coerceString`

add test `coerceBoolean`

add test `coerceColour`

* remove old todo

* fix: consistent quick add behaviour

* refactor: create flat rundown with metadata

* fix: show add buttons on top

* feat: allow editing milestones

* refactor: style tweaks to rundown elements

refactor: milestones are full width

refactor: cuesheet header alignment

fix: editor styling in cuesheet

* refactor: virtualise table

* refactor: improve overscan (#1758)

* bump version to 4.0.0-alpha.5

---------

Co-authored-by: Alex Christoffer Rasmussen <ac@omnivox.dk>
This commit is contained in:
Carlos Valente
2025-09-03 15:50:20 +02:00
committed by GitHub
parent 3c41b40c5f
commit ae15f3cdc5
102 changed files with 2950 additions and 2104 deletions
@@ -1,4 +1,4 @@
import { coerceColour, coerceEnum } from '../coerceType.js';
import { coerceBoolean, coerceColour, coerceEnum, coerceNumber, coerceString } from '../coerceType.js';
describe('parses a colour string that is', () => {
it('valid hex', () => {
@@ -44,3 +44,145 @@ describe('match a string to an enum that is', () => {
expect(() => coerceEnum(123, testEnum)).toThrow();
});
});
describe('coerce unknown value to a number', () => {
it('throws on null', () => {
expect(() => coerceNumber(null)).toThrowError('Invalid value received');
});
it('throws on NaN', () => {
expect(() => coerceNumber('abc')).toThrowError('Invalid value received');
});
it('throws on undefined', () => {
expect(() => coerceNumber(undefined)).toThrowError('Invalid value received');
});
it('throws on object', () => {
expect(() => coerceNumber({ test: 'object' })).toThrowError('Invalid value received');
});
it('throws on array', () => {
expect(() => coerceNumber([1, 2, 3])).toThrowError('Invalid value received');
});
it('casts string to number', () => {
expect(coerceNumber('123')).toStrictEqual(123);
});
it('handles white space', () => {
expect(coerceNumber(' 9 ')).toStrictEqual(9);
});
it('handles normal numbers', () => {
expect(coerceNumber(5)).toStrictEqual(5);
});
it('handles booleans', () => {
expect(coerceNumber(true)).toStrictEqual(1);
expect(coerceNumber(false)).toStrictEqual(0);
});
});
describe('coerce unknown value to a string', () => {
it('throws on null', () => {
expect(() => coerceString(null)).toThrowError('Invalid value received');
});
it('throws on undefined', () => {
expect(() => coerceString(undefined)).toThrowError('Invalid value received');
});
it('throws on objects', () => {
expect(() => coerceString({ test: 'object' })).toThrowError('Invalid value received');
});
it('throws on array', () => {
expect(() => coerceString([1, 2, 3])).toThrowError('Invalid value received');
});
it('casts number to string', () => {
expect(coerceString(123)).toStrictEqual('123');
});
it('handles normal strings', () => {
expect(coerceString('abcd')).toStrictEqual('abcd');
});
it('handles booleans', () => {
expect(coerceString(true)).toStrictEqual('true');
expect(coerceString(false)).toStrictEqual('false');
});
});
describe('coerce unknown value to a boolean', () => {
it('throws on null', () => {
expect(() => coerceBoolean(null)).toThrowError('Invalid value received');
});
it('throws on undefined', () => {
expect(() => coerceBoolean(undefined)).toThrowError('Invalid value received');
});
it('throws on objects', () => {
expect(() => coerceBoolean({ test: 'object' })).toThrowError('Invalid value received');
});
it('throws on array', () => {
expect(() => coerceBoolean([1, 2, 3])).toThrowError('Invalid value received');
});
test('true strings', () => {
expect(coerceBoolean('true')).toStrictEqual(true);
expect(coerceBoolean('1')).toStrictEqual(true);
expect(coerceBoolean('yes')).toStrictEqual(true);
});
test('false strings', () => {
expect(coerceBoolean('false')).toStrictEqual(false);
expect(coerceBoolean('0')).toStrictEqual(false);
expect(coerceBoolean('no')).toStrictEqual(false);
expect(coerceBoolean('')).toStrictEqual(false);
});
test('true numbers', () => {
expect(coerceBoolean(1)).toStrictEqual(true);
expect(coerceBoolean(2)).toStrictEqual(true);
expect(coerceBoolean(100000)).toStrictEqual(true);
});
test.todo('false numbers', () => {
expect(coerceBoolean(0)).toStrictEqual(false);
expect(coerceBoolean(-1)).toStrictEqual(false);
expect(coerceBoolean(-10000)).toStrictEqual(false);
});
test('booleans', () => {
expect(coerceBoolean(true)).toStrictEqual(true);
expect(coerceBoolean(false)).toStrictEqual(false);
});
});
describe('coerce unknown value to a colour', () => {
it('throws on all non strings', () => {
expect(() => coerceColour(null)).toThrowError('Invalid colour value received');
expect(() => coerceColour(undefined)).toThrowError('Invalid colour value received');
expect(() => coerceColour({ test: 'object' })).toThrowError('Invalid colour value received');
expect(() => coerceColour([1, 2, 3])).toThrowError('Invalid colour value received');
expect(() => coerceColour(true)).toThrowError('Invalid colour value received');
expect(() => coerceColour(false)).toThrowError('Invalid colour value received');
});
test('hex values', () => {
expect(() => coerceColour('#1')).toThrowError('Invalid hex colour received');
expect(coerceColour('#AAA')).toStrictEqual('#aaa');
expect(coerceColour('#FF3366')).toStrictEqual('#ff3366');
});
test('css values', () => {
expect(() => coerceColour('grøn')).toThrowError('Invalid colour name received');
expect(coerceColour('')).toStrictEqual('');
expect(coerceColour('aliceblue')).toStrictEqual('aliceblue');
expect(coerceColour('darkkhaki')).toStrictEqual('darkkhaki');
});
});
+2 -5
View File
@@ -13,7 +13,6 @@ export function coerceEnum<T>(value: unknown, list: object): T {
return value as T;
}
//TODO: write tests
/**
* @description Converts a value to a string if possible, throws otherwise
* @param {unknown} value - Value to be converted to a string.
@@ -21,13 +20,12 @@ export function coerceEnum<T>(value: unknown, list: object): T {
* @throws {Error} Throws an error if the value is null or undefined.
*/
export function coerceString(value: unknown): string {
if (value == null) {
if (value == null || typeof value === 'object') {
throw new Error('Invalid value received');
}
return String(value);
}
//TODO: write tests
/**
* @description Converts a value to a boolean if possible, throws otherwise
* @param {unknown} value - Value to be converted to a boolean.
@@ -35,7 +33,7 @@ export function coerceString(value: unknown): string {
* @throws {Error} Throws an error if the value is null or undefined.
*/
export function coerceBoolean(value: unknown): boolean {
if (value == null) {
if (value === undefined || typeof value === 'object') {
throw new Error('Invalid value received');
}
if (typeof value === 'string') {
@@ -57,7 +55,6 @@ export function coerceBoolean(value: unknown): boolean {
return Boolean(value);
}
//TODO: write tests
/**
* @description Converts a value to a number if possible, throws otherwise
* @param {unknown} value - Value to be converted to a number.