@genesislcap/pbc-notify-ui 15.24.0 → 15.24.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -479,27 +479,6 @@
479
479
  }
480
480
  ]
481
481
  },
482
- {
483
- "kind": "javascript-module",
484
- "path": "src/styles/scrollbar.styles.ts",
485
- "declarations": [
486
- {
487
- "kind": "variable",
488
- "name": "scrollbarStyles",
489
- "default": "css`\n ::-webkit-scrollbar {\n width: calc((var(--base-height-multiplier) + var(--design-unit)) * 1px);\n }\n\n ::-webkit-scrollbar-track {\n background: var(--neutral-layer-1);\n }\n\n ::-webkit-scrollbar-thumb {\n background: var(--neutral-fill-rest);\n }\n`"
490
- }
491
- ],
492
- "exports": [
493
- {
494
- "kind": "js",
495
- "name": "scrollbarStyles",
496
- "declaration": {
497
- "name": "scrollbarStyles",
498
- "module": "src/styles/scrollbar.styles.ts"
499
- }
500
- }
501
- ]
502
- },
503
482
  {
504
483
  "kind": "javascript-module",
505
484
  "path": "src/utils/eventDetail.ts",
@@ -821,6 +800,27 @@
821
800
  }
822
801
  ]
823
802
  },
803
+ {
804
+ "kind": "javascript-module",
805
+ "path": "src/styles/scrollbar.styles.ts",
806
+ "declarations": [
807
+ {
808
+ "kind": "variable",
809
+ "name": "scrollbarStyles",
810
+ "default": "css`\n ::-webkit-scrollbar {\n width: calc((var(--base-height-multiplier) + var(--design-unit)) * 1px);\n }\n\n ::-webkit-scrollbar-track {\n background: var(--neutral-layer-1);\n }\n\n ::-webkit-scrollbar-thumb {\n background: var(--neutral-fill-rest);\n }\n`"
811
+ }
812
+ ],
813
+ "exports": [
814
+ {
815
+ "kind": "js",
816
+ "name": "scrollbarStyles",
817
+ "declaration": {
818
+ "name": "scrollbarStyles",
819
+ "module": "src/styles/scrollbar.styles.ts"
820
+ }
821
+ }
822
+ ]
823
+ },
824
824
  {
825
825
  "kind": "javascript-module",
826
826
  "path": "src/components/foundation-inbox/inbox.styles.ts",
@@ -2041,54 +2041,19 @@
2041
2041
  },
