Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
148 commits
Select commit Hold shift + click to select a range
0e87184
feat(tracker): register Gantt view tab (placeholder UI)
MichaelUray May 15, 2026
4868b15
feat(tracker-resources): add Gantt lib types
MichaelUray May 15, 2026
5399bf6
test(tracker-resources): add failing Gantt time-scale tests
MichaelUray May 15, 2026
de2652e
feat(tracker-resources): implement Gantt time-scale lib
MichaelUray May 15, 2026
1ba2a15
test(tracker-resources): add failing Gantt layout tests
MichaelUray May 15, 2026
4ef672f
feat(tracker-resources): implement Gantt layout lib
MichaelUray May 15, 2026
e7e0472
feat(tracker-resources): add GanttHeader.svelte
MichaelUray May 15, 2026
2173ab4
feat(tracker-resources): add GanttBar.svelte (regular + summary claws)
MichaelUray May 15, 2026
af2d60a
feat(tracker-resources): add GanttTodayMarker.svelte
MichaelUray May 15, 2026
84355bd
feat(tracker-resources): add GanttMilestoneFlag.svelte
MichaelUray May 15, 2026
cc37678
feat(tracker-resources): add GanttCanvas.svelte
MichaelUray May 15, 2026
528eac4
feat(tracker-resources): add GanttSidebar.svelte
MichaelUray May 15, 2026
d257021
feat(tracker-resources): add GanttToolbar.svelte (zoom buttons)
MichaelUray May 15, 2026
1dfac46
feat(tracker-resources): GanttView wires Sidebar+Canvas+Toolbar with …
MichaelUray May 15, 2026
787f2ae
- layout.ts: orphan child issues (parent filtered out) now emit as roots
MichaelUray May 15, 2026
d100e2a
Toolbar (replaces previous floating zoom):
MichaelUray May 15, 2026
0f43f8f
- SVG horizontal-scroll bug: GanttHeader and GanttCanvas now render at
MichaelUray May 15, 2026
295d1bd
feat(tracker-resources): wire Gantt sidebar toggles into Customize-View
MichaelUray May 15, 2026
8cbe5a0
fix(tracker-resources): clip GanttSidebar inside its host
MichaelUray May 15, 2026
6eda168
fix(tracker-resources): unified Gantt scroll container (Plane-style s…
MichaelUray May 15, 2026
c307059
feat(tracker-resources): + New issue button in Gantt toolbar
MichaelUray May 15, 2026
2d8e4e6
chore(tracker): localize Gantt UI strings + minimize locale diffs
MichaelUray May 15, 2026
c5a65dc
feat(tracker-resources): blue plus-only NewIssueHeader
MichaelUray May 15, 2026
44b8797
fix(tracker-resources): resize handle no longer fights canvas pan
MichaelUray May 15, 2026
b2582fc
feat(tracker-resources): sticky-bottom horizontal scrollbar (Plane-st…
MichaelUray May 15, 2026
f1cd1a2
feat(tracker-resources): custom DOM scrollbar thumb (visible everywhere)
MichaelUray May 15, 2026
3d5ea84
feat(tracker-resources): hardened scrollbars + status colors + tight …
MichaelUray May 15, 2026
3bd0761
feat(tracker-resources): status badge column + ganttShowStatus toggle
MichaelUray May 15, 2026
fa36024
feat(tracker-resources): Tracker UI redesign polish v27
MichaelUray May 15, 2026
619b9a2
feat(tracker-resources): inline-add row in Gantt sidebar (PR2.1)
MichaelUray May 15, 2026
61c8df3
feat(model-tracker): register startDate + dueDate as Issue filters
MichaelUray May 15, 2026
27f29b5
fix(tracker-resources): hide Gantt h-scrollbar when there's no overflow
MichaelUray May 15, 2026
0911bb0
chore(tracker-resources): remove internal review markers from inline …
MichaelUray May 15, 2026
614929d
fix(tracker-resources): resolve eslint errors in gantt read-only comp…
MichaelUray Jul 3, 2026
6760882
chore(tracker-resources): apply prettier formatting after develop merge
MichaelUray Jul 3, 2026
08edbc5
feat(tracker-resources): Gantt drag/resize state types
MichaelUray May 15, 2026
3b41142
feat(tracker-resources): drag-controller reducer skeleton + idle tran…
MichaelUray May 15, 2026
5f363ef
feat(tracker-resources): drag-controller — body drag transitions
MichaelUray May 15, 2026
1a84628
feat(tracker-resources): drag-controller — resize-left/right with cla…
MichaelUray May 15, 2026
cd3100b
feat(tracker-resources): scheduler.descendantsWithDates (cycle-safe BFS)
MichaelUray May 15, 2026
456157f
feat(tracker): i18n keys for Gantt edit-mode (set-start-date + 5 toas…
MichaelUray May 15, 2026
ad50211
feat(tracker-resources): local Set-start-date action for Gantt menu
MichaelUray May 15, 2026
7fcdd8d
feat(tracker-resources): GanttView activeDrag store + per-issue edit …
MichaelUray May 15, 2026
9d7ae72
feat(tracker-resources): GanttBar edge-detect + resize-handle hit areas
MichaelUray May 15, 2026
e70801a
feat(tracker-resources): GanttCanvas forwards bar events + mounts res…
MichaelUray May 15, 2026
631accc
feat(tracker-resources): wire drag reducer + atomic commitDrag in Gan…
MichaelUray May 15, 2026
7ea1282
feat(tracker-resources): active-drag preview geometry + tint on GanttBar
MichaelUray May 15, 2026
0eba227
feat(tracker-resources): right-click context menu on bar + sidebar row
MichaelUray May 15, 2026
18e0ac2
feat(tracker-resources): keyboard Tab cycle + arrow-shift for Gantt bars
MichaelUray May 15, 2026
9b8e3da
feat(tracker-resources): dim non-active rows during drag (spotlight f…
MichaelUray May 15, 2026
f82c534
feat(tracker-resources): drag-from-unscheduled — drop on canvas sets …
MichaelUray May 15, 2026
c4fd5b0
fix(tracker-resources): allow direct idle → drag in reducer
MichaelUray May 15, 2026
a79ef05
feat(tracker-resources): slim Gantt context menu + fix pan-grip colli…
MichaelUray May 15, 2026
5887db0
fix(tracker-resources): Gantt menu — deny-list + restore Open/Parent/…
MichaelUray May 15, 2026
778c31f
feat(tracker): Gantt Hierarchy submenu + EditIssue parent + header su…
MichaelUray May 15, 2026
e0d9db0
feat(tracker-resources): Gantt select-first drag + confirm popup + su…
MichaelUray May 15, 2026
59097e9
fix(tracker-resources): Gantt parent-drag truth source + canvasX offs…
MichaelUray May 15, 2026
ba40985
chore(tracker-resources): Gantt polish — drop stale CSS, i18n ARIA la…
MichaelUray May 15, 2026
9c93a08
chore(tracker-resources): remove internal review markers from inline …
MichaelUray May 15, 2026
b64ac3b
fix(tracker-resources): resolve eslint errors in gantt edit components
MichaelUray Jul 3, 2026
69f295f
chore(tracker-resources): apply prettier formatting after develop merge
MichaelUray Jul 3, 2026
4e1b0f9
i18n(tracker-assets): sync ru.json keys with en.json (gantt pr3a)
MichaelUray Jul 3, 2026
1737b25
fix(tracker-resources): Gantt bar selection — cursor, visual, single-…
MichaelUray May 15, 2026
06cfec0
fix(tracker-resources): Gantt bar selection — reactive prop helpers
MichaelUray May 15, 2026
39ece57
feat(tracker-resources): Gantt sidebar — milestone single-click opens…
MichaelUray May 15, 2026
18a9c5f
fix(tracker-resources): Gantt openMilestone resolves full Milestone b…
MichaelUray May 15, 2026
9eec054
feat(tracker-resources): Gantt PR3.3 — milestone bars editable with c…
MichaelUray May 15, 2026
a6dffdf
feat(tracker-resources): Gantt pan from unselected bars
MichaelUray May 15, 2026
ea1da5e
feat(tracker): add 13 i18n keys for Gantt dependencies (PR4a)
MichaelUray May 15, 2026
c2d56c5
feat(model-tracker): add ganttShowPredecessors ViewOption (PR4a)
MichaelUray May 15, 2026
b4eba40
feat(tracker-resources): predecessor-format helpers (PR4a)
MichaelUray May 15, 2026
6149ff8
feat(tracker-resources): scheduler.wouldCreateCycle (PR4a)
MichaelUray May 15, 2026
a5c030b
feat(tracker-resources): dependency-router endpoints (PR4a)
MichaelUray May 15, 2026
8f86e87
feat(tracker-resources): dependency-router bezier + arrowhead (PR4a)
MichaelUray May 15, 2026
437d1b4
feat(tracker-resources): dependency-router connectedIssueIds (PR4a)
MichaelUray May 15, 2026
f5fe635
feat(tracker-resources): DragState + DragEvent connector variants (PR4a)
MichaelUray May 15, 2026
b4e5009
feat(tracker-resources): drag-controller connector state transitions …
MichaelUray May 15, 2026
2811809
fix(tracker-resources): drag-controller no stale target leak (PR4a)
MichaelUray May 15, 2026
33e7d48
feat(tracker-resources): GanttConnectorDot visual affordance (PR4a)
MichaelUray May 15, 2026
13977d9
feat(tracker-resources): GanttDependencyArrow bezier + lag pill (PR4a)
MichaelUray May 15, 2026
c50c141
feat(tracker-resources): GanttDependencyLayer overlay (PR4a)
MichaelUray May 15, 2026
5f05e90
feat(tracker-resources): DependencyEditor popup (PR4a)
MichaelUray May 15, 2026
a2a5a2c
fix(tracker-resources): GanttDependencyLayer use stroke-dasharray:0 n…
MichaelUray May 15, 2026
2abb02b
feat(tracker-resources): GanttBar hover state + connector dot mount (…
MichaelUray May 15, 2026
26e926e
fix(tracker-resources): GanttBar isMilestoneSummary use dragTarget (P…
MichaelUray May 15, 2026
12dc202
feat(tracker-resources): GanttCanvas mounts DependencyLayer + barRect…
MichaelUray May 15, 2026
ad90cd2
feat(tracker-resources): GanttSidebar predecessor column (PR4a)
MichaelUray May 15, 2026
38ce0c5
feat(tracker-resources): GanttView dependency wiring (PR4a)
MichaelUray May 15, 2026
f0a9502
fix(tracker): de-duplicate 13 PR4a i18n keys from base namespace
MichaelUray May 15, 2026
fbabcc5
fix(tracker-resources): guard relationQuery against empty visibleIssu…
MichaelUray May 15, 2026
e735e5e
fix(tracker-resources): drop $or relationQuery, filter client-side (P…
MichaelUray May 15, 2026
967fdb9
fix(tracker-resources): harden Gantt dependency init and bar clicks
MichaelUray May 15, 2026
11f4bb0
fix(tracker-resources): pan from Gantt bars on drag
MichaelUray May 15, 2026
64c9cef
fix(tracker-resources): restore selected Gantt bar editing
MichaelUray May 15, 2026
2e85237
fix(front): clean startup console noise
MichaelUray May 15, 2026
6c710c4
fix(notification-resources): return ArrayBuffer-backed push key
MichaelUray May 15, 2026
d056097
fix(tracker-resources): stabilize gantt viewport and connectors
MichaelUray May 15, 2026
f6fa3c4
feat(tracker-resources): adaptive Gantt time-scale + optimistic depen…
MichaelUray May 15, 2026
5634091
fix(tracker-resources): inline gantt live-bezier reactive deps
MichaelUray May 15, 2026
dbee073
feat(tracker-resources): PR4b cascade simulation types
MichaelUray May 15, 2026
00c1183
feat(tracker-resources): PR4b detectCycle DFS helper
MichaelUray May 15, 2026
87b898b
feat(tracker-resources): PR4b addScheduleDays Phase-2 hook
MichaelUray May 15, 2026
cf439bd
fix(tracker-resources): PR4b test file license header + drop dead DAY…
MichaelUray May 15, 2026
44cc8b6
feat(tracker-resources): PR4b simulateCascade FS push + no-cascade
MichaelUray May 15, 2026
6f917cf
feat(tracker-resources): PR4b cascade SS/FF/SF anchor model
MichaelUray May 15, 2026
06d2e70
feat(tracker-resources): PR4b cascade pull-predecessor
MichaelUray May 15, 2026
d3f93f4
feat(tracker-resources): PR4b cascade parent-drag + merge tests
MichaelUray May 15, 2026
d2f3ccd
feat(tracker-resources): PR4b cascade chain + iteration-overflow tests
MichaelUray May 15, 2026
a6f4e21
feat(tracker-resources): PR4b cascade cycle bailout test
MichaelUray May 15, 2026
0b17bd0
feat(tracker-resources): PR4b cascade permission-denied test
MichaelUray May 15, 2026
df6d72d
feat(tracker-resources): PR4b cascade hidden-issue scope test
MichaelUray May 15, 2026
32bb53b
feat(tracker-resources): PR4b cascade i18n keys (en)
MichaelUray May 15, 2026
e29db68
feat(tracker-resources): PR4b ConfirmCascadePopup mini-timeline
MichaelUray May 15, 2026
c03421f
docs(tracker-resources): PR4b scheduler comment polish
MichaelUray May 15, 2026
69609c9
feat(tracker-resources): PR4b commitWithCascade body-drag wiring + si…
MichaelUray May 15, 2026
d25cd9a
fix(tracker-resources): PR4b keep drag preview alive while cascade po…
MichaelUray May 15, 2026
c4381c8
feat(tracker-resources): show Gantt IssueRelations in issue editor
MichaelUray May 15, 2026
c030509
fix(tracker-resources): always show Dependencies section + ganttDebug…
MichaelUray May 15, 2026
c24582e
feat(tracker-resources): PR4b popup polish + legacy confirm parity
MichaelUray May 15, 2026
62cca12
fix(tracker-resources): PR4b svelte-check + type-narrowing fixes
MichaelUray May 15, 2026
8f2d0fa
fix(tracker-resources): PR4b permission check before no-cascade return
MichaelUray May 15, 2026
6484c10
feat(tracker-resources): PR5 critical-path types
MichaelUray May 15, 2026
b4a4574
feat(tracker-resources): PR5 critical-path scaffold + cycle bailout
MichaelUray May 15, 2026
1ccb5b5
feat(tracker-resources): PR5 i18n keys (en)
MichaelUray May 15, 2026
d6363f4
feat(tracker): PR5 ganttCriticalPath + ganttSlackColumn view options
MichaelUray May 15, 2026
67dc0fd
feat(tracker-resources): PR5 critical-path UI wiring
MichaelUray May 15, 2026
5a0a838
feat(tracker-resources): PR6 export + keyboard shortcuts + DE i18n
MichaelUray May 15, 2026
0651c50
fix(tracker-resources): PR5 critical-path topoSort guard + destroy timer
MichaelUray May 15, 2026
b27ffe9
fix(tracker-resources): PR5 violated bars paint red
MichaelUray May 15, 2026
9bb5de9
fix(tracker-resources): connector dot above arrows + target drop indi…
MichaelUray May 15, 2026
18cf64e
feat(tracker): readable Dependencies panel + IssueRelation activity p…
MichaelUray May 15, 2026
6f379db
refactor(tracker-resources): collapse connector-drag to a single even…
MichaelUray May 15, 2026
2abb7d8
refactor(tracker-resources): drop canvas-level connector delegation
MichaelUray May 15, 2026
ecb338f
fix(tracker-resources): deps panel — drop ignore, default to Issues t…
MichaelUray May 15, 2026
dfc91d9
fix(tracker): scope dependency picker to current project
MichaelUray May 15, 2026
23b0e86
fix(tracker): dependency picker — wrap ObjectPopup so items render
MichaelUray May 15, 2026
69de79a
feat(tracker): label LinkExistingSubIssue button + DE translation
MichaelUray May 15, 2026
2beed04
feat(tracker): unified hierarchy add chooser + resizable pickers
MichaelUray May 15, 2026
db0d1bb
feat(tracker): dependency direction chooser — predecessor + successor
MichaelUray May 15, 2026
ee5ecee
fix(tracker): cycle check uses project-wide relations + neutralize re…
MichaelUray May 15, 2026
45d3240
fix(tracker-resources): confirm dialog before dependency removal
MichaelUray May 15, 2026
b04935b
fix(love-resources): handle nullish content-type in strict-boolean check
MichaelUray Jul 3, 2026
9fe0b25
fix(tracker-resources): resolve eslint errors in gantt dependency/cas…
MichaelUray Jul 3, 2026
c80fcf2
chore(tracker-resources): apply prettier + eslint --fix formatting af…
MichaelUray Jul 3, 2026
022618b
fix(tracker-resources): repair GanttView imports and drop orphaned mo…
MichaelUray Jul 3, 2026
5628afb
test(sanity): adapt sub-issue page-objects to HierarchyAddPopup chooser
MichaelUray Jul 4, 2026
c9481fe
test(tracker): make buttonEstimation locator sibling-based, not posit…
MichaelUray Jul 4, 2026
2a865aa
chore(tracker): reconcile i18n + Gantt sources after develop rebase
MichaelUray Jul 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion models/tracker/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,9 @@ function defineFilters (builder: Builder): void {
key: 'milestone',
component: view.component.ObjectFilter,
showNested: false
}
},
'startDate',
'dueDate'
],
ignoreKeys: ['number', 'estimation', 'attachedTo'],
getVisibleFilters: tracker.function.GetVisibleFilters
Expand Down
9 changes: 9 additions & 0 deletions models/tracker/src/presenters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ export function definePresenters (builder: Builder): void {
presenter: tracker.component.NotificationIssuePresenter
})

//
// IssueRelation — single-line "FS +Nd → OSTRO-29 Title" presenter so
// the activity feed shows which dependency was added or removed
// (instead of the generic "Dependency" class label).
//
builder.mixin(tracker.class.IssueRelation, core.class.Class, view.mixin.ObjectPresenter, {
presenter: tracker.component.IssueRelationPresenter
})

builder.mixin(tracker.class.Issue, core.class.Class, view.mixin.PreviewPresenter, {
presenter: tracker.component.IssuePreview
})
Expand Down
127 changes: 127 additions & 0 deletions models/tracker/src/viewlets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,105 @@ export function issueConfig (
]
}

export function ganttViewOptions (): ViewOptionsModel {
// PR 2 ships a minimal read-only Gantt. Group-by + Show-colors are
// intentionally NOT advertised — the canvas does not honour them yet.
// The two sidebar-column toggles below ARE wired up to GanttSidebar.
return {
groupBy: [],
orderBy: [
['startDate', SortingOrder.Ascending],
['rank', SortingOrder.Ascending],
['dueDate', SortingOrder.Ascending]
],
other: [
{
key: 'ganttShowIssueCode',
type: 'toggle',
defaultValue: false,
actionTarget: 'display',
label: tracker.string.GanttShowIssueCode
},
{
key: 'ganttShowTitle',
type: 'toggle',
defaultValue: true,
actionTarget: 'display',
label: tracker.string.GanttShowTitle
},
{
key: 'ganttShowStatus',
type: 'toggle',
defaultValue: true,
actionTarget: 'display',
label: tracker.string.GanttShowStatus
},
{
// Default-on safety prompt: when set, dragging an issue's bar to a
// new date range shows a confirm dialog before writing the change.
// User feedback 2026-05-11: easy to misclick a bar while panning,
// and a one-click confirm prevents accidental schedule edits.
key: 'ganttConfirmMove',
type: 'toggle',
defaultValue: true,
actionTarget: 'display',
label: tracker.string.GanttConfirmMove
},
{
// Same idea but for left/right resize handles.
key: 'ganttConfirmResize',
type: 'toggle',
defaultValue: true,
actionTarget: 'display',
label: tracker.string.GanttConfirmResize
},
{
// PR4a: sidebar column showing predecessor notation (e.g. "12FS+2d").
// Hidden by default so existing users don't see a new column appear.
// Toggling on requires no migration — the column is purely derived
// from the IssueRelation collection that already exists from PR1.
key: 'ganttShowPredecessors',
type: 'toggle',
defaultValue: false,
actionTarget: 'display',
label: tracker.string.GanttShowPredecessors
},
{
// PR5: critical-path overlay toggle. When on, critical bars get a red
// border and fill overlay; critical relations get red arrows; non-critical
// bars show a grey slack glyph.
key: 'ganttCriticalPath',
type: 'toggle',
defaultValue: false,
actionTarget: 'display',
label: tracker.string.CriticalPathOn
},
{
// PR5: slack column in the sidebar. Shows numeric slack days or "CP" badge
// for critical issues. Requires ganttCriticalPath to be meaningful.
key: 'ganttSlackColumn',
type: 'toggle',
defaultValue: false,
actionTarget: 'display',
label: tracker.string.SlackColumn
}
]
}
}

export function ganttConfig (): BuildModelKey[] {
// Minimal config — Gantt drives its own column layout.
return [
{
key: '',
presenter: tracker.component.PriorityEditor,
label: tracker.string.Priority,
props: { kind: 'list', size: 'small' }
},
{ key: '', presenter: tracker.component.IssuePresenter, label: tracker.string.Issue }
]
}

export function defineViewlets (builder: Builder): void {
builder.createDoc(
view.class.ViewletDescriptor,
Expand All @@ -224,6 +323,17 @@ export function defineViewlets (builder: Builder): void {
tracker.viewlet.Kanban
)

builder.createDoc(
view.class.ViewletDescriptor,
core.space.Model,
{
label: tracker.string.Gantt,
icon: tracker.icon.Gantt,
component: tracker.component.GanttView
},
tracker.viewlet.Gantt
)

builder.createDoc(
view.class.Viewlet,
core.space.Model,
Expand Down Expand Up @@ -501,6 +611,23 @@ export function defineViewlets (builder: Builder): void {
tracker.viewlet.IssueKanban
)

// Gantt is registered AFTER List + Kanban so List remains the default
// viewlet (ViewletSelector falls back to viewlets[0] when no preference
// is saved). Putting Gantt last avoids surprising users with an empty
// canvas on first visit.
builder.createDoc(
view.class.Viewlet,
core.space.Model,
{
attachTo: tracker.class.Issue,
descriptor: tracker.viewlet.Gantt,
viewOptions: ganttViewOptions(),
configOptions: { strict: true, hiddenKeys: ['title'] },
config: ganttConfig()
},
tracker.viewlet.IssueGantt
)

const componentListViewOptions: ViewOptionsModel = {
groupBy: ['lead', 'createdBy', 'modifiedBy'],
orderBy: [
Expand Down
3 changes: 2 additions & 1 deletion packages/presentation/src/components/DocPopup.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
export let placeholder: IntlString = presentation.string.Search
export let selectedObjects: Ref<Doc>[] = []
export let shadows: boolean = true
export let width: 'medium' | 'large' | 'full' | 'auto' = 'medium'
export let width: 'medium' | 'large' | 'full' | 'auto' | 'resizable' = 'medium'
export let size: 'small' | 'medium' | 'large' = 'large'

export let noSearchField: boolean = false
Expand Down Expand Up @@ -222,6 +222,7 @@
class:full-width={width === 'full'}
class:plainContainer={!shadows}
class:width-40={width === 'large'}
class:width-resizable={width === 'resizable'}
class:auto={width === 'auto'}
class:embedded
on:keydown={onKeydown}
Expand Down
2 changes: 1 addition & 1 deletion packages/presentation/src/components/ObjectPopup.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
export let selectedObjects: Ref<Doc>[] = []
export let ignoreObjects: Ref<Doc>[] = []
export let shadows: boolean = true
export let width: 'medium' | 'large' | 'full' | 'auto' = 'medium'
export let width: 'medium' | 'large' | 'full' | 'auto' | 'resizable' = 'medium'
export let size: 'small' | 'medium' | 'large' = 'large'

export let searchMode: 'field' | 'fulltext' | 'disabled' | 'spotlight' = 'field'
Expand Down
13 changes: 11 additions & 2 deletions packages/presentation/src/sound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { getClient } from '.'
import notification from '@hcengineering/notification'

const sounds = new Map<Asset, AudioBuffer>()
const context = new AudioContext()
let context: AudioContext | undefined

function getAudioContext (): AudioContext {
context ??= new AudioContext()
return context
}

export async function isNotificationAllowed (_class?: Ref<Class<Doc>>): Promise<boolean> {
if (_class === undefined) return false
Expand All @@ -24,7 +29,7 @@ export async function prepareSound (key: string): Promise<void> {
const soundUrl = getMetadata(key as Asset) as string
const rawAudio = await fetch(soundUrl)
const rawBuffer = await rawAudio.arrayBuffer()
const decodedBuffer = await context.decodeAudioData(rawBuffer)
const decodedBuffer = await getAudioContext().decodeAudioData(rawBuffer)

sounds.set(key as Asset, decodedBuffer)
} catch (err) {
Expand All @@ -46,6 +51,10 @@ export async function playSound (soundKey: string, loop = false): Promise<(() =>
}

try {
const context = getAudioContext()
if (context.state === 'suspended') {
await context.resume()
}
const audio = context.createBufferSource()
audio.buffer = sound
audio.loop = loop
Expand Down
12 changes: 11 additions & 1 deletion packages/theme/styles/popups.scss
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,17 @@
width: 100%;
max-width: 100%;
}

&.width-resizable {
width: 48rem;
max-width: min(96vw, 80rem);
min-width: 28rem;
height: 36rem;
max-height: min(96vh, 60rem);
min-height: 16rem;
resize: both;
overflow: hidden;
}

&.maxHeight { height: 22rem; }
&.autoHeight {
max-height: calc(100vh - 2rem);
Expand Down
4 changes: 4 additions & 0 deletions plugins/love-resources/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,10 @@ async function checkRecordAvailable (): Promise<void> {
}, 500)
} else if (endpoint !== '') {
const res = await fetch(concatLink(endpoint, '/checkRecordAvailable'))
if (!res.ok || !(res.headers.get('content-type')?.includes('application/json') ?? false)) {
isRecordingAvailable.set(false)
return
}
const result = await res.json()
isRecordingAvailable.set(result)
} else {
Expand Down
46 changes: 27 additions & 19 deletions plugins/notification-resources/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ import { getObjectLinkId, parseLinkId } from '@hcengineering/view-resources'
import type { LocationData } from '@hcengineering/workbench'
import { get, writable } from 'svelte/store'

import { isDesktopClient } from './desktop'
import { InboxNotificationsClientImpl } from './inboxNotificationsClient'
import { type InboxData, type InboxNotificationsFilter } from './types'

Expand Down Expand Up @@ -690,10 +689,6 @@ export const pushAllowed = writable<boolean>(false)

export async function checkPermission (value: boolean): Promise<boolean> {
if (!value) return true
if (isDesktopClient()) {
pushAllowed.set(false)
return false
}
if ('serviceWorker' in navigator && 'PushManager' in window) {
try {
const loc = getCurrentLocation()
Expand Down Expand Up @@ -730,25 +725,20 @@ function addWorkerListener (): void {
}

export function pushAvailable (): boolean {
if (isDesktopClient()) return false
const publicKey = getPushPublicKey()
const publicKey = getMetadata(notification.metadata.PushPublicKey)
return (
'serviceWorker' in navigator &&
'PushManager' in window &&
publicKey !== undefined &&
isValidPushPublicKey(publicKey) &&
'Notification' in window &&
Notification.permission !== 'denied'
)
}

export async function subscribePush (): Promise<boolean> {
if (isDesktopClient()) {
pushAllowed.set(false)
return false
}
const client = getClient()
const publicKey = getPushPublicKey()
if ('serviceWorker' in navigator && 'PushManager' in window && publicKey !== undefined) {
const publicKey = getMetadata(notification.metadata.PushPublicKey)
if ('serviceWorker' in navigator && 'PushManager' in window && isValidPushPublicKey(publicKey)) {
try {
const loc = getCurrentLocation()
let registration = await navigator.serviceWorker.getRegistration(`/${loc.path[0]}/${loc.path[1]}`)
Expand All @@ -763,7 +753,7 @@ export async function subscribePush (): Promise<boolean> {
if (current == null) {
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: publicKey
applicationServerKey: urlBase64ToUint8Array(publicKey)
})
await client.createDoc(notification.class.PushSubscription, core.space.Workspace, {
user: getCurrentAccount().uuid,
Expand Down Expand Up @@ -802,10 +792,28 @@ export async function subscribePush (): Promise<boolean> {
return false
}

function getPushPublicKey (): string | undefined {
const publicKey = getMetadata(notification.metadata.PushPublicKey)
if (publicKey === undefined) return undefined
return publicKey.trim() !== '' ? publicKey : undefined
function isValidPushPublicKey (publicKey: string | undefined): publicKey is string {
if (publicKey === undefined || publicKey.trim() === '') return false

try {
const key = urlBase64ToUint8Array(publicKey)
return key.length === 65 && key[0] === 4
} catch {
return false
}
}

function urlBase64ToUint8Array (value: string): Uint8Array<ArrayBuffer> {
const padding = '='.repeat((4 - (value.length % 4)) % 4)
const base64 = `${value}${padding}`.replace(/-/g, '+').replace(/_/g, '/')
const rawData = atob(base64)
const outputArray = new Uint8Array(new ArrayBuffer(rawData.length))

for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i)
}

return outputArray
}

async function cleanTag (_id: Ref<Doc>): Promise<void> {
Expand Down
21 changes: 20 additions & 1 deletion plugins/tracker-assets/lang/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,26 @@
"UnsetParentIssue": "Odebrat nadřazený úkol",
"ForbidCreateProjectPermission": "Zakázat vytvoření projektu",
"ForbidCreateProjectPermissionDescription": "Zakazuje uživatelům vytvářet nové projekty",
"AllowCreatingIssues": "Povolit vytváření úkolů"
"AllowCreatingIssues": "Povolit vytváření úkolů",
"Day": "Day",
"Week": "Week",
"Month": "Month",
"Quarter": "Quarter",
"Gantt": "Gantt",
"GanttShowIssueCode": "Show issue code",
"GanttShowTitle": "Show title",
"GanttShowStatus": "Show status",
"GanttToday": "Today",
"GanttJumpToStart": "Jump to start",
"GanttJumpToEnd": "Jump to end",
"GanttJumpToDate": "Jump to date",
"GanttPreviousPeriod": "Previous period",
"GanttNextPeriod": "Next period",
"GanttScrollLeftToBar": "Scroll left to bar",
"GanttScrollRightToBar": "Scroll right to bar",
"GanttExpand": "Expand",
"GanttCollapse": "Collapse"

},
"status": {}
}
Loading