2042
2042
  {
2043
2043
  "kind": "javascript-module",
2044
- "path": "src/components/foundation-sounds/foundation-sounds-panel.styles.ts",
2045
- "declarations": [
2046
- {
2047
- "kind": "variable",
2048
- "name": "FoundationSoundsPanelStyles",
2049
- "default": "css`\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n width: 100%;\n }\n\n .sounds-controls {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n gap: 12px;\n padding: calc(var(--design-unit) * 3px);\n box-sizing: border-box;\n }\n\n .sounds-help-disclosure {\n flex: 0 0 auto;\n }\n\n .sounds-help-toggle {\n margin-inline-start: calc(var(--design-unit) * 1px);\n }\n\n .sounds-help-toggle::before {\n content: '+';\n }\n\n .sounds-help-disclosure[expanded] .sounds-help-toggle::before {\n content: '−';\n }\n\n .sounds-help {\n margin: 0;\n font-size: var(--type-ramp-minus-1-font-size);\n color: var(--neutral-foreground-hint);\n text-align: left;\n }\n\n .volume-row {\n display: flex;\n align-items: center;\n flex: 0 0 auto;\n gap: calc(var(--design-unit) * 2px);\n min-width: 0;\n }\n\n .volume-icon {\n flex: 0 0 auto;\n }\n\n .volume-label {\n flex: 0 0 auto;\n font-size: var(--type-ramp-minus-1-font-size);\n color: var(--neutral-foreground-hint);\n }\n\n .volume-slider {\n flex: 1 1 auto;\n min-width: 0;\n }\n\n .volume-percent {\n flex: 0 0 auto;\n min-width: 3ch;\n text-align: end;\n font-size: var(--type-ramp-minus-1-font-size);\n color: var(--neutral-foreground-hint);\n }\n\n .mute-all {\n flex: 0 0 auto;\n margin: 0;\n }\n\n .sound-rules-panel {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n }\n\n .sound-rules {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .sound-rule {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);\n border-radius: calc(var(--control-corner-radius) * 1px);\n\n /* Keep absolute listboxes from being clipped by the card itself. */\n overflow: visible;\n }\n\n .sound-rule-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-weight: 700;\n font-size: var(--type-ramp-minus-1-font-size);\n }\n\n .sound-rule-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n }\n\n .sound-rule-label {\n display: flex;\n flex-direction: column;\n gap: 4px;\n font-size: var(--type-ramp-minus-1-font-size);\n color: var(--neutral-foreground-hint);\n }\n\n .pattern-input,\n .match-mode-select,\n .rule-select,\n .sound-file-input {\n width: 100%;\n }\n\n /*\n * Anchor the listbox to the select host and use position:fixed so it escapes\n * .sound-rules-panel overflow:auto (and the rule card). Each select sets a\n * unique --sounds-select-anchor / anchor-name via inline style.\n * !important beats FAST's internal absolute top/bottom for [open] selects.\n */\n .match-mode-select[open]::part(listbox),\n .rule-select[open]::part(listbox) {\n position: fixed !important;\n /* stylelint-disable-next-line property-no-unknown -- CSS anchor positioning */\n position-anchor: var(--sounds-select-anchor);\n inset: auto !important;\n top: anchor(bottom) !important;\n left: anchor(left) !important;\n right: anchor(right) !important;\n bottom: auto !important;\n width: auto !important;\n margin-top: calc(var(--design-unit) * 1px);\n z-index: 10000;\n max-height: min(240px, 40vh);\n overflow-x: hidden;\n overflow-y: auto;\n box-shadow: 0 4px 16px rgb(0 0 0 / 24%);\n }\n\n .match-mode-select[open][position='above']::part(listbox),\n .rule-select[open][position='above']::part(listbox) {\n top: auto !important;\n bottom: anchor(top) !important;\n margin-top: 0;\n margin-bottom: calc(var(--design-unit) * 1px);\n }\n\n .sound-file-row {\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .sound-file-row .sound-file-input {\n flex: 1;\n min-width: 0;\n }\n\n .choose-sound {\n cursor: pointer;\n }\n\n .sound-rules-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex: 0 0 auto;\n gap: 8px;\n }\n\n .rule-count {\n font-size: var(--type-ramp-minus-1-font-size);\n color: var(--neutral-foreground-hint);\n }\n\n .file-input {\n display: none;\n }\n\n ${scrollbarStyles}\n`"
2050
- }
2051
- ],
2052
- "exports": [
2053
- {
2054
- "kind": "js",
2055
- "name": "FoundationSoundsPanelStyles",
2056
- "declaration": {
2057
- "name": "FoundationSoundsPanelStyles",
2058
- "module": "src/components/foundation-sounds/foundation-sounds-panel.styles.ts"
2059
- }
2060
- }
2061
- ]
2062
- },
2063
- {
2064
- "kind": "javascript-module",
2065
- "path": "src/components/foundation-sounds/foundation-sounds-panel.template.ts",
2044
+ "path": "src/components/foundation-notification-dashboard/alert-sound-attachment.ts",
2066
2045
  "declarations": [
2067
2046
  {
2068
2047
  "kind": "variable",
2069
- "name": "FoundationSoundsPanelTemplate",
2070
- "default": "html<FoundationSoundsPanel>`\n <div class=\"sounds-controls\" part=\"controls\">\n <input\n ${ref('fileInput')}\n class=\"file-input\"\n type=\"file\"\n accept=\"audio/*\"\n @change=${(x, c) => x.onFileSelected(c.event)}\n />\n <rapid-disclosure class=\"sounds-help-disclosure\" appearance=\"lightweight\">\n <span slot=\"title\">\n Sound Alerts Information\n <span class=\"sounds-help-toggle\" aria-hidden=\"true\"></span>\n </span>\n <p class=\"sounds-help\">\n Add up to ${(x) => x.maxRules} sounds.\n <br />\n Match text in MESSAGE or HEADER (a word or phrase), or a notification rule (including rules\n created when you subscribe to a template).\n <br />\n The first matching rule is played.\n </p>\n </rapid-disclosure>\n <div class=\"volume-row\">\n <rapid-icon\n class=\"volume-icon\"\n name=${(x) => (x.muted || x.volumePercent === 0 ? 'volume-xmark' : 'volume-high')}\n ></rapid-icon>\n <span class=\"volume-label\">Volume</span>\n <rapid-slider\n class=\"volume-slider\"\n min=\"0\"\n max=\"100\"\n step=\"1\"\n :value=${(x) => String(x.volumePercent)}\n @change=${(x, c) => x.onVolumeChange(c.event)}\n ></rapid-slider>\n <span class=\"volume-percent\">${(x) => `${x.volumePercent}%`}</span>\n <rapid-button\n class=\"mute-all\"\n appearance=\"lightweight\"\n title=${(x) => (x.muted ? 'Unmute alert sounds' : 'Mute all alert sounds')}\n @click=${(x) => x.toggleMute()}\n >\n ${(x) => (x.muted ? 'Unmute' : 'Mute all')}\n </rapid-button>\n </div>\n <div class=\"sound-rules-panel\">\n <div class=\"sound-rules\">\n ${repeat(\n (x) => x.rules,\n html<AlertSoundRuleView, FoundationSoundsPanel>`\n <div class=\"sound-rule\" data-rule-index=${(x) => x.index}>\n <div class=\"sound-rule-header\">\n <span>Rule ${(x) => x.index + 1}</span>\n <div class=\"sound-rule-actions\">\n <rapid-button\n class=\"mute-rule\"\n appearance=\"stealth\"\n title=${(x) => (x.muted ? 'Unmute this rule' : 'Mute this rule')}\n @click=${(x, c) => c.parent.toggleRuleMute(x.index)}\n >\n <rapid-icon\n name=${(x) => (x.muted ? 'volume-xmark' : 'volume-high')}\n ></rapid-icon>\n </rapid-button>\n <rapid-button\n class=\"remove-rule\"\n appearance=\"stealth\"\n title=${(_, c) => (c.parent.canRemoveRule ? 'Remove rule' : 'Reset rule')}\n @click=${(x, c) => c.parent.removeRule(x.index)}\n >\n <rapid-icon name=\"trash\"></rapid-icon>\n </rapid-button>\n </div>\n </div>\n <label class=\"sound-rule-label\">\n Match by\n <rapid-select\n class=\"match-mode-select\"\n style=${(x) =>\n `anchor-name: --sound-match-${x.index}; --sounds-select-anchor: --sound-match-${x.index}`}\n :value=${(x) => x.matchMode}\n @change=${(x, c) => c.parent.onMatchModeChange(x.index, c.event)}\n >\n <rapid-option value=\"message\">MESSAGE text</rapid-option>\n <rapid-option value=\"header\">HEADER text</rapid-option>\n <rapid-option value=\"rule\">Notification rule</rapid-option>\n </rapid-select>\n </label>\n <label\n class=\"sound-rule-label\"\n style=${(x) => (x.matchMode === 'rule' ? 'display: none;' : '')}\n >\n ${(x) => (x.matchMode === 'header' ? 'HEADER text' : 'MESSAGE text')}\n <rapid-text-field\n class=\"pattern-input\"\n placeholder=${(x) =>\n x.matchMode === 'header' ? 'e.g. Price alert' : 'e.g. limit breached'}\n :value=${(x) => x.pattern}\n @input=${(x, c) => c.parent.onPatternInput(x.index, c.event)}\n ></rapid-text-field>\n </label>\n <label\n class=\"sound-rule-label\"\n style=${(x) => (x.matchMode === 'rule' ? '' : 'display: none;')}\n >\n Notification rule\n <rapid-select\n class=\"rule-select\"\n style=${(x) =>\n `anchor-name: --sound-rule-${x.index}; --sounds-select-anchor: --sound-rule-${x.index}`}\n :value=${(x) => x.templateId ?? ''}\n @change=${(x, c) => c.parent.onRuleChange(x.index, c.event)}\n >\n <options-datasource\n value-field=\"id\"\n label-field=\"name\"\n option-element=\"rapid-option\"\n :data=${(_, c) => c.parent.ruleSelectOptions}\n ></options-datasource>\n </rapid-select>\n </label>\n <label class=\"sound-rule-label\">\n Sound file\n <div class=\"sound-file-row\">\n <rapid-text-field\n class=\"sound-file-input\"\n readonly\n placeholder=\"No sound selected\"\n :value=${(x) => x.fileName ?? ''}\n title=${(x) => x.fileName ?? 'No sound selected'}\n >\n <rapid-icon\n slot=\"end\"\n class=\"choose-sound\"\n name=\"folder-open\"\n title=\"Choose alert sound\"\n @click=${(x, c) => {\n c.event.stopPropagation();\n return c.parent.openFilePicker(x.index);\n }}\n ></rapid-icon>\n </rapid-text-field>\n <rapid-button\n class=\"test-sound\"\n appearance=\"stealth\"\n title=\"Test play this sound\"\n ?disabled=${(x) => !x.hasSound}\n @click=${(x, c) => c.parent.testSound(x.index)}\n >\n <rapid-icon name=\"play\"></rapid-icon>\n </rapid-button>\n <rapid-button\n class=\"clear-sound\"\n appearance=\"stealth\"\n title=\"Clear sound file\"\n ?disabled=${(x) => !x.hasSound}\n @click=${(x, c) => c.parent.clearSound(x.index)}\n >\n <rapid-icon name=\"times\"></rapid-icon>\n </rapid-button>\n </div>\n </label>\n </div>\n `,\n )}\n </div>\n </div>\n <div class=\"sound-rules-footer\">\n <rapid-button\n class=\"add-rule\"\n appearance=\"lightweight\"\n title=\"Add sound rule\"\n ?disabled=${(x) => !x.canAddRule}\n @click=${(x) => x.addRule()}\n >\n <rapid-icon name=\"plus\"></rapid-icon>\n Add rule\n </rapid-button>\n <span class=\"rule-count\">${(x) => `${x.rules.length} / ${x.maxRules}`}</span>\n </div>\n </div>\n`"
2071
- }
2072
- ],
2073
- "exports": [
2074
- {
2075
- "kind": "js",
2076
- "name": "FoundationSoundsPanelTemplate",
2077
- "declaration": {
2078
- "name": "FoundationSoundsPanelTemplate",
2079
- "module": "src/components/foundation-sounds/foundation-sounds-panel.template.ts"
2080
- }
2081
- }
2082
- ]
2083
- },
2084
- {
2085
- "kind": "javascript-module",
2086
- "path": "src/components/foundation-sounds/foundation-sounds-panel.ts",
2087
- "declarations": [
2048
+ "name": "alertSoundAttachmentTemplate",
2049
+ "default": "html<AlertSoundAttachmentHost>`\n <div class=\"alert-sound\">\n <input\n ${ref('fileInput')}\n class=\"file-input\"\n type=\"file\"\n accept=\"audio/*\"\n @change=${(x, c) => x.onAlertSoundSelected(c.event)}\n />\n <label>Alert sound</label>\n <div class=\"alert-sound-row\">\n <span class=\"alert-sound-name\" title=${(x) => x.alertSoundFileName || ''}>\n ${(x) => x.alertSoundFileName || 'No sound attached'}\n </span>\n <rapid-button appearance=\"lightweight\" @click=${(x) => x.openAlertSoundPicker()}>\n ${(x) => (x.hasAlertSound ? 'Replace' : 'Attach')}\n </rapid-button>\n ${when(\n (x) => x.hasAlertSound,\n html<AlertSoundAttachmentHost>`\n <rapid-button appearance=\"lightweight\" @click=${(x) => x.testAttachedAlertSound()}>\n Test\n </rapid-button>\n <rapid-button appearance=\"lightweight\" @click=${(x) => x.clearAttachedAlertSound()}>\n Clear\n </rapid-button>\n `,\n )}\n </div>\n </div>\n`",
2050
+ "description": "Shared Attach/Replace/Test/Clear UI for rule and template dialogs.",
2051
+ "privacy": "public"
2052
+ },
2088
2053
  {
2089
- "kind": "class",
2090
- "description": "Configures alert sound rules in the inbox Sounds tab. Persists via the shared\nAlertSoundPlayer; playback is handled by layout-mounted\nFoundationSounds.",
2091
- "name": "FoundationSoundsPanel",
2054
+ "kind": "mixin",
2055
+ "description": "Mixin: pick / test / clear / load server sound + apply fields to submit payload.\n\nSubclasses must provide ruleService, isAlertSoundEditMode,\nalertSoundEntityId, and alertSoundCacheSyncMode.",
2056
+ "name": "AlertSoundAttachmentMixin",
2092
2057
  "members": [
2093
2058
  {
2094
2059
  "kind": "field",
@@ -2099,21 +2064,56 @@
2099
2064
  },
2100
2065
  {
2101
2066
  "kind": "field",
2102
- "name": "volumePercent",
2067
+ "name": "isAlertSoundEditMode",
2103
2068
  "type": {
2104
- "text": "number"
2069
+ "text": "boolean"
2105
2070
  },
2106
- "default": "100",
2107
- "description": "Global playback volume 0–100. @internal"
2071
+ "description": "True when editing an existing entity (clear should set CLEAR_ALERT_SOUND).",
2072
+ "readonly": true
2108
2073
  },
2109
2074
  {
2110
2075
  "kind": "field",
2111
- "name": "selectableRules",
2076
+ "name": "alertSoundEntityId",
2112
2077
  "type": {
2113
- "text": "AlertSoundSelectableRule[]"
2078
+ "text": "string | null"
2114
2079
  },
2115
- "default": "[]",
2116
- "description": "Notification rules from REQ_NOTIFICATION_RULE. @internal"
2080
+ "description": "DYNAMIC_RULE_ID of the entity being edited (null on create).\nUsed when alertSoundCacheSyncMode is `'entity'`.",
2081
+ "readonly": true
2082
+ },
2083
+ {
2084
+ "kind": "field",
2085
+ "name": "alertSoundCacheSyncMode",
2086
+ "type": {
2087
+ "text": "'entity' | 'all'"
2088
+ },
2089
+ "description": "`'entity'` — update/clear cache for alertSoundEntityId (rules).\n`'all'` — drop every cached server sound (templates; instance ids unknown).",
2090
+ "readonly": true
2091
+ },
2092
+ {
2093
+ "kind": "field",
2094
+ "name": "alertSoundFileName",
2095
+ "type": {
2096
+ "text": "string"
2097
+ },
2098
+ "default": "''",
2099
+ "description": "Display name of the attached / pending alert sound file."
2100
+ },
2101
+ {
2102
+ "kind": "field",
2103
+ "name": "alertSoundMimeType",
2104
+ "type": {
2105
+ "text": "string"
2106
+ },
2107
+ "default": "''"
2108
+ },
2109
+ {
2110
+ "kind": "field",
2111
+ "name": "hasAlertSound",
2112
+ "type": {
2113
+ "text": "boolean"
2114
+ },
2115
+ "default": "false",
2116
+ "description": "True when edit loaded an existing server sound (or user attached one)."
2117
2117
  },
2118
2118
  {
2119
2119
  "kind": "field",
@@ -2124,98 +2124,58 @@
2124
2124
  },
2125
2125
  {
2126
2126
  "kind": "field",
2127
- "name": "pendingRuleIndex",
2127
+ "name": "pendingAlertSoundData",
2128
2128
  "type": {
2129
- "text": "number | null"
2129
+ "text": "string | null"
2130
2130
  },
2131
- "privacy": "private",
2132
2131
  "default": "null"
2133
2132
  },
2134
2133
  {
2135
2134
  "kind": "field",
2136
- "name": "player",
2137
- "privacy": "private",
2138
- "readonly": true
2135
+ "name": "alertSoundDirty",
2136
+ "type": {
2137
+ "text": "boolean"
2138
+ },
2139
+ "default": "false",
2140
+ "description": "True when the user picked a new file this session (needs upload)."
2139
2141
  },
2140
2142
  {
2141
2143
  "kind": "field",
2142
- "name": "unsubscribePlayer",
2144
+ "name": "clearAlertSound",
2143
2145
  "type": {
2144
- "text": "(() => void) | undefined"
2146
+ "text": "boolean"
2145
2147
  },
2146
- "privacy": "private"
2148
+ "default": "false"
2147
2149
  },
2148
2150
  {
2149
2151
  "kind": "field",
2150
- "name": "ignoreSelectChanges",
2152
+ "name": "testAudio",
2151
2153
  "type": {
2152
- "text": "boolean"
2154
+ "text": "HTMLAudioElement | null"
2153
2155
  },
2154
- "privacy": "private",
2155
- "default": "false",
2156
- "description": "Suppresses select change events while options are rebuilt."
2156
+ "default": "null",
2157
+ "description": "In-progress Test playback; not private — mixin return type is exported."
2157
2158
  },
2158
2159
  {
2159
2160
  "kind": "method",
2160
- "name": "onMatchModeChange",
2161
- "return": {
2162
- "type": {
2163
- "text": "boolean"
2164
- }
2165
- },
2161
+ "name": "loadExistingAlertSound",
2166
2162
  "parameters": [
2167
2163
  {
2168
- "name": "index",
2169
- "type": {
2170
- "text": "number"
2171
- }
2172
- },
2173
- {
2174
- "name": "event",
2164
+ "name": "dynamicRuleId",
2175
2165
  "type": {
2176
- "text": "Event"
2166
+ "text": "string"
2177
2167
  }
2178
2168
  }
2179
2169
  ]
2180
2170
  },
2181
2171
  {
2182
2172
  "kind": "method",
2183
- "name": "onPatternInput",
2184
- "return": {
2185
- "type": {
2186
- "text": "boolean"
2187
- }
2188
- },
2189
- "parameters": [
2190
- {
2191
- "name": "index",
2192
- "type": {
2193
- "text": "number"
2194
- }
2195
- },
2196
- {
2197
- "name": "event",
2198
- "type": {
2199
- "text": "Event"
2200
- }
2201
- }
2202
- ]
2173
+ "name": "openAlertSoundPicker"
2203
2174
  },
2204
2175
  {
2205
2176
  "kind": "method",
2206
- "name": "onRuleChange",
2207
- "return": {
2208
- "type": {
2209
- "text": "boolean"
2210
- }
2211
- },
2177
+ "name": "onAlertSoundSelected",
2212
2178
  "parameters": [
2213
- {
2214
- "name": "index",
2215
- "type": {
2216
- "text": "number"
2217
- }
2218
- },
2219
2179
  {
2220
2180
  "name": "event",
2221
2181
  "type": {
@@ -2226,939 +2186,806 @@
2226
2186
  },
2227
2187
  {
2228
2188
  "kind": "method",
2229
- "name": "openFilePicker",
2189
+ "name": "clearAttachedAlertSound"
2190
+ },
2191
+ {
2192
+ "kind": "method",
2193
+ "name": "testAttachedAlertSound"
2194
+ },
2195
+ {
2196
+ "kind": "method",
2197
+ "name": "stopTestSound"
2198
+ },
2199
+ {
2200
+ "kind": "method",
2201
+ "name": "resetAlertSoundState"
2202
+ },
2203
+ {
2204
+ "kind": "method",
2205
+ "name": "applyAlertSoundToPayload",
2230
2206
  "return": {
2231
2207
  "type": {
2232
- "text": "boolean"
2208
+ "text": "T"
2233
2209
  }
2234
2210
  },
2235
2211
  "parameters": [
2236
2212
  {
2237
- "name": "index",
2213
+ "name": "target",
2238
2214
  "type": {
2239
- "text": "number"
2215
+ "text": "T"
2240
2216
  }
2241
2217
  }
2242
- ]
2218
+ ],
2219
+ "description": "Merges pending sound / clear flag onto a create/update DETAILS object."
2243
2220
  },
2244
2221
  {
2245
2222
  "kind": "method",
2246
- "name": "onFileSelected",
2247
- "return": {
2248
- "type": {
2249
- "text": "boolean"
2250
- }
2251
- },
2252
- "parameters": [
2253
- {
2254
- "name": "event",
2255
- "type": {
2256
- "text": "Event"
2257
- }
2258
- }
2259
- ]
2260
- },
2261
- {
2262
- "kind": "method",
2263
- "name": "clearSound",
2264
- "return": {
2265
- "type": {
2266
- "text": "boolean"
2267
- }
2268
- },
2269
- "parameters": [
2270
- {
2271
- "name": "index",
2272
- "type": {
2273
- "text": "number"
2274
- }
2275
- }
2276
- ]
2277
- },
2278
- {
2279
- "kind": "method",
2280
- "name": "testSound",
2281
- "return": {
2282
- "type": {
2283
- "text": "boolean"
2284
- }
2285
- },
2286
- "parameters": [
2287
- {
2288
- "name": "index",
2289
- "type": {
2290
- "text": "number"
2291
- }
2292
- }
2293
- ]
2294
- },
2295
- {
2296
- "kind": "method",
2297
- "name": "toggleRuleMute",
2298
- "return": {
2299
- "type": {
2300
- "text": "boolean"
2301
- }
2302
- },
2303
- "parameters": [
2304
- {
2305
- "name": "index",
2306
- "type": {
2307
- "text": "number"
2308
- }
2309
- }
2310
- ]
2311
- },
2312
- {
2313
- "kind": "method",
2314
- "name": "onVolumeChange",
2315
- "return": {
2316
- "type": {
2317
- "text": "boolean"
2318
- }
2319
- },
2320
- "parameters": [
2321
- {
2322
- "name": "event",
2323
- "type": {
2324
- "text": "Event"
2325
- }
2326
- }
2327
- ]
2328
- },
2329
- {
2330
- "kind": "method",
2331
- "name": "toggleMute",
2332
- "return": {
2333
- "type": {
2334
- "text": "boolean"
2335
- }
2336
- }
2337
- },
2223
+ "name": "syncAlertSoundCacheAfterSave",
2224
+ "description": "Keep AlertSoundPlayer's in-memory NOTIFY_ALERT_SOUND cache in sync with\nwhat we just saved — otherwise the next alert still plays the old file."
2225
+ }
2226
+ ],
2227
+ "parameters": [
2338
2228
  {
2339
- "kind": "method",
2340
- "name": "addRule",
2341
- "return": {
2342
- "type": {
2343
- "text": "boolean"
2344
- }
2229
+ "name": "Base",
2230
+ "type": {
2231
+ "text": "TBase"
2345
2232
  }
2346
- },
2347
- {
2348
- "kind": "method",
2349
- "name": "removeRule",
2350
- "return": {
2351
- "type": {
2352
- "text": "boolean"
2353
- }
2354
- },
2355
- "parameters": [
2356
- {
2357
- "name": "index",
2358
- "type": {
2359
- "text": "number"
2360
- }
2361
- }
2362
- ]
2363
- },
2364
- {
2365
- "kind": "method",
2366
- "name": "reloadRules",
2367
- "return": {
2368
- "type": {
2369
- "text": "Promise<void>"
2370
- }
2371
- },
2372
- "description": "Reloads the notification-rule picker (e.g. when the Sounds tab is opened)."
2373
- },
2233
+ }
2234
+ ],
2235
+ "privacy": "public"
2236
+ }
2237
+ ],
2238
+ "exports": [
2239
+ {
2240
+ "kind": "js",
2241
+ "name": "alertSoundAttachmentTemplate",
2242
+ "declaration": {
2243
+ "name": "alertSoundAttachmentTemplate",
2244
+ "module": "src/components/foundation-notification-dashboard/alert-sound-attachment.ts"
2245
+ }
2246
+ },
2247
+ {
2248
+ "kind": "js",
2249
+ "name": "AlertSoundAttachmentMixin",
2250
+ "declaration": {
2251
+ "name": "AlertSoundAttachmentMixin",
2252
+ "module": "src/components/foundation-notification-dashboard/alert-sound-attachment.ts"
2253
+ }
2254
+ }
2255
+ ]
2256
+ },
2257
+ {
2258
+ "kind": "javascript-module",
2259
+ "path": "src/components/foundation-notification-dashboard/index.ts",
2260
+ "declarations": [],
2261
+ "exports": [
2262
+ {
2263
+ "kind": "js",
2264
+ "name": "*",
2265
+ "declaration": {
2266
+ "name": "*",
2267
+ "package": "./notification-dashboard"
2268
+ }
2269
+ }
2270
+ ]
2271
+ },
2272
+ {
2273
+ "kind": "javascript-module",
2274
+ "path": "src/components/foundation-notification-dashboard/notification-dashboard.styles.ts",
2275
+ "declarations": [
2276
+ {
2277
+ "kind": "variable",
2278
+ "name": "FoundationNotificationDashboardStyles",
2279
+ "default": "css`\n .notification-dashboard,\n rapid-tabs,\n rapid-tab-panel {\n height: 100%;\n }\n\n .no-permissions {\n font-family: var(--body-font);\n color: var(--neutral-foreground-rest);\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n`",
2280
+ "privacy": "public"
2281
+ }
2282
+ ],
2283
+ "exports": [
2284
+ {
2285
+ "kind": "js",
2286
+ "name": "FoundationNotificationDashboardStyles",
2287
+ "declaration": {
2288
+ "name": "FoundationNotificationDashboardStyles",
2289
+ "module": "src/components/foundation-notification-dashboard/notification-dashboard.styles.ts"
2290
+ }
2291
+ }
2292
+ ]
2293
+ },
2294
+ {
2295
+ "kind": "javascript-module",
2296
+ "path": "src/components/foundation-notification-dashboard/notification-dashboard.tabs.ts",
2297
+ "declarations": [
2298
+ {
2299
+ "kind": "class",
2300
+ "description": "",
2301
+ "name": "NotificationDashboardTab",
2302
+ "members": [
2374
2303
  {
2375
- "kind": "method",
2376
- "name": "loadRules",
2377
- "privacy": "private",
2378
- "return": {
2379
- "type": {
2380
- "text": "Promise<void>"
2381
- }
2304
+ "kind": "field",
2305
+ "name": "id",
2306
+ "type": {
2307
+ "text": "string"
2382
2308
  }
2383
2309
  },
2384
2310
  {
2385
- "kind": "method",
2386
- "name": "settleRuleOptions",
2387
- "privacy": "private",
2388
- "return": {
2389
- "type": {
2390
- "text": "Promise<void>"
2391
- }
2392
- },
2393
- "description": "Suppresses select `change` events only while options-datasource rebuilds\nthe DOM — not for the `getRules()` round trip itself, so a user picking a\nrule while a request is in flight isn't silently dropped."
2394
- },
2395
- {
2396
- "kind": "method",
2397
- "name": "applyRuleSelectValues",
2398
- "privacy": "private",
2399
- "return": {
2400
- "type": {
2401
- "text": "void"
2402
- }
2403
- },
2404
- "description": "Re-applies persisted template ids onto `.rule-select` hosts after\noptions-datasource has rebuilt its options. We deliberately do *not* bind\n`:initialSelectedValue` to templateId: that path compares the option label\nagainst Select.value (the option id), always mismatches, clearData()'s the\nselect, and leaves the next pick stuck on \"Select a rule...\"."
2405
- },
2406
- {
2407
- "kind": "method",
2408
- "name": "mapRules",
2409
- "privacy": "private",
2410
- "return": {
2411
- "type": {
2412
- "text": "AlertSoundSelectableRule[]"
2413
- }
2414
- },
2415
- "parameters": [
2416
- {
2417
- "name": "ruleList",
2418
- "type": {
2419
- "text": "NamedRuleRow[]"
2420
- }
2421
- }
2422
- ]
2423
- },
2424
- {
2425
- "kind": "method",
2426
- "name": "ruleMatchId",
2427
- "privacy": "private",
2428
- "return": {
2429
- "type": {
2430
- "text": "string"
2431
- }
2432
- },
2433
- "parameters": [
2434
- {
2435
- "name": "rule",
2436
- "type": {
2437
- "text": "NamedRuleRow | undefined"
2438
- }
2439
- }
2440
- ]
2311
+ "kind": "field",
2312
+ "name": "name",
2313
+ "type": {
2314
+ "text": "string"
2315
+ }
2441
2316
  },
2442
2317
  {
2443
- "kind": "method",
2444
- "name": "syncSoundState",
2445
- "privacy": "private"
2318
+ "kind": "field",
2319
+ "name": "component",
2320
+ "type": {
2321
+ "text": "string"
2322
+ }
2323
+ },
2324
+ {
2325
+ "kind": "field",
2326
+ "name": "right",
2327
+ "type": {
2328
+ "text": "string"
2329
+ }
2446
2330
  }
2447
- ],
2448
- "superclass": {
2449
- "name": "GenesisElement",
2450
- "package": "@genesislcap/web-core"
2331
+ ]
2332
+ },
2333
+ {
2334
+ "kind": "variable",
2335
+ "name": "NOTIFICATION_DASHBOARD_TABS",
2336
+ "type": {
2337
+ "text": "NotificationDashboardTab[]"
2451
2338
  },
2452
- "tagName": "foundation-sounds-panel",
2453
- "customElement": true
2339
+ "default": "[\n {\n id: 'rules',\n name: 'Rules',\n component: 'rule-management',\n right: 'NotificationRuleView',\n },\n {\n id: 'templates',\n name: 'Templates',\n component: 'template-management',\n right: 'NotificationRuleTemplateView',\n },\n {\n id: 'routes',\n name: 'Routes',\n component: 'route-management',\n right: 'NotificationRouteView',\n },\n /* TODO: Not needed at the moment\n {\n id: 'notify-audit',\n name: 'Notify Audit',\n component: 'notify-audit-management',\n right: 'NotificationAuditView',\n },\n */\n]"
2454
2340
  }
2455
2341
  ],
2456
2342
  "exports": [
2457
2343
  {
2458
2344
  "kind": "js",
2459
- "name": "FoundationSoundsPanel",
2345
+ "name": "NotificationDashboardTab",
2460
2346
  "declaration": {
2461
- "name": "FoundationSoundsPanel",
2462
- "module": "src/components/foundation-sounds/foundation-sounds-panel.ts"
2347
+ "name": "NotificationDashboardTab",
2348
+ "module": "src/components/foundation-notification-dashboard/notification-dashboard.tabs.ts"
2463
2349
  }
2464
2350
  },
2465
2351
  {
2466
- "kind": "custom-element-definition",
2467
- "name": "foundation-sounds-panel",
2352
+ "kind": "js",
2353
+ "name": "NOTIFICATION_DASHBOARD_TABS",
2468
2354
  "declaration": {
2469
- "name": "FoundationSoundsPanel",
2470
- "module": "src/components/foundation-sounds/foundation-sounds-panel.ts"
2355
+ "name": "NOTIFICATION_DASHBOARD_TABS",
2356
+ "module": "src/components/foundation-notification-dashboard/notification-dashboard.tabs.ts"
2471
2357
  }
2472
2358
  }
2473
2359
  ]
2474
2360
  },
2475
2361
  {
2476
2362
  "kind": "javascript-module",
2477
- "path": "src/components/foundation-sounds/foundation-sounds.styles.ts",
2363
+ "path": "src/components/foundation-notification-dashboard/notification-dashboard.template.ts",
2478
2364
  "declarations": [
2479
2365
  {
2480
2366
  "kind": "variable",
2481
- "name": "FoundationSoundsStyles",
2482
- "default": "css`\n :host {\n display: none;\n }\n`",
2483
- "description": "Headless layout listener — take no space in the layout chrome."
2367
+ "name": "FoundationNotificationDashboardTemplate",
2368
+ "default": "html<FoundationNotificationDashboard>`\n <div class=\"notification-dashboard\">\n ${whenElse(\n (x) => x.hasPermissions,\n html`\n <rapid-tabs class=\"tabs\">\n <!-- Tabs -->\n ${repeat(\n (_) => NOTIFICATION_DASHBOARD_TABS,\n html<NotificationDashboardTab>`\n ${when(\n (x, c) => (c.parent.auth as Auth).currentUser.hasPermission(x.right),\n html<NotificationDashboardTab>`\n <rapid-tab slot=\"${(x) => x.id}-tab\">${(x) => x.name}</rapid-tab>\n `,\n )}\n `,\n )}\n\n <!-- Panels -->\n ${repeat(\n (_) => NOTIFICATION_DASHBOARD_TABS,\n html<NotificationDashboardTab>`\n ${when(\n (x, c) => (c.parent.auth as Auth).currentUser.hasPermission(x.right),\n html`\n ${\n /* HTML Render */\n (x) => html<NotificationDashboardTab>`\n <rapid-tab-panel slot=\"${x.id}-tab\"\n id=\"${x.id}-tab-panel\">\n <${x.component}></${x.component}>\n </rapid-tab-panel>\n `\n }\n `,\n )}\n `,\n )}\n </rapid-tabs>\n `,\n html`\n <div class=\"no-permissions\">\n <label>User has no permissions to view Notification Screens</label>\n </div>\n `,\n )}\n </div>\n`"
2484
2369
  }
2485
2370
  ],
2486
2371
  "exports": [
2487
2372
  {
2488
2373
  "kind": "js",
2489
- "name": "FoundationSoundsStyles",
2374
+ "name": "FoundationNotificationDashboardTemplate",
2490
2375
  "declaration": {
2491
- "name": "FoundationSoundsStyles",
2492
- "module": "src/components/foundation-sounds/foundation-sounds.styles.ts"
2376
+ "name": "FoundationNotificationDashboardTemplate",
2377
+ "module": "src/components/foundation-notification-dashboard/notification-dashboard.template.ts"
2493
2378
  }
2494
2379
  }
2495
2380
  ]
2496
2381
  },
2497
2382
  {
2498
2383
  "kind": "javascript-module",
2499
- "path": "src/components/foundation-sounds/foundation-sounds.ts",
2384
+ "path": "src/components/foundation-notification-dashboard/notification-dashboard.ts",
2500
2385
  "declarations": [
2501
2386
  {
2502
2387
  "kind": "class",
2503
- "description": "Headless listener for inbox alert inserts. Plays configured sounds via the\nshared AlertSoundPlayer. Mount once in the app layout.\n\nConfigure rules in the inbox Sounds tab with FoundationSoundsPanel.",
2504
- "name": "FoundationSounds",
2388
+ "description": "",
2389
+ "name": "FoundationNotificationDashboard",
2505
2390
  "members": [
2506
2391
  {
2507
2392
  "kind": "field",
2508
- "name": "connect",
2393
+ "name": "auth",
2509
2394
  "type": {
2510
- "text": "Connect"
2395
+ "text": "Auth"
2511
2396
  }
2512
2397
  },
2513
2398
  {
2514
2399
  "kind": "field",
2515
- "name": "inboxService",
2400
+ "name": "ready",
2516
2401
  "type": {
2517
- "text": "FoundationInboxService"
2518
- }
2402
+ "text": "boolean"
2403
+ },
2404
+ "default": "false"
2519
2405
  },
2520
2406
  {
2521
2407
  "kind": "field",
2522
- "name": "ruleService",
2408
+ "name": "hasPermissions",
2523
2409
  "type": {
2524
- "text": "RuleService"
2525
- }
2526
- },
2410
+ "text": "boolean"
2411
+ },
2412
+ "default": "true"
2413
+ }
2414
+ ],
2415
+ "superclass": {
2416
+ "name": "GenesisElement",
2417
+ "package": "@genesislcap/web-core"
2418
+ },
2419
+ "tagName": "foundation-notification-dashboard",
2420
+ "customElement": true
2421
+ }
2422
+ ],
2423
+ "exports": [
2424
+ {
2425
+ "kind": "js",
2426
+ "name": "FoundationNotificationDashboard",
2427
+ "declaration": {
2428
+ "name": "FoundationNotificationDashboard",
2429
+ "module": "src/components/foundation-notification-dashboard/notification-dashboard.ts"
2430
+ }
2431
+ },
2432
+ {
2433
+ "kind": "custom-element-definition",
2434
+ "name": "foundation-notification-dashboard",
2435
+ "declaration": {
2436
+ "name": "FoundationNotificationDashboard",
2437
+ "module": "src/components/foundation-notification-dashboard/notification-dashboard.ts"
2438
+ }
2439
+ }
2440
+ ]
2441
+ },
2442
+ {
2443
+ "kind": "javascript-module",
2444
+ "path": "src/components/foundation-notification-dashboard/notification-dashboard.utils.ts",
2445
+ "declarations": [
2446
+ {
2447
+ "kind": "class",
2448
+ "description": "",
2449
+ "name": "UUIDGenerator",
2450
+ "members": [
2527
2451
  {
2528
2452
  "kind": "field",
2529
- "name": "soundEnabled",
2453
+ "name": "uuid",
2530
2454
  "type": {
2531
- "text": "boolean"
2455
+ "text": "UUID"
2532
2456
  },
2533
- "default": "true",
2534
- "description": "When false, new audible alerts are tracked but do not play."
2457
+ "privacy": "private",
2458
+ "static": true
2535
2459
  },
2536
2460
  {
2537
2461
  "kind": "field",
2538
- "name": "connectionSub",
2539
- "type": {
2540
- "text": "Subscription | undefined"
2541
- },
2542
- "privacy": "private"
2462
+ "name": "createUUID",
2463
+ "static": true
2464
+ }
2465
+ ]
2466
+ },
2467
+ {
2468
+ "kind": "function",
2469
+ "name": "isEmpty",
2470
+ "parameters": [
2471
+ {
2472
+ "name": "value"
2473
+ }
2474
+ ]
2475
+ },
2476
+ {
2477
+ "kind": "class",
2478
+ "description": "",
2479
+ "name": "DynamicRuleUtils",
2480
+ "members": [
2481
+ {
2482
+ "kind": "field",
2483
+ "name": "createEmptyCondition",
2484
+ "static": true
2543
2485
  },
2544
2486
  {
2545
2487
  "kind": "field",
2546
- "name": "player",
2547
- "privacy": "private",
2548
- "readonly": true
2488
+ "name": "createAssignment",
2489
+ "static": true
2549
2490
  },
2550
2491
  {
2551
2492
  "kind": "field",
2552
- "name": "knownAlertIds",
2553
- "privacy": "private",
2554
- "default": "new Set<string>()"
2493
+ "name": "createTextAssignment",
2494
+ "static": true
2555
2495
  },
2556
2496
  {
2557
2497
  "kind": "field",
2558
- "name": "serverSoundFetches",
2559
- "privacy": "private",
2560
- "readonly": true,
2561
- "default": "new Map<string, Promise<boolean>>()",
2562
- "description": "In-flight server sound fetches keyed by DYNAMIC_RULE_ID."
2498
+ "name": "getAssignmentValue",
2499
+ "static": true
2500
+ },
2501
+ {
2502
+ "kind": "field",
2503
+ "name": "getAssignmentText",
2504
+ "static": true
2563
2505
  },
2564
2506
  {
2565
2507
  "kind": "method",
2566
- "name": "subscribeToAlerts",
2567
- "privacy": "private",
2508
+ "name": "createConditions",
2509
+ "static": true,
2568
2510
  "return": {
2569
2511
  "type": {
2570
- "text": "void"
2512
+ "text": "any"
2571
2513
  }
2572
- }
2514
+ },
2515
+ "parameters": [
2516
+ {
2517
+ "name": "conditions",
2518
+ "type": {
2519
+ "text": "ConditionNode[]"
2520
+ }
2521
+ },
2522
+ {
2523
+ "name": "parameters",
2524
+ "optional": true
2525
+ }
2526
+ ]
2573
2527
  },
2574
2528
  {
2575
- "kind": "field",
2576
- "name": "subscriptionHandler",
2577
- "privacy": "private"
2529
+ "kind": "method",
2530
+ "name": "hasMultiValueCondition",
2531
+ "static": true,
2532
+ "return": {
2533
+ "type": {
2534
+ "text": "boolean"
2535
+ }
2536
+ },
2537
+ "parameters": [
2538
+ {
2539
+ "name": "conditions",
2540
+ "type": {
2541
+ "text": "ConditionNode[]"
2542
+ }
2543
+ }
2544
+ ]
2545
+ },
2546
+ {
2547
+ "kind": "method",
2548
+ "name": "hasOrJoin",
2549
+ "static": true,
2550
+ "return": {
2551
+ "type": {
2552
+ "text": "boolean"
2553
+ }
2554
+ },
2555
+ "parameters": [
2556
+ {
2557
+ "name": "conditions",
2558
+ "type": {
2559
+ "text": "ConditionNode[]"
2560
+ }
2561
+ }
2562
+ ]
2563
+ },
2564
+ {
2565
+ "kind": "method",
2566
+ "name": "hasGroup",
2567
+ "static": true,
2568
+ "return": {
2569
+ "type": {
2570
+ "text": "boolean"
2571
+ }
2572
+ },
2573
+ "parameters": [
2574
+ {
2575
+ "name": "conditions",
2576
+ "type": {
2577
+ "text": "ConditionNode[]"
2578
+ }
2579
+ }
2580
+ ]
2578
2581
  },
2579
2582
  {
2580
2583
  "kind": "method",
2581
- "name": "playForNewAlerts",
2582
- "privacy": "private",
2584
+ "name": "hasUnsupportedOperator",
2585
+ "static": true,
2583
2586
  "return": {
2584
2587
  "type": {
2585
- "text": "Promise<void>"
2588
+ "text": "boolean"
2586
2589
  }
2587
2590
  },
2588
2591
  "parameters": [
2589
2592
  {
2590
- "name": "rows",
2593
+ "name": "conditions",
2591
2594
  "type": {
2592
- "text": "Array<{\n id: string;\n message?: string;\n header?: string;\n dynamicRuleId?: string;\n }>"
2595
+ "text": "ConditionNode[]"
2593
2596
  }
2594
2597
  }
2595
2598
  ]
2596
2599
  },
2597
2600
  {
2598
2601
  "kind": "method",
2599
- "name": "tryPlayServerSound",
2600
- "privacy": "private",
2602
+ "name": "flattenConditions",
2603
+ "static": true,
2601
2604
  "return": {
2602
2605
  "type": {
2603
- "text": "Promise<boolean>"
2606
+ "text": "ConditionBuilderEntity[]"
2604
2607
  }
2605
2608
  },
2606
2609
  "parameters": [
2607
2610
  {
2608
- "name": "dynamicRuleId",
2611
+ "name": "conditions",
2609
2612
  "type": {
2610
- "text": "string"
2613
+ "text": "ConditionNode[]"
2611
2614
  }
2612
2615
  }
2613
2616
  ]
2614
2617
  },
2615
2618
  {
2616
2619
  "kind": "method",
2617
- "name": "fetchAndCacheServerSound",
2618
- "privacy": "private",
2620
+ "name": "resolveLeftValues",
2621
+ "static": true,
2619
2622
  "return": {
2620
2623
  "type": {
2621
- "text": "Promise<boolean>"
2624
+ "text": "ConditionNode[]"
2622
2625
  }
2623
2626
  },
2624
2627
  "parameters": [
2625
2628
  {
2626
- "name": "dynamicRuleId",
2629
+ "name": "conditions",
2627
2630
  "type": {
2628
- "text": "string"
2631
+ "text": "ConditionNode[]"
2632
+ }
2633
+ },
2634
+ {
2635
+ "name": "fields",
2636
+ "type": {
2637
+ "text": "any[]"
2629
2638
  }
2630
2639
  }
2631
2640
  ]
2632
- }
2633
- ],
2634
- "attributes": [
2635
- {
2636
- "name": "sound-enabled",
2637
- "type": {
2638
- "text": "boolean"
2639
- },
2640
- "default": "true",
2641
- "description": "When false, new audible alerts are tracked but do not play.",
2642
- "fieldName": "soundEnabled"
2643
- }
2644
- ],
2645
- "superclass": {
2646
- "name": "GenesisElement",
2647
- "package": "@genesislcap/web-core"
2648
- },
2649
- "tagName": "foundation-sounds",
2650
- "customElement": true
2651
- }
2652
- ],
2653
- "exports": [
2654
- {
2655
- "kind": "js",
2656
- "name": "FoundationSounds",
2657
- "declaration": {
2658
- "name": "FoundationSounds",
2659
- "module": "src/components/foundation-sounds/foundation-sounds.ts"
2660
- }
2661
- },
2662
- {
2663
- "kind": "custom-element-definition",
2664
- "name": "foundation-sounds",
2665
- "declaration": {
2666
- "name": "FoundationSounds",
2667
- "module": "src/components/foundation-sounds/foundation-sounds.ts"
2668
- }
2669
- }
2670
- ]
2671
- },
2672
- {
2673
- "kind": "javascript-module",
2674
- "path": "src/components/foundation-notification-dashboard/alert-sound-attachment.ts",
2675
- "declarations": [
2676
- {
2677
- "kind": "variable",
2678
- "name": "alertSoundAttachmentTemplate",
2679
- "default": "html<AlertSoundAttachmentHost>`\n <div class=\"alert-sound\">\n <input\n ${ref('fileInput')}\n class=\"file-input\"\n type=\"file\"\n accept=\"audio/*\"\n @change=${(x, c) => x.onAlertSoundSelected(c.event)}\n />\n <label>Alert sound</label>\n <div class=\"alert-sound-row\">\n <span class=\"alert-sound-name\" title=${(x) => x.alertSoundFileName || ''}>\n ${(x) => x.alertSoundFileName || 'No sound attached'}\n </span>\n <rapid-button appearance=\"lightweight\" @click=${(x) => x.openAlertSoundPicker()}>\n ${(x) => (x.hasAlertSound ? 'Replace' : 'Attach')}\n </rapid-button>\n ${when(\n (x) => x.hasAlertSound,\n html<AlertSoundAttachmentHost>`\n <rapid-button appearance=\"lightweight\" @click=${(x) => x.testAttachedAlertSound()}>\n Test\n </rapid-button>\n <rapid-button appearance=\"lightweight\" @click=${(x) => x.clearAttachedAlertSound()}>\n Clear\n </rapid-button>\n `,\n )}\n </div>\n </div>\n`",
2680
- "description": "Shared Attach/Replace/Test/Clear UI for rule and template dialogs.",
2681
- "privacy": "public"
2682
- },
2683
- {
2684
- "kind": "mixin",
2685
- "description": "Mixin: pick / test / clear / load server sound + apply fields to submit payload.\n\nSubclasses must provide ruleService, isAlertSoundEditMode,\nalertSoundEntityId, and alertSoundCacheSyncMode.",
2686
- "name": "AlertSoundAttachmentMixin",
2687
- "members": [
2688
- {
2689
- "kind": "field",
2690
- "name": "ruleService",
2691
- "type": {
2692
- "text": "RuleService"
2693
- }
2694
- },
2695
- {
2696
- "kind": "field",
2697
- "name": "isAlertSoundEditMode",
2698
- "type": {
2699
- "text": "boolean"
2700
- },
2701
- "description": "True when editing an existing entity (clear should set CLEAR_ALERT_SOUND).",
2702
- "readonly": true
2703
- },
2704
- {
2705
- "kind": "field",
2706
- "name": "alertSoundEntityId",
2707
- "type": {
2708
- "text": "string | null"
2709
- },
2710
- "description": "DYNAMIC_RULE_ID of the entity being edited (null on create).\nUsed when alertSoundCacheSyncMode is `'entity'`.",
2711
- "readonly": true
2712
- },
2713
- {
2714
- "kind": "field",
2715
- "name": "alertSoundCacheSyncMode",
2716
- "type": {
2717
- "text": "'entity' | 'all'"
2718
- },
2719
- "description": "`'entity'` — update/clear cache for alertSoundEntityId (rules).\n`'all'` — drop every cached server sound (templates; instance ids unknown).",
2720
- "readonly": true
2721
- },
2722
- {
2723
- "kind": "field",
2724
- "name": "alertSoundFileName",
2725
- "type": {
2726
- "text": "string"
2727
- },
2728
- "default": "''",
2729
- "description": "Display name of the attached / pending alert sound file."
2730
- },
2731
- {
2732
- "kind": "field",
2733
- "name": "alertSoundMimeType",
2734
- "type": {
2735
- "text": "string"
2736
- },
2737
- "default": "''"
2738
- },
2739
- {
2740
- "kind": "field",
2741
- "name": "hasAlertSound",
2742
- "type": {
2743
- "text": "boolean"
2744
- },
2745
- "default": "false",
2746
- "description": "True when edit loaded an existing server sound (or user attached one)."
2747
- },
2748
- {
2749
- "kind": "field",
2750
- "name": "fileInput",
2751
- "type": {
2752
- "text": "HTMLInputElement"
2753
- }
2754
- },
2755
- {
2756
- "kind": "field",
2757
- "name": "pendingAlertSoundData",
2758
- "type": {
2759
- "text": "string | null"
2760
- },
2761
- "default": "null"
2762
- },
2763
- {
2764
- "kind": "field",
2765
- "name": "alertSoundDirty",
2766
- "type": {
2767
- "text": "boolean"
2768
- },
2769
- "default": "false",
2770
- "description": "True when the user picked a new file this session (needs upload)."
2771
2641
  },
2772
2642
  {
2773
2643
  "kind": "field",
2774
- "name": "clearAlertSound",
2775
- "type": {
2776
- "text": "boolean"
2777
- },
2778
- "default": "false"
2779
- },
2780
- {
2781
- "kind": "field",
2782
- "name": "testAudio",
2783
- "type": {
2784
- "text": "HTMLAudioElement | null"
2785
- },
2786
- "default": "null",
2787
- "description": "In-progress Test playback; not private — mixin return type is exported."
2644
+ "name": "createEmptyGroup",
2645
+ "static": true
2788
2646
  },
2789
2647
  {
2790
2648
  "kind": "method",
2791
- "name": "loadExistingAlertSound",
2649
+ "name": "buildRawExpression",
2650
+ "static": true,
2651
+ "return": {
2652
+ "type": {
2653
+ "text": "string"
2654
+ }
2655
+ },
2792
2656
  "parameters": [
2793
2657
  {
2794
- "name": "dynamicRuleId",
2658
+ "name": "conditions",
2795
2659
  "type": {
2796
- "text": "string"
2660
+ "text": "ConditionNode[]"
2797
2661
  }
2798
2662
  }
2799
2663
  ]
2800
2664
  },
2801
2665
  {
2802
2666
  "kind": "method",
2803
- "name": "openAlertSoundPicker"
2804
- },
2805
- {
2806
- "kind": "method",
2807
- "name": "onAlertSoundSelected",
2667
+ "name": "parseRawExpression",
2668
+ "static": true,
2669
+ "return": {
2670
+ "type": {
2671
+ "text": "ConditionNode[] | null"
2672
+ }
2673
+ },
2808
2674
  "parameters": [
2809
2675
  {
2810
- "name": "event",
2676
+ "name": "rawExpression",
2811
2677
  "type": {
2812
- "text": "Event"
2678
+ "text": "string"
2813
2679
  }
2814
2680
  }
2815
2681
  ]
2682
+ }
2683
+ ]
2684
+ },
2685
+ {
2686
+ "kind": "class",
2687
+ "description": "",
2688
+ "name": "TemplateUtils",
2689
+ "members": [
2690
+ {
2691
+ "kind": "field",
2692
+ "name": "createEmptyParameter",
2693
+ "static": true
2816
2694
  },
2817
2695
  {
2818
2696
  "kind": "method",
2819
- "name": "clearAttachedAlertSound"
2697
+ "name": "getParameters",
2698
+ "static": true,
2699
+ "parameters": [
2700
+ {
2701
+ "name": "parameters"
2702
+ }
2703
+ ]
2820
2704
  },
2821
2705
  {
2822
2706
  "kind": "method",
2823
- "name": "testAttachedAlertSound"
2707
+ "name": "buildRightValue",
2708
+ "privacy": "private",
2709
+ "static": true,
2710
+ "parameters": [
2711
+ {
2712
+ "name": "logicalOperator",
2713
+ "type": {
2714
+ "text": "LogicalOperator"
2715
+ }
2716
+ },
2717
+ {
2718
+ "name": "condition"
2719
+ },
2720
+ {
2721
+ "name": "parameters",
2722
+ "optional": true
2723
+ }
2724
+ ]
2824
2725
  },
2825
2726
  {
2826
2727
  "kind": "method",
2827
- "name": "stopTestSound"
2728
+ "name": "getConditions",
2729
+ "static": true,
2730
+ "parameters": [
2731
+ {
2732
+ "name": "conditions"
2733
+ },
2734
+ {
2735
+ "name": "parameters",
2736
+ "optional": true
2737
+ }
2738
+ ]
2828
2739
  },
2829
2740
  {
2830
2741
  "kind": "method",
2831
- "name": "resetAlertSoundState"
2832
- },
2742
+ "name": "createParameterDetails",
2743
+ "static": true,
2744
+ "parameters": [
2745
+ {
2746
+ "name": "parameters"
2747
+ }
2748
+ ]
2749
+ }
2750
+ ]
2751
+ },
2752
+ {
2753
+ "kind": "class",
2754
+ "description": "",
2755
+ "name": "RuleUtils",
2756
+ "members": [
2833
2757
  {
2834
2758
  "kind": "method",
2835
- "name": "applyAlertSoundToPayload",
2836
- "return": {
2837
- "type": {
2838
- "text": "T"
2839
- }
2840
- },
2759
+ "name": "buildRightValue",
2760
+ "privacy": "private",
2761
+ "static": true,
2841
2762
  "parameters": [
2842
2763
  {
2843
- "name": "target",
2764
+ "name": "logicalOperator",
2844
2765
  "type": {
2845
- "text": "T"
2766
+ "text": "LogicalOperator"
2846
2767
  }
2768
+ },
2769
+ {
2770
+ "name": "condition"
2847
2771
  }
2848
- ],
2849
- "description": "Merges pending sound / clear flag onto a create/update DETAILS object."
2772
+ ]
2850
2773
  },
2851
2774
  {
2852
2775
  "kind": "method",
2853
- "name": "syncAlertSoundCacheAfterSave",
2854
- "description": "Keep AlertSoundPlayer's in-memory NOTIFY_ALERT_SOUND cache in sync with\nwhat we just saved — otherwise the next alert still plays the old file."
2776
+ "name": "getConditions",
2777
+ "static": true,
2778
+ "parameters": [
2779
+ {
2780
+ "name": "conditions"
2781
+ }
2782
+ ]
2855
2783
  }
2856
- ],
2784
+ ]
2785
+ },
2786
+ {
2787
+ "kind": "function",
2788
+ "name": "showNotificationError",
2857
2789
  "parameters": [
2858
2790
  {
2859
- "name": "Base",
2860
- "type": {
2861
- "text": "TBase"
2862
- }
2791
+ "name": "error"
2863
2792
  }
2864
- ],
2865
- "privacy": "public"
2793
+ ]
2866
2794
  }
2867
2795
  ],
2868
2796
  "exports": [
2869
2797
  {
2870
2798
  "kind": "js",
2871
- "name": "alertSoundAttachmentTemplate",
2799
+ "name": "UUIDGenerator",
2872
2800
  "declaration": {
2873
- "name": "alertSoundAttachmentTemplate",
2874
- "module": "src/components/foundation-notification-dashboard/alert-sound-attachment.ts"
2801
+ "name": "UUIDGenerator",
2802
+ "module": "src/components/foundation-notification-dashboard/notification-dashboard.utils.ts"
2875
2803
  }
2876
2804
  },
2877
2805
  {
2878
2806
  "kind": "js",
2879
- "name": "AlertSoundAttachmentMixin",
2807
+ "name": "isEmpty",
2880
2808
  "declaration": {
2881
- "name": "AlertSoundAttachmentMixin",
2882
- "module": "src/components/foundation-notification-dashboard/alert-sound-attachment.ts"
2809
+ "name": "isEmpty",
2810
+ "module": "src/components/foundation-notification-dashboard/notification-dashboard.utils.ts"
2883
2811
  }
2884
- }
2885
- ]
2886
- },
2887
- {
2888
- "kind": "javascript-module",
2889
- "path": "src/components/foundation-notification-dashboard/index.ts",
2890
- "declarations": [],
2891
- "exports": [
2812
+ },
2892
2813
  {
2893
2814
  "kind": "js",
2894
- "name": "*",
2815
+ "name": "DynamicRuleUtils",
2895
2816
  "declaration": {
2896
- "name": "*",
2897
- "package": "./notification-dashboard"
2817
+ "name": "DynamicRuleUtils",
2818
+ "module": "src/components/foundation-notification-dashboard/notification-dashboard.utils.ts"
2898
2819
  }
2899
- }
2900
- ]
2901
- },
2902
- {
2903
- "kind": "javascript-module",
2904
- "path": "src/components/foundation-notification-dashboard/notification-dashboard.styles.ts",
2905
- "declarations": [
2906
- {
2907
- "kind": "variable",
2908
- "name": "FoundationNotificationDashboardStyles",
2909
- "default": "css`\n .notification-dashboard,\n rapid-tabs,\n rapid-tab-panel {\n height: 100%;\n }\n\n .no-permissions {\n font-family: var(--body-font);\n color: var(--neutral-foreground-rest);\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n`",
2910
- "privacy": "public"
2911
- }
2912
- ],
2913
- "exports": [
2820
+ },
2914
2821
  {
2915
2822
  "kind": "js",
2916
- "name": "FoundationNotificationDashboardStyles",
2823
+ "name": "TemplateUtils",
2917
2824
  "declaration": {
2918
- "name": "FoundationNotificationDashboardStyles",
2919
- "module": "src/components/foundation-notification-dashboard/notification-dashboard.styles.ts"
2825
+ "name": "TemplateUtils",
2826
+ "module": "src/components/foundation-notification-dashboard/notification-dashboard.utils.ts"
2920
2827
  }
2921
- }
2922
- ]
2923
- },
2924
- {
2925
- "kind": "javascript-module",
2926
- "path": "src/components/foundation-notification-dashboard/notification-dashboard.tabs.ts",
2927
- "declarations": [
2928
- {
2929
- "kind": "class",
2930
- "description": "",
2931
- "name": "NotificationDashboardTab",
2932
- "members": [
2933
- {
2934
- "kind": "field",
2935
- "name": "id",
2936
- "type": {
2937
- "text": "string"
2938
- }
2939
- },
2940
- {
2941
- "kind": "field",
2942
- "name": "name",
2943
- "type": {
2944
- "text": "string"
2945
- }
2946
- },
2947
- {
2948
- "kind": "field",
2949
- "name": "component",
2950
- "type": {
2951
- "text": "string"
2952
- }
2953
- },
2954
- {
2955
- "kind": "field",
2956
- "name": "right",
2957
- "type": {
2958
- "text": "string"
2959
- }
2960
- }
2961
- ]
2962
2828
  },
2963
- {
2964
- "kind": "variable",
2965
- "name": "NOTIFICATION_DASHBOARD_TABS",
2966
- "type": {
2967
- "text": "NotificationDashboardTab[]"
2968
- },
2969
- "default": "[\n {\n id: 'rules',\n name: 'Rules',\n component: 'rule-management',\n right: 'NotificationRuleView',\n },\n {\n id: 'templates',\n name: 'Templates',\n component: 'template-management',\n right: 'NotificationRuleTemplateView',\n },\n {\n id: 'routes',\n name: 'Routes',\n component: 'route-management',\n right: 'NotificationRouteView',\n },\n /* TODO: Not needed at the moment\n {\n id: 'notify-audit',\n name: 'Notify Audit',\n component: 'notify-audit-management',\n right: 'NotificationAuditView',\n },\n */\n]"
2970
- }
2971
- ],
2972
- "exports": [
2973
2829
  {
2974
2830
  "kind": "js",
2975
- "name": "NotificationDashboardTab",
2831
+ "name": "RuleUtils",
2976
2832
  "declaration": {
2977
- "name": "NotificationDashboardTab",
2978
- "module": "src/components/foundation-notification-dashboard/notification-dashboard.tabs.ts"
2833
+ "name": "RuleUtils",
2834
+ "module": "src/components/foundation-notification-dashboard/notification-dashboard.utils.ts"
2979
2835
  }
2980
2836
  },
2981
2837
  {
2982
2838
  "kind": "js",
2983
- "name": "NOTIFICATION_DASHBOARD_TABS",
2839
+ "name": "showNotificationError",
2984
2840
  "declaration": {
2985
- "name": "NOTIFICATION_DASHBOARD_TABS",
2986
- "module": "src/components/foundation-notification-dashboard/notification-dashboard.tabs.ts"
2841
+ "name": "showNotificationError",
2842
+ "module": "src/components/foundation-notification-dashboard/notification-dashboard.utils.ts"
2987
2843
  }
2988
2844
  }
2989
2845
  ]
2990
2846
  },
2991
2847
  {
2992
2848
  "kind": "javascript-module",
2993
- "path": "src/components/foundation-notification-dashboard/notification-dashboard.template.ts",
2849
+ "path": "src/components/foundation-sounds/foundation-sounds-panel.styles.ts",
2994
2850
  "declarations": [
2995
2851
  {
2996
2852
  "kind": "variable",
2997
- "name": "FoundationNotificationDashboardTemplate",
2998
- "default": "html<FoundationNotificationDashboard>`\n <div class=\"notification-dashboard\">\n ${whenElse(\n (x) => x.hasPermissions,\n html`\n <rapid-tabs class=\"tabs\">\n <!-- Tabs -->\n ${repeat(\n (_) => NOTIFICATION_DASHBOARD_TABS,\n html<NotificationDashboardTab>`\n ${when(\n (x, c) => (c.parent.auth as Auth).currentUser.hasPermission(x.right),\n html<NotificationDashboardTab>`\n <rapid-tab slot=\"${(x) => x.id}-tab\">${(x) => x.name}</rapid-tab>\n `,\n )}\n `,\n )}\n\n <!-- Panels -->\n ${repeat(\n (_) => NOTIFICATION_DASHBOARD_TABS,\n html<NotificationDashboardTab>`\n ${when(\n (x, c) => (c.parent.auth as Auth).currentUser.hasPermission(x.right),\n html`\n ${\n /* HTML Render */\n (x) => html<NotificationDashboardTab>`\n <rapid-tab-panel slot=\"${x.id}-tab\"\n id=\"${x.id}-tab-panel\">\n <${x.component}></${x.component}>\n </rapid-tab-panel>\n `\n }\n `,\n )}\n `,\n )}\n </rapid-tabs>\n `,\n html`\n <div class=\"no-permissions\">\n <label>User has no permissions to view Notification Screens</label>\n </div>\n `,\n )}\n </div>\n`"
2853
+ "name": "FoundationSoundsPanelStyles",
2854
+ "default": "css`\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n width: 100%;\n }\n\n .sounds-controls {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n gap: 12px;\n padding: calc(var(--design-unit) * 3px);\n box-sizing: border-box;\n }\n\n .sounds-help-disclosure {\n flex: 0 0 auto;\n }\n\n .sounds-help-toggle {\n margin-inline-start: calc(var(--design-unit) * 1px);\n }\n\n .sounds-help-toggle::before {\n content: '+';\n }\n\n .sounds-help-disclosure[expanded] .sounds-help-toggle::before {\n content: '−';\n }\n\n .sounds-help {\n margin: 0;\n font-size: var(--type-ramp-minus-1-font-size);\n color: var(--neutral-foreground-hint);\n text-align: left;\n }\n\n .volume-row {\n display: flex;\n align-items: center;\n flex: 0 0 auto;\n gap: calc(var(--design-unit) * 2px);\n min-width: 0;\n }\n\n .volume-icon {\n flex: 0 0 auto;\n }\n\n .volume-label {\n flex: 0 0 auto;\n font-size: var(--type-ramp-minus-1-font-size);\n color: var(--neutral-foreground-hint);\n }\n\n .volume-slider {\n flex: 1 1 auto;\n min-width: 0;\n }\n\n .volume-percent {\n flex: 0 0 auto;\n min-width: 3ch;\n text-align: end;\n font-size: var(--type-ramp-minus-1-font-size);\n color: var(--neutral-foreground-hint);\n }\n\n .mute-all {\n flex: 0 0 auto;\n margin: 0;\n }\n\n .sound-rules-panel {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n }\n\n .sound-rules {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .sound-rule {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);\n border-radius: calc(var(--control-corner-radius) * 1px);\n\n /* Keep absolute listboxes from being clipped by the card itself. */\n overflow: visible;\n }\n\n .sound-rule-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-weight: 700;\n font-size: var(--type-ramp-minus-1-font-size);\n }\n\n .sound-rule-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n }\n\n .sound-rule-label {\n display: flex;\n flex-direction: column;\n gap: 4px;\n font-size: var(--type-ramp-minus-1-font-size);\n color: var(--neutral-foreground-hint);\n }\n\n .pattern-input,\n .match-mode-select,\n .rule-select,\n .sound-file-input {\n width: 100%;\n }\n\n /*\n * Anchor the listbox to the select host and use position:fixed so it escapes\n * .sound-rules-panel overflow:auto (and the rule card). Each select sets a\n * unique --sounds-select-anchor / anchor-name via inline style.\n * !important beats FAST's internal absolute top/bottom for [open] selects.\n */\n .match-mode-select[open]::part(listbox),\n .rule-select[open]::part(listbox) {\n position: fixed !important;\n /* stylelint-disable-next-line property-no-unknown -- CSS anchor positioning */\n position-anchor: var(--sounds-select-anchor);\n inset: auto !important;\n top: anchor(bottom) !important;\n left: anchor(left) !important;\n right: anchor(right) !important;\n bottom: auto !important;\n width: auto !important;\n margin-top: calc(var(--design-unit) * 1px);\n z-index: 10000;\n max-height: min(240px, 40vh);\n overflow-x: hidden;\n overflow-y: auto;\n box-shadow: 0 4px 16px rgb(0 0 0 / 24%);\n }\n\n .match-mode-select[open][position='above']::part(listbox),\n .rule-select[open][position='above']::part(listbox) {\n top: auto !important;\n bottom: anchor(top) !important;\n margin-top: 0;\n margin-bottom: calc(var(--design-unit) * 1px);\n }\n\n .sound-file-row {\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .sound-file-row .sound-file-input {\n flex: 1;\n min-width: 0;\n }\n\n .choose-sound {\n cursor: pointer;\n }\n\n .sound-rules-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex: 0 0 auto;\n gap: 8px;\n }\n\n .rule-count {\n font-size: var(--type-ramp-minus-1-font-size);\n color: var(--neutral-foreground-hint);\n }\n\n .file-input {\n display: none;\n }\n\n ${scrollbarStyles}\n`"
2999
2855
  }
3000
2856
  ],
3001
2857
  "exports": [
3002
2858
  {
3003
2859
  "kind": "js",
3004
- "name": "FoundationNotificationDashboardTemplate",
2860
+ "name": "FoundationSoundsPanelStyles",
3005
2861
  "declaration": {
3006
- "name": "FoundationNotificationDashboardTemplate",
3007
- "module": "src/components/foundation-notification-dashboard/notification-dashboard.template.ts"
2862
+ "name": "FoundationSoundsPanelStyles",
2863
+ "module": "src/components/foundation-sounds/foundation-sounds-panel.styles.ts"
3008
2864
  }
3009
2865
  }
3010
2866
  ]
3011
2867
  },
3012
2868
  {
3013
2869
  "kind": "javascript-module",
3014
- "path": "src/components/foundation-notification-dashboard/notification-dashboard.ts",
2870
+ "path": "src/components/foundation-sounds/foundation-sounds-panel.template.ts",
3015
2871
  "declarations": [
3016
2872
  {
3017
- "kind": "class",
3018
- "description": "",
3019
- "name": "FoundationNotificationDashboard",
3020
- "members": [
3021
- {
3022
- "kind": "field",
3023
- "name": "auth",
3024
- "type": {
3025
- "text": "Auth"
3026
- }
3027
- },
3028
- {
3029
- "kind": "field",
3030
- "name": "ready",
3031
- "type": {
3032
- "text": "boolean"
3033
- },
3034
- "default": "false"
3035
- },
3036
- {
3037
- "kind": "field",
3038
- "name": "hasPermissions",
3039
- "type": {
3040
- "text": "boolean"
3041
- },
3042
- "default": "true"
3043
- }
3044
- ],
3045
- "superclass": {
3046
- "name": "GenesisElement",
3047
- "package": "@genesislcap/web-core"
3048
- },
3049
- "tagName": "foundation-notification-dashboard",
3050
- "customElement": true
2873
+ "kind": "variable",
2874
+ "name": "FoundationSoundsPanelTemplate",
2875
+ "default": "html<FoundationSoundsPanel>`\n <div class=\"sounds-controls\" part=\"controls\">\n <input\n ${ref('fileInput')}\n class=\"file-input\"\n type=\"file\"\n accept=\"audio/*\"\n @change=${(x, c) => x.onFileSelected(c.event)}\n />\n <rapid-disclosure class=\"sounds-help-disclosure\" appearance=\"lightweight\">\n <span slot=\"title\">\n Sound Alerts Information\n <span class=\"sounds-help-toggle\" aria-hidden=\"true\"></span>\n </span>\n <p class=\"sounds-help\">\n Add up to ${(x) => x.maxRules} sounds.\n <br />\n Match text in MESSAGE or HEADER (a word or phrase), or a notification rule (including rules\n created when you subscribe to a template).\n <br />\n The first matching rule is played.\n </p>\n </rapid-disclosure>\n <div class=\"volume-row\">\n <rapid-icon\n class=\"volume-icon\"\n name=${(x) => (x.muted || x.volumePercent === 0 ? 'volume-xmark' : 'volume-high')}\n ></rapid-icon>\n <span class=\"volume-label\">Volume</span>\n <rapid-slider\n class=\"volume-slider\"\n min=\"0\"\n max=\"100\"\n step=\"1\"\n :value=${(x) => String(x.volumePercent)}\n @change=${(x, c) => x.onVolumeChange(c.event)}\n ></rapid-slider>\n <span class=\"volume-percent\">${(x) => `${x.volumePercent}%`}</span>\n <rapid-button\n class=\"mute-all\"\n appearance=\"lightweight\"\n title=${(x) => (x.muted ? 'Unmute alert sounds' : 'Mute all alert sounds')}\n @click=${(x) => x.toggleMute()}\n >\n ${(x) => (x.muted ? 'Unmute' : 'Mute all')}\n </rapid-button>\n </div>\n <div class=\"sound-rules-panel\">\n <div class=\"sound-rules\">\n ${repeat(\n (x) => x.rules,\n html<AlertSoundRuleView, FoundationSoundsPanel>`\n <div class=\"sound-rule\" data-rule-index=${(x) => x.index}>\n <div class=\"sound-rule-header\">\n <span>Rule ${(x) => x.index + 1}</span>\n <div class=\"sound-rule-actions\">\n <rapid-button\n class=\"mute-rule\"\n appearance=\"stealth\"\n title=${(x) => (x.muted ? 'Unmute this rule' : 'Mute this rule')}\n @click=${(x, c) => c.parent.toggleRuleMute(x.index)}\n >\n <rapid-icon\n name=${(x) => (x.muted ? 'volume-xmark' : 'volume-high')}\n ></rapid-icon>\n </rapid-button>\n <rapid-button\n class=\"remove-rule\"\n appearance=\"stealth\"\n title=${(_, c) => (c.parent.canRemoveRule ? 'Remove rule' : 'Reset rule')}\n @click=${(x, c) => c.parent.removeRule(x.index)}\n >\n <rapid-icon name=\"trash\"></rapid-icon>\n </rapid-button>\n </div>\n </div>\n <label class=\"sound-rule-label\">\n Match by\n <rapid-select\n class=\"match-mode-select\"\n style=${(x) =>\n `anchor-name: --sound-match-${x.index}; --sounds-select-anchor: --sound-match-${x.index}`}\n :value=${(x) => x.matchMode}\n @change=${(x, c) => c.parent.onMatchModeChange(x.index, c.event)}\n >\n <rapid-option value=\"message\">MESSAGE text</rapid-option>\n <rapid-option value=\"header\">HEADER text</rapid-option>\n <rapid-option value=\"rule\">Notification rule</rapid-option>\n </rapid-select>\n </label>\n <label\n class=\"sound-rule-label\"\n style=${(x) => (x.matchMode === 'rule' ? 'display: none;' : '')}\n >\n ${(x) => (x.matchMode === 'header' ? 'HEADER text' : 'MESSAGE text')}\n <rapid-text-field\n class=\"pattern-input\"\n placeholder=${(x) =>\n x.matchMode === 'header' ? 'e.g. Price alert' : 'e.g. limit breached'}\n :value=${(x) => x.pattern}\n @input=${(x, c) => c.parent.onPatternInput(x.index, c.event)}\n ></rapid-text-field>\n </label>\n <label\n class=\"sound-rule-label\"\n style=${(x) => (x.matchMode === 'rule' ? '' : 'display: none;')}\n >\n Notification rule\n <rapid-select\n class=\"rule-select\"\n style=${(x) =>\n `anchor-name: --sound-rule-${x.index}; --sounds-select-anchor: --sound-rule-${x.index}`}\n :value=${(x) => x.templateId ?? ''}\n @change=${(x, c) => c.parent.onRuleChange(x.index, c.event)}\n >\n <options-datasource\n value-field=\"id\"\n label-field=\"name\"\n option-element=\"rapid-option\"\n :data=${(_, c) => c.parent.ruleSelectOptions}\n ></options-datasource>\n </rapid-select>\n </label>\n <label class=\"sound-rule-label\">\n Sound file\n <div class=\"sound-file-row\">\n <rapid-text-field\n class=\"sound-file-input\"\n readonly\n placeholder=\"No sound selected\"\n :value=${(x) => x.fileName ?? ''}\n title=${(x) => x.fileName ?? 'No sound selected'}\n >\n <rapid-icon\n slot=\"end\"\n class=\"choose-sound\"\n name=\"folder-open\"\n title=\"Choose alert sound\"\n @click=${(x, c) => {\n c.event.stopPropagation();\n return c.parent.openFilePicker(x.index);\n }}\n ></rapid-icon>\n </rapid-text-field>\n <rapid-button\n class=\"test-sound\"\n appearance=\"stealth\"\n title=\"Test play this sound\"\n ?disabled=${(x) => !x.hasSound}\n @click=${(x, c) => c.parent.testSound(x.index)}\n >\n <rapid-icon name=\"play\"></rapid-icon>\n </rapid-button>\n <rapid-button\n class=\"clear-sound\"\n appearance=\"stealth\"\n title=\"Clear sound file\"\n ?disabled=${(x) => !x.hasSound}\n @click=${(x, c) => c.parent.clearSound(x.index)}\n >\n <rapid-icon name=\"times\"></rapid-icon>\n </rapid-button>\n </div>\n </label>\n </div>\n `,\n )}\n </div>\n </div>\n <div class=\"sound-rules-footer\">\n <rapid-button\n class=\"add-rule\"\n appearance=\"lightweight\"\n title=\"Add sound rule\"\n ?disabled=${(x) => !x.canAddRule}\n @click=${(x) => x.addRule()}\n >\n <rapid-icon name=\"plus\"></rapid-icon>\n Add rule\n </rapid-button>\n <span class=\"rule-count\">${(x) => `${x.rules.length} / ${x.maxRules}`}</span>\n </div>\n </div>\n`"
3051
2876
  }
3052
2877
  ],
3053
2878
  "exports": [
3054
2879
  {
3055
2880
  "kind": "js",
3056
- "name": "FoundationNotificationDashboard",
3057
- "declaration": {
3058
- "name": "FoundationNotificationDashboard",
3059
- "module": "src/components/foundation-notification-dashboard/notification-dashboard.ts"
3060
- }
3061
- },
3062
- {
3063
- "kind": "custom-element-definition",
3064
- "name": "foundation-notification-dashboard",
2881
+ "name": "FoundationSoundsPanelTemplate",
3065
2882
  "declaration": {
3066
- "name": "FoundationNotificationDashboard",
3067
- "module": "src/components/foundation-notification-dashboard/notification-dashboard.ts"
2883
+ "name": "FoundationSoundsPanelTemplate",
2884
+ "module": "src/components/foundation-sounds/foundation-sounds-panel.template.ts"
3068
2885
  }
3069
2886
  }
3070
2887
  ]
3071
2888
  },
3072
2889
  {
3073
2890
  "kind": "javascript-module",
3074
- "path": "src/components/foundation-notification-dashboard/notification-dashboard.utils.ts",
2891
+ "path": "src/components/foundation-sounds/foundation-sounds-panel.ts",
3075
2892
  "declarations": [
3076
2893
  {
3077
2894
  "kind": "class",
3078
- "description": "",
3079
- "name": "UUIDGenerator",
2895
+ "description": "Configures alert sound rules in the inbox Sounds tab. Persists via the shared\nAlertSoundPlayer; playback is handled by layout-mounted\nFoundationSounds.",
2896
+ "name": "FoundationSoundsPanel",
3080
2897
  "members": [
3081
2898
  {
3082
2899
  "kind": "field",
3083
- "name": "uuid",
2900
+ "name": "ruleService",
3084
2901
  "type": {
3085
- "text": "UUID"
3086
- },
3087
- "privacy": "private",
3088
- "static": true
2902
+ "text": "RuleService"
2903
+ }
3089
2904
  },
3090
2905
  {
3091
2906
  "kind": "field",
3092
- "name": "createUUID",
3093
- "static": true
3094
- }
3095
- ]
3096
- },
3097
- {
3098
- "kind": "function",
3099
- "name": "isEmpty",
3100
- "parameters": [
2907
+ "name": "volumePercent",
2908
+ "type": {
2909
+ "text": "number"
2910
+ },
2911
+ "default": "100",
2912
+ "description": "Global playback volume 0–100. @internal"
2913
+ },
3101
2914
  {
3102
- "name": "value"
3103
- }
3104
- ]
3105
- },
3106
- {
3107
- "kind": "class",
3108
- "description": "",
3109
- "name": "DynamicRuleUtils",
3110
- "members": [
2915
+ "kind": "field",
2916
+ "name": "selectableRules",
2917
+ "type": {
2918
+ "text": "AlertSoundSelectableRule[]"
2919
+ },
2920
+ "default": "[]",
2921
+ "description": "Notification rules from REQ_NOTIFICATION_RULE. @internal"
2922
+ },
3111
2923
  {
3112
2924
  "kind": "field",
3113
- "name": "createEmptyCondition",
3114
- "static": true
2925
+ "name": "fileInput",
2926
+ "type": {
2927
+ "text": "HTMLInputElement"
2928
+ }
3115
2929
  },
3116
2930
  {
3117
2931
  "kind": "field",
3118
- "name": "createAssignment",
3119
- "static": true
2932
+ "name": "pendingRuleIndex",
2933
+ "type": {
2934
+ "text": "number | null"
2935
+ },
2936
+ "privacy": "private",
2937
+ "default": "null"
3120
2938
  },
3121
2939
  {
3122
2940
  "kind": "field",
3123
- "name": "createTextAssignment",
3124
- "static": true
2941
+ "name": "player",
2942
+ "privacy": "private",
2943
+ "readonly": true
3125
2944
  },
3126
2945
  {
3127
2946
  "kind": "field",
3128
- "name": "getAssignmentValue",
3129
- "static": true
2947
+ "name": "unsubscribePlayer",
2948
+ "type": {
2949
+ "text": "(() => void) | undefined"
2950
+ },
2951
+ "privacy": "private"
3130
2952
  },
3131
2953
  {
3132
2954
  "kind": "field",
3133
- "name": "getAssignmentText",
3134
- "static": true
2955
+ "name": "ignoreSelectChanges",
2956
+ "type": {
2957
+ "text": "boolean"
2958
+ },
2959
+ "privacy": "private",
2960
+ "default": "false",
2961
+ "description": "Suppresses select change events while options are rebuilt."
3135
2962
  },
3136
2963
  {
3137
2964
  "kind": "method",
3138
- "name": "createConditions",
3139
- "static": true,
2965
+ "name": "onMatchModeChange",
3140
2966
  "return": {
3141
2967
  "type": {
3142
- "text": "any"
2968
+ "text": "boolean"
3143
2969
  }
3144
2970
  },
3145
2971
  "parameters": [
3146
2972
  {
3147
- "name": "conditions",
2973
+ "name": "index",
3148
2974
  "type": {
3149
- "text": "ConditionNode[]"
2975
+ "text": "number"
3150
2976
  }
3151
2977
  },
3152
2978
  {
3153
- "name": "parameters",
3154
- "optional": true
2979
+ "name": "event",
2980
+ "type": {
2981
+ "text": "Event"
2982
+ }
3155
2983
  }
3156
2984
  ]
3157
2985
  },
3158
2986
  {
3159
2987
  "kind": "method",
3160
- "name": "hasMultiValueCondition",
3161
- "static": true,
2988
+ "name": "onPatternInput",
3162
2989
  "return": {
3163
2990
  "type": {
3164
2991
  "text": "boolean"
@@ -3166,17 +2993,22 @@
3166
2993
  },
3167
2994
  "parameters": [
3168
2995
  {
3169
- "name": "conditions",
2996
+ "name": "index",
3170
2997
  "type": {
3171
- "text": "ConditionNode[]"
2998
+ "text": "number"
2999
+ }
3000
+ },
3001
+ {
3002
+ "name": "event",
3003
+ "type": {
3004
+ "text": "Event"
3172
3005
  }
3173
3006
  }
3174
3007
  ]
3175
3008
  },
3176
3009
  {
3177
3010
  "kind": "method",
3178
- "name": "hasOrJoin",
3179
- "static": true,
3011
+ "name": "onRuleChange",
3180
3012
  "return": {
3181
3013
  "type": {
3182
3014
  "text": "boolean"
@@ -3184,17 +3016,22 @@
3184
3016
  },
3185
3017
  "parameters": [
3186
3018
  {
3187
- "name": "conditions",
3019
+ "name": "index",
3188
3020
  "type": {
3189
- "text": "ConditionNode[]"
3021
+ "text": "number"
3022
+ }
3023
+ },
3024
+ {
3025
+ "name": "event",
3026
+ "type": {
3027
+ "text": "Event"
3190
3028
  }
3191
3029
  }
3192
3030
  ]
3193
3031
  },
3194
3032
  {
3195
3033
  "kind": "method",
3196
- "name": "hasGroup",
3197
- "static": true,
3034
+ "name": "openFilePicker",
3198
3035
  "return": {
3199
3036
  "type": {
3200
3037
  "text": "boolean"
@@ -3202,17 +3039,16 @@
3202
3039
  },
3203
3040
  "parameters": [
3204
3041
  {
3205
- "name": "conditions",
3042
+ "name": "index",
3206
3043
  "type": {
3207
- "text": "ConditionNode[]"
3044
+ "text": "number"
3208
3045
  }
3209
3046
  }
3210
3047
  ]
3211
3048
  },
3212
3049
  {
3213
3050
  "kind": "method",
3214
- "name": "hasUnsupportedOperator",
3215
- "static": true,
3051
+ "name": "onFileSelected",
3216
3052
  "return": {
3217
3053
  "type": {
3218
3054
  "text": "boolean"
@@ -3220,256 +3056,420 @@
3220
3056
  },
3221
3057
  "parameters": [
3222
3058
  {
3223
- "name": "conditions",
3059
+ "name": "event",
3224
3060
  "type": {
3225
- "text": "ConditionNode[]"
3061
+ "text": "Event"
3226
3062
  }
3227
3063
  }
3228
3064
  ]
3229
3065
  },
3230
3066
  {
3231
3067
  "kind": "method",
3232
- "name": "flattenConditions",
3233
- "static": true,
3068
+ "name": "clearSound",
3234
3069
  "return": {
3235
3070
  "type": {
3236
- "text": "ConditionBuilderEntity[]"
3071
+ "text": "boolean"
3237
3072
  }
3238
3073
  },
3239
3074
  "parameters": [
3240
3075
  {
3241
- "name": "conditions",
3076
+ "name": "index",
3242
3077
  "type": {
3243
- "text": "ConditionNode[]"
3078
+ "text": "number"
3079
+ }
3080
+ }
3081
+ ]
3082
+ },
3083
+ {
3084
+ "kind": "method",
3085
+ "name": "testSound",
3086
+ "return": {
3087
+ "type": {
3088
+ "text": "boolean"
3089
+ }
3090
+ },
3091
+ "parameters": [
3092
+ {
3093
+ "name": "index",
3094
+ "type": {
3095
+ "text": "number"
3096
+ }
3097
+ }
3098
+ ]
3099
+ },
3100
+ {
3101
+ "kind": "method",
3102
+ "name": "toggleRuleMute",
3103
+ "return": {
3104
+ "type": {
3105
+ "text": "boolean"
3106
+ }
3107
+ },
3108
+ "parameters": [
3109
+ {
3110
+ "name": "index",
3111
+ "type": {
3112
+ "text": "number"
3113
+ }
3114
+ }
3115
+ ]
3116
+ },
3117
+ {
3118
+ "kind": "method",
3119
+ "name": "onVolumeChange",
3120
+ "return": {
3121
+ "type": {
3122
+ "text": "boolean"
3123
+ }
3124
+ },
3125
+ "parameters": [
3126
+ {
3127
+ "name": "event",
3128
+ "type": {
3129
+ "text": "Event"
3244
3130
  }
3245
3131
  }
3246
- ]
3132
+ ]
3133
+ },
3134
+ {
3135
+ "kind": "method",
3136
+ "name": "toggleMute",
3137
+ "return": {
3138
+ "type": {
3139
+ "text": "boolean"
3140
+ }
3141
+ }
3142
+ },
3143
+ {
3144
+ "kind": "method",
3145
+ "name": "addRule",
3146
+ "return": {
3147
+ "type": {
3148
+ "text": "boolean"
3149
+ }
3150
+ }
3151
+ },
3152
+ {
3153
+ "kind": "method",
3154
+ "name": "removeRule",
3155
+ "return": {
3156
+ "type": {
3157
+ "text": "boolean"
3158
+ }
3159
+ },
3160
+ "parameters": [
3161
+ {
3162
+ "name": "index",
3163
+ "type": {
3164
+ "text": "number"
3165
+ }
3166
+ }
3167
+ ]
3168
+ },
3169
+ {
3170
+ "kind": "method",
3171
+ "name": "reloadRules",
3172
+ "return": {
3173
+ "type": {
3174
+ "text": "Promise<void>"
3175
+ }
3176
+ },
3177
+ "description": "Reloads the notification-rule picker (e.g. when the Sounds tab is opened)."
3178
+ },
3179
+ {
3180
+ "kind": "method",
3181
+ "name": "loadRules",
3182
+ "privacy": "private",
3183
+ "return": {
3184
+ "type": {
3185
+ "text": "Promise<void>"
3186
+ }
3187
+ }
3188
+ },
3189
+ {
3190
+ "kind": "method",
3191
+ "name": "settleRuleOptions",
3192
+ "privacy": "private",
3193
+ "return": {
3194
+ "type": {
3195
+ "text": "Promise<void>"
3196
+ }
3197
+ },
3198
+ "description": "Suppresses select `change` events only while options-datasource rebuilds\nthe DOM — not for the `getRules()` round trip itself, so a user picking a\nrule while a request is in flight isn't silently dropped."
3247
3199
  },
3248
3200
  {
3249
3201
  "kind": "method",
3250
- "name": "resolveLeftValues",
3251
- "static": true,
3202
+ "name": "applyRuleSelectValues",
3203
+ "privacy": "private",
3252
3204
  "return": {
3253
3205
  "type": {
3254
- "text": "ConditionNode[]"
3206
+ "text": "void"
3255
3207
  }
3256
3208
  },
3257
- "parameters": [
3258
- {
3259
- "name": "conditions",
3260
- "type": {
3261
- "text": "ConditionNode[]"
3262
- }
3263
- },
3264
- {
3265
- "name": "fields",
3266
- "type": {
3267
- "text": "any[]"
3268
- }
3269
- }
3270
- ]
3271
- },
3272
- {
3273
- "kind": "field",
3274
- "name": "createEmptyGroup",
3275
- "static": true
3209
+ "description": "Re-applies persisted template ids onto `.rule-select` hosts after\noptions-datasource has rebuilt its options. We deliberately do *not* bind\n`:initialSelectedValue` to templateId: that path compares the option label\nagainst Select.value (the option id), always mismatches, clearData()'s the\nselect, and leaves the next pick stuck on \"Select a rule...\"."
3276
3210
  },
3277
3211
  {
3278
3212
  "kind": "method",
3279
- "name": "buildRawExpression",
3280
- "static": true,
3213
+ "name": "mapRules",
3214
+ "privacy": "private",
3281
3215
  "return": {
3282
3216
  "type": {
3283
- "text": "string"
3217
+ "text": "AlertSoundSelectableRule[]"
3284
3218
  }
3285
3219
  },
3286
3220
  "parameters": [
3287
3221
  {
3288
- "name": "conditions",
3222
+ "name": "ruleList",
3289
3223
  "type": {
3290
- "text": "ConditionNode[]"
3224
+ "text": "NamedRuleRow[]"
3291
3225
  }
3292
3226
  }
3293
3227
  ]
3294
3228
  },
3295
3229
  {
3296
3230
  "kind": "method",
3297
- "name": "parseRawExpression",
3298
- "static": true,
3231
+ "name": "ruleMatchId",
3232
+ "privacy": "private",
3299
3233
  "return": {
3300
3234
  "type": {
3301
- "text": "ConditionNode[] | null"
3235
+ "text": "string"
3302
3236
  }
3303
3237
  },
3304
3238
  "parameters": [
3305
3239
  {
3306
- "name": "rawExpression",
3240
+ "name": "rule",
3307
3241
  "type": {
3308
- "text": "string"
3242
+ "text": "NamedRuleRow | undefined"
3309
3243
  }
3310
3244
  }
3311
3245
  ]
3246
+ },
3247
+ {
3248
+ "kind": "method",
3249
+ "name": "syncSoundState",
3250
+ "privacy": "private"
3312
3251
  }
3313
- ]
3252
+ ],
3253
+ "superclass": {
3254
+ "name": "GenesisElement",
3255
+ "package": "@genesislcap/web-core"
3256
+ },
3257
+ "tagName": "foundation-sounds-panel",
3258
+ "customElement": true
3259
+ }
3260
+ ],
3261
+ "exports": [
3262
+ {
3263
+ "kind": "js",
3264
+ "name": "FoundationSoundsPanel",
3265
+ "declaration": {
3266
+ "name": "FoundationSoundsPanel",
3267
+ "module": "src/components/foundation-sounds/foundation-sounds-panel.ts"
3268
+ }
3314
3269
  },
3270
+ {
3271
+ "kind": "custom-element-definition",
3272
+ "name": "foundation-sounds-panel",
3273
+ "declaration": {
3274
+ "name": "FoundationSoundsPanel",
3275
+ "module": "src/components/foundation-sounds/foundation-sounds-panel.ts"
3276
+ }
3277
+ }
3278
+ ]
3279
+ },
3280
+ {
3281
+ "kind": "javascript-module",
3282
+ "path": "src/components/foundation-sounds/foundation-sounds.styles.ts",
3283
+ "declarations": [
3284
+ {
3285
+ "kind": "variable",
3286
+ "name": "FoundationSoundsStyles",
3287
+ "default": "css`\n :host {\n display: none;\n }\n`",
3288
+ "description": "Headless layout listener — take no space in the layout chrome."
3289
+ }
3290
+ ],
3291
+ "exports": [
3292
+ {
3293
+ "kind": "js",
3294
+ "name": "FoundationSoundsStyles",
3295
+ "declaration": {
3296
+ "name": "FoundationSoundsStyles",
3297
+ "module": "src/components/foundation-sounds/foundation-sounds.styles.ts"
3298
+ }
3299
+ }
3300
+ ]
3301
+ },
3302
+ {
3303
+ "kind": "javascript-module",
3304
+ "path": "src/components/foundation-sounds/foundation-sounds.ts",
3305
+ "declarations": [
3315
3306
  {
3316
3307
  "kind": "class",
3317
- "description": "",
3318
- "name": "TemplateUtils",
3308
+ "description": "Headless listener for inbox alert inserts. Plays configured sounds via the\nshared AlertSoundPlayer. Mount once in the app layout.\n\nConfigure rules in the inbox Sounds tab with FoundationSoundsPanel.",
3309
+ "name": "FoundationSounds",
3319
3310
  "members": [
3320
3311
  {
3321
3312
  "kind": "field",
3322
- "name": "createEmptyParameter",
3323
- "static": true
3313
+ "name": "connect",
3314
+ "type": {
3315
+ "text": "Connect"
3316
+ }
3324
3317
  },
3325
3318
  {
3326
- "kind": "method",
3327
- "name": "getParameters",
3328
- "static": true,
3329
- "parameters": [
3330
- {
3331
- "name": "parameters"
3332
- }
3333
- ]
3319
+ "kind": "field",
3320
+ "name": "inboxService",
3321
+ "type": {
3322
+ "text": "FoundationInboxService"
3323
+ }
3334
3324
  },
3335
3325
  {
3336
- "kind": "method",
3337
- "name": "buildRightValue",
3326
+ "kind": "field",
3327
+ "name": "ruleService",
3328
+ "type": {
3329
+ "text": "RuleService"
3330
+ }
3331
+ },
3332
+ {
3333
+ "kind": "field",
3334
+ "name": "soundEnabled",
3335
+ "type": {
3336
+ "text": "boolean"
3337
+ },
3338
+ "default": "true",
3339
+ "description": "When false, new audible alerts are tracked but do not play."
3340
+ },
3341
+ {
3342
+ "kind": "field",
3343
+ "name": "connectionSub",
3344
+ "type": {
3345
+ "text": "Subscription | undefined"
3346
+ },
3347
+ "privacy": "private"
3348
+ },
3349
+ {
3350
+ "kind": "field",
3351
+ "name": "player",
3338
3352
  "privacy": "private",
3339
- "static": true,
3340
- "parameters": [
3341
- {
3342
- "name": "logicalOperator",
3343
- "type": {
3344
- "text": "LogicalOperator"
3345
- }
3346
- },
3347
- {
3348
- "name": "condition"
3349
- },
3350
- {
3351
- "name": "parameters",
3352
- "optional": true
3353
- }
3354
- ]
3353
+ "readonly": true
3354
+ },
3355
+ {
3356
+ "kind": "field",
3357
+ "name": "knownAlertIds",
3358
+ "privacy": "private",
3359
+ "default": "new Set<string>()"
3360
+ },
3361
+ {
3362
+ "kind": "field",
3363
+ "name": "serverSoundFetches",
3364
+ "privacy": "private",
3365
+ "readonly": true,
3366
+ "default": "new Map<string, Promise<boolean>>()",
3367
+ "description": "In-flight server sound fetches keyed by DYNAMIC_RULE_ID."
3355
3368
  },
3356
3369
  {
3357
3370
  "kind": "method",
3358
- "name": "getConditions",
3359
- "static": true,
3360
- "parameters": [
3361
- {
3362
- "name": "conditions"
3363
- },
3364
- {
3365
- "name": "parameters",
3366
- "optional": true
3371
+ "name": "subscribeToAlerts",
3372
+ "privacy": "private",
3373
+ "return": {
3374
+ "type": {
3375
+ "text": "void"
3367
3376
  }
3368
- ]
3377
+ }
3378
+ },
3379
+ {
3380
+ "kind": "field",
3381
+ "name": "subscriptionHandler",
3382
+ "privacy": "private"
3369
3383
  },
3370
3384
  {
3371
3385
  "kind": "method",
3372
- "name": "createParameterDetails",
3373
- "static": true,
3386
+ "name": "playForNewAlerts",
3387
+ "privacy": "private",
3388
+ "return": {
3389
+ "type": {
3390
+ "text": "Promise<void>"
3391
+ }
3392
+ },
3374
3393
  "parameters": [
3375
3394
  {
3376
- "name": "parameters"
3395
+ "name": "rows",
3396
+ "type": {
3397
+ "text": "Array<{\n id: string;\n message?: string;\n header?: string;\n dynamicRuleId?: string;\n }>"
3398
+ }
3377
3399
  }
3378
3400
  ]
3379
- }
3380
- ]
3381
- },
3382
- {
3383
- "kind": "class",
3384
- "description": "",
3385
- "name": "RuleUtils",
3386
- "members": [
3401
+ },
3387
3402
  {
3388
3403
  "kind": "method",
3389
- "name": "buildRightValue",
3404
+ "name": "tryPlayServerSound",
3390
3405
  "privacy": "private",
3391
- "static": true,
3406
+ "return": {
3407
+ "type": {
3408
+ "text": "Promise<boolean>"
3409
+ }
3410
+ },
3392
3411
  "parameters": [
3393
3412
  {
3394
- "name": "logicalOperator",
3413
+ "name": "dynamicRuleId",
3395
3414
  "type": {
3396
- "text": "LogicalOperator"
3415
+ "text": "string"
3397
3416
  }
3398
- },
3399
- {
3400
- "name": "condition"
3401
3417
  }
3402
3418
  ]
3403
3419
  },
3404
3420
  {
3405
3421
  "kind": "method",
3406
- "name": "getConditions",
3407
- "static": true,
3422
+ "name": "fetchAndCacheServerSound",
3423
+ "privacy": "private",
3424
+ "return": {
3425
+ "type": {
3426
+ "text": "Promise<boolean>"
3427
+ }
3428
+ },
3408
3429
  "parameters": [
3409
3430
  {
3410
- "name": "conditions"
3431
+ "name": "dynamicRuleId",
3432
+ "type": {
3433
+ "text": "string"
3434
+ }
3411
3435
  }
3412
3436
  ]
3413
3437
  }
3414
- ]
3415
- },
3416
- {
3417
- "kind": "function",
3418
- "name": "showNotificationError",
3419
- "parameters": [
3438
+ ],
3439
+ "attributes": [
3420
3440
  {
3421
- "name": "error"
3441
+ "name": "sound-enabled",
3442
+ "type": {
3443
+ "text": "boolean"
3444
+ },
3445
+ "default": "true",
3446
+ "description": "When false, new audible alerts are tracked but do not play.",
3447
+ "fieldName": "soundEnabled"
3422
3448
  }
3423
- ]
3449
+ ],
3450
+ "superclass": {
3451
+ "name": "GenesisElement",
3452
+ "package": "@genesislcap/web-core"
3453
+ },
3454
+ "tagName": "foundation-sounds",
3455
+ "customElement": true
3424
3456
  }
3425
3457
  ],
3426
3458
  "exports": [
3427
3459
  {
3428
3460
  "kind": "js",
3429
- "name": "UUIDGenerator",
3430
- "declaration": {
3431
- "name": "UUIDGenerator",
3432
- "module": "src/components/foundation-notification-dashboard/notification-dashboard.utils.ts"
3433
- }
3434
- },
3435
- {
3436
- "kind": "js",
3437
- "name": "isEmpty",
3438
- "declaration": {
3439
- "name": "isEmpty",
3440
- "module": "src/components/foundation-notification-dashboard/notification-dashboard.utils.ts"
3441
- }
3442
- },
3443
- {
3444
- "kind": "js",
3445
- "name": "DynamicRuleUtils",
3446
- "declaration": {
3447
- "name": "DynamicRuleUtils",
3448
- "module": "src/components/foundation-notification-dashboard/notification-dashboard.utils.ts"
3449
- }
3450
- },
3451
- {
3452
- "kind": "js",
3453
- "name": "TemplateUtils",
3454
- "declaration": {
3455
- "name": "TemplateUtils",
3456
- "module": "src/components/foundation-notification-dashboard/notification-dashboard.utils.ts"
3457
- }
3458
- },
3459
- {
3460
- "kind": "js",
3461
- "name": "RuleUtils",
3461
+ "name": "FoundationSounds",
3462
3462
  "declaration": {
3463
- "name": "RuleUtils",
3464
- "module": "src/components/foundation-notification-dashboard/notification-dashboard.utils.ts"
3463
+ "name": "FoundationSounds",
3464
+ "module": "src/components/foundation-sounds/foundation-sounds.ts"
3465
3465
  }
3466
3466
  },
3467
3467
  {
3468
- "kind": "js",
3469
- "name": "showNotificationError",
3468
+ "kind": "custom-element-definition",
3469
+ "name": "foundation-sounds",
3470
3470
  "declaration": {
3471
- "name": "showNotificationError",
3472
- "module": "src/components/foundation-notification-dashboard/notification-dashboard.utils.ts"
3471
+ "name": "FoundationSounds",
3472
+ "module": "src/components/foundation-sounds/foundation-sounds.ts"
3473
3473
  }
3474
3474
  }
3475
3475
  ]
@@ -4229,95 +4229,6 @@
4229
4229
  }
4230
4230
  ]
4231
4231
  },
4232
- {
4233
- "kind": "javascript-module",
4234
- "path": "src/components/foundation-notification-dashboard/styles/condition-builder.styles.ts",
4235
- "declarations": [
4236
- {
4237
- "kind": "variable",
4238
- "name": "ConditionBuilderStyles",
4239
- "default": "css`\n .condition-builder {\n display: flex;\n gap: calc(var(--design-unit) * 2px);\n align-items: center;\n margin-bottom: calc(var(--design-unit) * 2px);\n }\n\n rapid-button {\n margin: 0;\n }\n\n /* The AND/OR toggle sits on its own row ABOVE the condition it joins,\n rendered as a pair of small text links rather than buttons - reads like\n a sentence connector (\"... and ...\") instead of a UI control competing\n with the row's fields for attention. */\n .join-toggle-row {\n display: flex;\n margin-bottom: calc(var(--design-unit) * 1px);\n }\n\n .join-toggle {\n display: flex;\n gap: calc(var(--design-unit) * 1.5px);\n }\n\n .join-text {\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.02em;\n color: var(--accent-fill-rest);\n cursor: pointer;\n text-decoration: underline dotted;\n text-underline-offset: 3px;\n opacity: 40%;\n }\n\n .join-text:hover {\n opacity: 70%;\n }\n\n .join-text.active {\n opacity: 100%;\n text-decoration: underline solid;\n }\n\n .join-text.active:hover {\n opacity: 100%;\n }\n\n .delete {\n margin: 0;\n display: flex;\n justify-content: center;\n height: calc(var(--design-unit) * 9px);\n }\n\n .delete:hover {\n background-color: color-mix(in srgb, var(--neutral-foreground-rest), transparent 89%);\n }\n\n rapid-text-field {\n width: 100%;\n margin-bottom: 0;\n }\n\n rapid-text-field::part(root) {\n height: calc(var(--design-unit) * 9px);\n }\n\n rapid-select {\n min-width: auto;\n }\n\n rapid-select.left-value::part(control) {\n width: 250px;\n }\n\n rapid-select.logical-operator::part(control) {\n width: 160px;\n }\n\n .logical-operator-null-and-blank {\n width: 100%;\n }\n\n rapid-select.right-criteria::part(control) {\n width: 135px;\n }\n\n rapid-select.right-criteria-user-entry {\n width: 100%;\n }\n\n rapid-select.right-criteria-select {\n width: 100%;\n min-width: 0;\n }\n\n rapid-select::part(listbox) {\n max-height: 160px;\n }\n`"
4240
- },
4241
- {
4242
- "kind": "variable",
4243
- "name": "ConditionGroupStyles",
4244
- "default": "css`\n .condition-group-row {\n margin-bottom: calc(var(--design-unit) * 2px);\n }\n\n /* The AND/OR toggle sits on its own row ABOVE the group it joins - see\n ConditionBuilderStyles' .join-toggle-row/.join-text for why it's a pair\n of text links rather than buttons. */\n .join-toggle-row {\n display: flex;\n margin-bottom: calc(var(--design-unit) * 1px);\n }\n\n .join-toggle {\n display: flex;\n gap: calc(var(--design-unit) * 1.5px);\n }\n\n .join-text {\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.02em;\n color: var(--accent-fill-rest);\n cursor: pointer;\n text-decoration: underline dotted;\n text-underline-offset: 3px;\n opacity: 40%;\n }\n\n .join-text:hover {\n opacity: 70%;\n }\n\n .join-text.active {\n opacity: 100%;\n text-decoration: underline solid;\n }\n\n .join-text.active:hover {\n opacity: 100%;\n }\n\n /* A full bordered box reads as \"this is one parenthesized unit\" more\n literally than a left rail - it nests naturally too, a group inside a\n group just gets a second box drawn inside the first, like actual nested\n parens would look. */\n .condition-group-box {\n flex: 1;\n min-width: 0;\n border: calc(var(--design-unit) * 0.5px) solid\n color-mix(in srgb, var(--accent-fill-rest), transparent 25%);\n border-radius: calc(var(--design-unit) * 1px);\n padding: calc(var(--design-unit) * 2px);\n background-color: color-mix(in srgb, var(--accent-fill-rest), transparent 96%);\n }\n\n .condition-group-box > .content-row {\n display: flex;\n gap: calc(var(--design-unit) * 2px);\n align-items: center;\n margin-top: calc(var(--design-unit) * 1px);\n }\n\n .condition-group-box > .content-row rapid-button {\n font-size: 12px;\n }\n\n rule-condition-builder,\n rule-condition-group,\n template-condition-builder,\n template-condition-group {\n display: block;\n margin-bottom: calc(var(--design-unit) * 1px);\n }\n\n .delete-group {\n margin: 0;\n opacity: 60%;\n }\n\n .delete-group:hover {\n opacity: 100%;\n }\n`"
4245
- }
4246
- ],
4247
- "exports": [
4248
- {
4249
- "kind": "js",
4250
- "name": "ConditionBuilderStyles",
4251
- "declaration": {
4252
- "name": "ConditionBuilderStyles",
4253
- "module": "src/components/foundation-notification-dashboard/styles/condition-builder.styles.ts"
4254
- }
4255
- },
4256
- {
4257
- "kind": "js",
4258
- "name": "ConditionGroupStyles",
4259
- "declaration": {
4260
- "name": "ConditionGroupStyles",
4261
- "module": "src/components/foundation-notification-dashboard/styles/condition-builder.styles.ts"
4262
- }
4263
- }
4264
- ]
4265
- },
4266
- {
4267
- "kind": "javascript-module",
4268
- "path": "src/components/foundation-notification-dashboard/styles/dynamic-rule.styles.ts",
4269
- "declarations": [
4270
- {
4271
- "kind": "variable",
4272
- "name": "DynamicRuleManagementStyles",
4273
- "default": "css`\n .container {\n display: flex;\n height: 100%;\n flex-direction: column;\n }\n\n .header {\n display: flex;\n flex-direction: row-reverse;\n }\n\n .grid {\n height: 100%;\n }\n`"
4274
- },
4275
- {
4276
- "kind": "variable",
4277
- "name": "DynamicRuleDialogStyles",
4278
- "default": "css`\n ${scrollbarStyles}\n ${top}\n ${bottom}\n\n rapid-modal::part(dialog) {\n padding: 0;\n background: var(--neutral-layer-4);\n border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);\n }\n\n .dialog-content {\n display: flex;\n flex-direction: column;\n width: ${String(modalWidthPx)}px;\n max-height: 600px;\n overflow-y: scroll;\n gap: calc(var(--design-unit) * 3px);\n padding: calc(var(--design-unit) * 4px);\n }\n\n .content-row {\n display: flex;\n gap: calc(var(--design-unit) * 3px);\n }\n\n .control {\n display: flex;\n flex-direction: column;\n width: 100%;\n gap: calc(var(--design-unit) * 2px);\n }\n\n .items {\n border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);\n border-radius: calc(var(--control-corner-radius) * 1px);\n display: flex;\n padding: calc(var(--design-unit) * 2px);\n flex-direction: column;\n }\n\n .item {\n gap: 0;\n flex-direction: column;\n margin-bottom: 0;\n }\n\n ${textField}\n ${select}\n\n rapid-button {\n margin: 0;\n }\n\n rapid-select {\n min-width: 0;\n }\n\n rapid-select::part(listbox) {\n max-height: 160px;\n }\n\n .horizontal {\n flex-direction: row;\n }\n\n .destination {\n align-self: center;\n }\n\n .topic {\n min-width: revert-layer;\n }\n\n .expression-preview {\n width: 100%;\n margin-top: calc(var(--design-unit) * 2px);\n }\n\n .expression-preview::part(control) {\n font-family: var(--body-font, monospace);\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n min-height: calc(var(--design-unit) * 12px);\n resize: vertical;\n }\n\n .alert-sound {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n margin-top: calc(var(--design-unit) * 2px);\n }\n\n .alert-sound .file-input {\n display: none;\n }\n\n .alert-sound-row {\n display: flex;\n align-items: center;\n gap: calc(var(--design-unit) * 2px);\n flex-wrap: wrap;\n border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);\n border-radius: calc(var(--control-corner-radius) * 1px);\n padding: calc(var(--design-unit) * 2px);\n }\n\n .alert-sound-name {\n flex: 1;\n min-width: 120px;\n color: var(--neutral-foreground-hint);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n`"
4279
- }
4280
- ],
4281
- "exports": [
4282
- {
4283
- "kind": "js",
4284
- "name": "DynamicRuleManagementStyles",
4285
- "declaration": {
4286
- "name": "DynamicRuleManagementStyles",
4287
- "module": "src/components/foundation-notification-dashboard/styles/dynamic-rule.styles.ts"
4288
- }
4289
- },
4290
- {
4291
- "kind": "js",
4292
- "name": "DynamicRuleDialogStyles",
4293
- "declaration": {
4294
- "name": "DynamicRuleDialogStyles",
4295
- "module": "src/components/foundation-notification-dashboard/styles/dynamic-rule.styles.ts"
4296
- }
4297
- }
4298
- ]
4299
- },
4300
- {
4301
- "kind": "javascript-module",
4302
- "path": "src/components/foundation-notification-dashboard/styles/management.styles.ts",
4303
- "declarations": [
4304
- {
4305
- "kind": "variable",
4306
- "name": "managementGridStyles",
4307
- "default": "css`\n :host {\n height: 100%;\n }\n\n .container {\n display: flex;\n height: 100%;\n flex-direction: column;\n }\n\n .header {\n display: flex;\n }\n\n .grid {\n height: 100%;\n }\n`"
4308
- }
4309
- ],
4310
- "exports": [
4311
- {
4312
- "kind": "js",
4313
- "name": "managementGridStyles",
4314
- "declaration": {
4315
- "name": "managementGridStyles",
4316
- "module": "src/components/foundation-notification-dashboard/styles/management.styles.ts"
4317
- }
4318
- }
4319
- ]
4320
- },
4321
4232
  {
4322
4233
  "kind": "javascript-module",
4323
4234
  "path": "src/components/foundation-notification-dashboard/types/expression-type.ts",
@@ -4918,6 +4829,95 @@
4918
4829
  }
4919
4830
  ]
4920
4831
  },
4832
+ {
4833
+ "kind": "javascript-module",
4834
+ "path": "src/components/foundation-notification-dashboard/styles/condition-builder.styles.ts",
4835
+ "declarations": [
4836
+ {
4837
+ "kind": "variable",
4838
+ "name": "ConditionBuilderStyles",
4839
+ "default": "css`\n .condition-builder {\n display: flex;\n gap: calc(var(--design-unit) * 2px);\n align-items: center;\n margin-bottom: calc(var(--design-unit) * 2px);\n }\n\n rapid-button {\n margin: 0;\n }\n\n /* The AND/OR toggle sits on its own row ABOVE the condition it joins,\n rendered as a pair of small text links rather than buttons - reads like\n a sentence connector (\"... and ...\") instead of a UI control competing\n with the row's fields for attention. */\n .join-toggle-row {\n display: flex;\n margin-bottom: calc(var(--design-unit) * 1px);\n }\n\n .join-toggle {\n display: flex;\n gap: calc(var(--design-unit) * 1.5px);\n }\n\n .join-text {\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.02em;\n color: var(--accent-fill-rest);\n cursor: pointer;\n text-decoration: underline dotted;\n text-underline-offset: 3px;\n opacity: 40%;\n }\n\n .join-text:hover {\n opacity: 70%;\n }\n\n .join-text.active {\n opacity: 100%;\n text-decoration: underline solid;\n }\n\n .join-text.active:hover {\n opacity: 100%;\n }\n\n .delete {\n margin: 0;\n display: flex;\n justify-content: center;\n height: calc(var(--design-unit) * 9px);\n }\n\n .delete:hover {\n background-color: color-mix(in srgb, var(--neutral-foreground-rest), transparent 89%);\n }\n\n rapid-text-field {\n width: 100%;\n margin-bottom: 0;\n }\n\n rapid-text-field::part(root) {\n height: calc(var(--design-unit) * 9px);\n }\n\n rapid-select {\n min-width: auto;\n }\n\n rapid-select.left-value::part(control) {\n width: 250px;\n }\n\n rapid-select.logical-operator::part(control) {\n width: 160px;\n }\n\n .logical-operator-null-and-blank {\n width: 100%;\n }\n\n rapid-select.right-criteria::part(control) {\n width: 135px;\n }\n\n rapid-select.right-criteria-user-entry {\n width: 100%;\n }\n\n rapid-select.right-criteria-select {\n width: 100%;\n min-width: 0;\n }\n\n rapid-select::part(listbox) {\n max-height: 160px;\n }\n`"
4840
+ },
4841
+ {
4842
+ "kind": "variable",
4843
+ "name": "ConditionGroupStyles",
4844
+ "default": "css`\n .condition-group-row {\n margin-bottom: calc(var(--design-unit) * 2px);\n }\n\n /* The AND/OR toggle sits on its own row ABOVE the group it joins - see\n ConditionBuilderStyles' .join-toggle-row/.join-text for why it's a pair\n of text links rather than buttons. */\n .join-toggle-row {\n display: flex;\n margin-bottom: calc(var(--design-unit) * 1px);\n }\n\n .join-toggle {\n display: flex;\n gap: calc(var(--design-unit) * 1.5px);\n }\n\n .join-text {\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.02em;\n color: var(--accent-fill-rest);\n cursor: pointer;\n text-decoration: underline dotted;\n text-underline-offset: 3px;\n opacity: 40%;\n }\n\n .join-text:hover {\n opacity: 70%;\n }\n\n .join-text.active {\n opacity: 100%;\n text-decoration: underline solid;\n }\n\n .join-text.active:hover {\n opacity: 100%;\n }\n\n /* A full bordered box reads as \"this is one parenthesized unit\" more\n literally than a left rail - it nests naturally too, a group inside a\n group just gets a second box drawn inside the first, like actual nested\n parens would look. */\n .condition-group-box {\n flex: 1;\n min-width: 0;\n border: calc(var(--design-unit) * 0.5px) solid\n color-mix(in srgb, var(--accent-fill-rest), transparent 25%);\n border-radius: calc(var(--design-unit) * 1px);\n padding: calc(var(--design-unit) * 2px);\n background-color: color-mix(in srgb, var(--accent-fill-rest), transparent 96%);\n }\n\n .condition-group-box > .content-row {\n display: flex;\n gap: calc(var(--design-unit) * 2px);\n align-items: center;\n margin-top: calc(var(--design-unit) * 1px);\n }\n\n .condition-group-box > .content-row rapid-button {\n font-size: 12px;\n }\n\n rule-condition-builder,\n rule-condition-group,\n template-condition-builder,\n template-condition-group {\n display: block;\n margin-bottom: calc(var(--design-unit) * 1px);\n }\n\n .delete-group {\n margin: 0;\n opacity: 60%;\n }\n\n .delete-group:hover {\n opacity: 100%;\n }\n`"
4845
+ }
4846
+ ],
4847
+ "exports": [
4848
+ {
4849
+ "kind": "js",
4850
+ "name": "ConditionBuilderStyles",
4851
+ "declaration": {
4852
+ "name": "ConditionBuilderStyles",
4853
+ "module": "src/components/foundation-notification-dashboard/styles/condition-builder.styles.ts"
4854
+ }
4855
+ },
4856
+ {
4857
+ "kind": "js",
4858
+ "name": "ConditionGroupStyles",
4859
+ "declaration": {
4860
+ "name": "ConditionGroupStyles",
4861
+ "module": "src/components/foundation-notification-dashboard/styles/condition-builder.styles.ts"
4862
+ }
4863
+ }
4864
+ ]
4865
+ },
4866
+ {
4867
+ "kind": "javascript-module",
4868
+ "path": "src/components/foundation-notification-dashboard/styles/dynamic-rule.styles.ts",
4869
+ "declarations": [
4870
+ {
4871
+ "kind": "variable",
4872
+ "name": "DynamicRuleManagementStyles",
4873
+ "default": "css`\n .container {\n display: flex;\n height: 100%;\n flex-direction: column;\n }\n\n .header {\n display: flex;\n flex-direction: row-reverse;\n }\n\n .grid {\n height: 100%;\n }\n`"
4874
+ },
4875
+ {
4876
+ "kind": "variable",
4877
+ "name": "DynamicRuleDialogStyles",
4878
+ "default": "css`\n ${scrollbarStyles}\n ${top}\n ${bottom}\n\n rapid-modal::part(dialog) {\n padding: 0;\n background: var(--neutral-layer-4);\n border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);\n }\n\n .dialog-content {\n display: flex;\n flex-direction: column;\n width: ${String(modalWidthPx)}px;\n max-height: 600px;\n overflow-y: scroll;\n gap: calc(var(--design-unit) * 3px);\n padding: calc(var(--design-unit) * 4px);\n }\n\n .content-row {\n display: flex;\n gap: calc(var(--design-unit) * 3px);\n }\n\n .control {\n display: flex;\n flex-direction: column;\n width: 100%;\n gap: calc(var(--design-unit) * 2px);\n }\n\n .items {\n border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);\n border-radius: calc(var(--control-corner-radius) * 1px);\n display: flex;\n padding: calc(var(--design-unit) * 2px);\n flex-direction: column;\n }\n\n .item {\n gap: 0;\n flex-direction: column;\n margin-bottom: 0;\n }\n\n ${textField}\n ${select}\n\n rapid-button {\n margin: 0;\n }\n\n rapid-select {\n min-width: 0;\n }\n\n rapid-select::part(listbox) {\n max-height: 160px;\n }\n\n .horizontal {\n flex-direction: row;\n }\n\n .destination {\n align-self: center;\n }\n\n .topic {\n min-width: revert-layer;\n }\n\n .expression-preview {\n width: 100%;\n margin-top: calc(var(--design-unit) * 2px);\n }\n\n .expression-preview::part(control) {\n font-family: var(--body-font, monospace);\n font-size: 12px;\n color: var(--neutral-foreground-hint);\n min-height: calc(var(--design-unit) * 12px);\n resize: vertical;\n }\n\n .alert-sound {\n display: flex;\n flex-direction: column;\n gap: calc(var(--design-unit) * 2px);\n margin-top: calc(var(--design-unit) * 2px);\n }\n\n .alert-sound .file-input {\n display: none;\n }\n\n .alert-sound-row {\n display: flex;\n align-items: center;\n gap: calc(var(--design-unit) * 2px);\n flex-wrap: wrap;\n border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest);\n border-radius: calc(var(--control-corner-radius) * 1px);\n padding: calc(var(--design-unit) * 2px);\n }\n\n .alert-sound-name {\n flex: 1;\n min-width: 120px;\n color: var(--neutral-foreground-hint);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n`"
4879
+ }
4880
+ ],
4881
+ "exports": [
4882
+ {
4883
+ "kind": "js",
4884
+ "name": "DynamicRuleManagementStyles",
4885
+ "declaration": {
4886
+ "name": "DynamicRuleManagementStyles",
4887
+ "module": "src/components/foundation-notification-dashboard/styles/dynamic-rule.styles.ts"
4888
+ }
4889
+ },
4890
+ {
4891
+ "kind": "js",
4892
+ "name": "DynamicRuleDialogStyles",
4893
+ "declaration": {
4894
+ "name": "DynamicRuleDialogStyles",
4895
+ "module": "src/components/foundation-notification-dashboard/styles/dynamic-rule.styles.ts"
4896
+ }
4897
+ }
4898
+ ]
4899
+ },
4900
+ {
4901
+ "kind": "javascript-module",
4902
+ "path": "src/components/foundation-notification-dashboard/styles/management.styles.ts",
4903
+ "declarations": [
4904
+ {
4905
+ "kind": "variable",
4906
+ "name": "managementGridStyles",
4907
+ "default": "css`\n :host {\n height: 100%;\n }\n\n .container {\n display: flex;\n height: 100%;\n flex-direction: column;\n }\n\n .header {\n display: flex;\n }\n\n .grid {\n height: 100%;\n }\n`"
4908
+ }
4909
+ ],
4910
+ "exports": [
4911
+ {
4912
+ "kind": "js",
4913
+ "name": "managementGridStyles",
4914
+ "declaration": {
4915
+ "name": "managementGridStyles",
4916
+ "module": "src/components/foundation-notification-dashboard/styles/management.styles.ts"
4917
+ }
4918
+ }
4919
+ ]
4920
+ },
4921
4921
  {
4922
4922
  "kind": "javascript-module",
4923
4923
  "path": "src/components/foundation-inbox/components/foundation-inbox-counter/foundation-inbox-counter.styles.ts",