Skip to content

Commit 144bbe0

Browse files
committed
Merge feature/v2.1.0-quick-wins: Configurable settings and UX improvements
Closes #20, Closes #11 Features: - Configurable title display duration (5, 10, 15, or 30 seconds) - Flash on meeting start option (default off) - Shows 'Please Setup' for unconfigured plugins Bug fixes: - Fixed title display duration bug (was showing minutes instead of seconds) - Fixed startup race condition causing buttons to get stuck on Loading
2 parents 2f845f0 + 7e5bb33 commit 144bbe0

File tree

15 files changed

+663
-41
lines changed

15 files changed

+663
-41
lines changed

.github/copilot-instructions.md

Lines changed: 124 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,11 @@ Checkboxes require specific HTML structure for SDPI styling:
145145
When checking boolean settings, handle `undefined` for backwards compatibility:
146146

147147
```typescript
148-
// undefined = true (default), false = false, true = true
149-
const setting = value === undefined ? true : Boolean(value);
148+
// excludeAllDay: undefined = true (default on), false = false, true = true
149+
const excludeAllDay = value === undefined ? true : Boolean(value);
150+
151+
// flashOnMeetingStart: undefined = false (default off), must explicitly be true
152+
const flashEnabled = settings.flashOnMeetingStart === true;
150153
```
151154

152155
## Common Issues
@@ -158,6 +161,8 @@ const setting = value === undefined ? true : Boolean(value);
158161
| Checkbox not visible | Wrong SDPI HTML structure | Use `type="checkbox"` on parent div, label with span |
159162
| Debug panel always showing | `display: block` hardcoded | Set `display: none`, show only when `isDebugMode` |
160163
| Outlook times wrong | Windows timezone not mapped | Check `timezone-service.ts` mapping |
164+
| Buttons stuck on "Loading" | Startup race condition | `waitForCacheAndStart` uses 500ms polling with `actionRef` fallback |
165+
| Title shows for too long | Duration multiplied twice | `getTitleDisplayDuration()` returns seconds, caller multiplies by 1000 |
161166

162167
## File Locations
163168

@@ -170,44 +175,142 @@ const setting = value === undefined ? true : Boolean(value);
170175

171176
## Release Process
172177

173-
### Creating a Release Package
178+
### Complete Release Workflow
179+
180+
Follow these steps in order for a complete release:
181+
182+
#### 1. Pre-Release Checklist
183+
184+
```powershell
185+
# Ensure all tests pass
186+
npm test
187+
188+
# Ensure you're on the feature branch with all changes committed
189+
git status
190+
git log --oneline -5
191+
```
192+
193+
#### 2. Update Version Numbers
194+
195+
Update version in both files (must match):
196+
- `manifest.json`: 4-part version `"Version": "X.Y.Z.0"`
197+
- `package.json`: 3-part version `"version": "X.Y.Z"`
198+
199+
#### 3. Merge Feature Branch to Main
200+
201+
```powershell
202+
# Switch to main and pull latest
203+
git checkout main
204+
git pull origin main
205+
206+
# Merge feature branch (use --no-ff to preserve history)
207+
# Include issue references to auto-close them
208+
git merge --no-ff feature/vX.Y.Z-branch-name -m "Merge feature/vX.Y.Z-branch-name: Brief description
209+
210+
Closes #XX, Closes #YY"
211+
212+
# Push to main
213+
git push origin main
214+
```
215+
216+
#### 4. Create Release Package
174217

175218
**CRITICAL**: Always use the Stream Deck CLI to create packages. Manual zipping will create invalid packages.
176219

177220
```powershell
178-
# 1. Build for production (outputs to release/ folder)
221+
# Build for production (outputs to release/ folder)
179222
npm run build:production
180223
181-
# 2. Create package using Stream Deck CLI
224+
# Create package using Stream Deck CLI
182225
streamdeck pack "release/com.pedrofuentes.ical.sdPlugin" --output release
183226
184-
# 3. Creates: release/com.pedrofuentes.ical.streamDeckPlugin
227+
# Verify package was created
228+
Get-Item "release/com.pedrofuentes.ical.streamDeckPlugin"
185229
```
186230

187-
### Creating a GitHub Release
231+
#### 5. Test the Package (Optional but Recommended)
188232

189233
```powershell
190-
# 1. Create annotated tag
191-
git tag -a vX.Y.Z -m "vX.Y.Z - Description"
234+
# Remove dev plugin and test the package
235+
Stop-Process -Name "StreamDeck" -Force
236+
Remove-Item "$env:APPDATA\Elgato\StreamDeck\Plugins\com.pedrofuentes.ical.sdPlugin" -Recurse -Force
237+
Start-Process "$env:ProgramFiles\Elgato\StreamDeck\StreamDeck.exe"
238+
# Then double-click the .streamDeckPlugin file to install and verify it works
239+
```
240+
241+
#### 6. Create Git Tag
242+
243+
```powershell
244+
# Create annotated tag on main branch
245+
git tag -a vX.Y.Z -m "vX.Y.Z - Brief description of release"
246+
247+
# Push tag to remote
192248
git push origin vX.Y.Z
249+
```
250+
251+
#### 7. Create GitHub Release
193252

194-
# 2. Create release with plugin package
253+
**IMPORTANT**: Use GitHub keywords to automatically close related issues. Include `Closes #X`, `Fixes #X`, or `Resolves #X` in the release notes for each issue addressed.
254+
255+
```powershell
256+
# Create release with plugin package attached
195257
gh release create vX.Y.Z "release/com.pedrofuentes.ical.streamDeckPlugin" `
196-
--title "vX.Y.Z - Title" `
197-
--notes "Release notes"
258+
--title "vX.Y.Z - Release Title" `
259+
--notes "## What's New
260+
261+
- ✨ Feature 1 (Closes #XX)
262+
- ✨ Feature 2 (Closes #YY)
263+
- 🐛 Bug fix 1 (Fixes #ZZ)
264+
265+
## Installation
266+
267+
Download the \`.streamDeckPlugin\` file and double-click to install."
198268
```
199269

200-
### Testing Before Release
270+
Or create manually on GitHub:
271+
1. Go to https://github.com/pedrofuentes/stream-deck-ical/releases/new
272+
2. Choose the tag `vX.Y.Z`
273+
3. Set release title
274+
4. Add release notes with `Closes #X` or `Fixes #X` for each issue
275+
5. Attach `release/com.pedrofuentes.ical.streamDeckPlugin`
276+
6. Publish release
277+
278+
### Automatic Issue Closing
279+
280+
GitHub automatically closes issues when these keywords are used in:
281+
- **Commit messages** merged to main: `git commit -m "feat: add feature X (Closes #123)"`
282+
- **PR descriptions**: Include `Closes #123` in the PR body
283+
- **Release notes**: Issues are closed when the release is published
284+
285+
**Keywords** (case-insensitive):
286+
- `Closes #X` / `Close #X`
287+
- `Fixes #X` / `Fix #X`
288+
- `Resolves #X` / `Resolve #X`
289+
290+
**Multiple issues**: `Closes #11, Closes #20` or `Fixes #11, #20`
291+
292+
#### 8. Post-Release Cleanup
201293

202294
```powershell
203-
# Remove dev plugin and test the package
204-
Stop-Process -Name "StreamDeck" -Force
205-
Remove-Item "$env:APPDATA\Elgato\StreamDeck\Plugins\com.pedrofuentes.ical.sdPlugin" -Recurse -Force
206-
Start-Process "$env:ProgramFiles\Elgato\StreamDeck\StreamDeck.exe"
207-
# Then double-click the .streamDeckPlugin file to install
295+
# Delete merged feature branch (optional)
296+
git branch -d feature/vX.Y.Z-branch-name
297+
git push origin --delete feature/vX.Y.Z-branch-name
298+
299+
# Re-link development plugin if needed
300+
streamdeck link "dist/com.pedrofuentes.ical.sdPlugin"
208301
```
209302

210-
### Version Numbers
303+
### Quick Reference Commands
211304

212-
- `manifest.json`: 4-part version `"Version": "X.Y.Z.0"`
213-
- `package.json`: 3-part version `"version": "X.Y.Z"`
305+
```powershell
306+
# Full release sequence (after testing is complete)
307+
git checkout main
308+
git pull origin main
309+
git merge --no-ff feature/vX.Y.Z-name -m "Merge feature/vX.Y.Z-name"
310+
git push origin main
311+
npm run build:production
312+
streamdeck pack "release/com.pedrofuentes.ical.sdPlugin" --output release
313+
git tag -a vX.Y.Z -m "vX.Y.Z - Description"
314+
git push origin vX.Y.Z
315+
gh release create vX.Y.Z "release/com.pedrofuentes.ical.streamDeckPlugin" --title "vX.Y.Z" --notes "Release notes"
316+
```

README.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ iCal Plugin for [elgato Stream Deck](https://www.elgato.com/en/gaming/stream-dec
66

77
This plugin is available on the Stream Deck store, you can also download [the last release](https://github.com/pedrofuentes/stream-deck-ical/releases) or build it yourself using the code on this repo.
88

9+
## ✨ New in v2.1
10+
11+
-**Configurable Title Display**: Choose how long meeting titles show (5, 10, 15, or 30 seconds)
12+
-**Meeting Start Flash**: Optional visual alert when meetings begin
13+
-**Improved Startup**: Faster button initialization with better status messages
14+
-**Better UX**: Shows "Please Setup" for unconfigured plugins
15+
916
## ✨ New in v2.0
1017

1118
-**Recurring Events Support**: Daily, weekly, monthly recurring events with RRULE
@@ -36,8 +43,10 @@ This plugin is available on the Stream Deck store, you can also download [the la
3643
### Next Meeting ###
3744
* Shows time left until next meeting starts
3845
* If the button is pushed it will show the title of the next meeting (scrolling marquee)
46+
* **Configurable duration**: Choose 5, 10, 15, or 30 seconds for title display
3947
* If the button is pushed while the text is showing it will go back to show the time left until the next meeting
4048
* At the end of the title animation, the button will go back to show the time left until the next meeting
49+
* **Optional flash alert** when meetings are about to start (disabled by default)
4150
* Changes icon color to orange when there are 5 minutes left for the next meeting to start
4251
* Changes icon color to red when there are 30 seconds left for the next meeting to start
4352

@@ -106,8 +115,10 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup instructions.
106115
3. Click "Settings" button
107116
4. Enter your iCal URL
108117
5. Choose time window (1, 3, 5, or 7 days)
109-
6. Optionally uncheck "Exclude All-Day Events" to show all-day events
110-
7. Click "Save Settings"
118+
6. Set title display duration (5, 10, 15, or 30 seconds)
119+
7. Optionally enable "Flash when meeting starts" for visual alerts
120+
8. Optionally uncheck "Exclude All-Day Events" to show all-day events
121+
9. Click "Save Settings"
111122

112123
## Troubleshooting
113124

@@ -155,6 +166,14 @@ We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for:
155166

156167
## Changelog
157168

169+
### v2.1.0 (2026)
170+
-**Configurable Title Display Duration**: Choose 5, 10, 15, or 30 seconds (#20)
171+
-**Flash on Meeting Start**: Optional visual alert when meetings begin (#11)
172+
- 🐛 Fixed title display duration bug (was showing for minutes instead of seconds)
173+
- 🐛 Fixed startup race condition causing buttons to get stuck on "Loading"
174+
- 🐛 Improved status messages: Shows "Please Setup" for unconfigured plugins
175+
- ✅ Added 18 new regression tests for v2.1.0 features
176+
158177
### v2.0.0 (2026)
159178
-**Major Update**: Migrated to Node.js SDK v2
160179
- ✨ Added recurring events support (RRULE, EXDATE)

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"CategoryIcon": "assets/icalIcon",
4141
"URL": "https://github.com/pedrofuentes/stream-deck-ical#readme",
4242
"PropertyInspectorPath": "pi.html",
43-
"Version": "2.0.0.0",
43+
"Version": "2.1.0.0",
4444
"Nodejs": {
4545
"Version": "20",
4646
"Debug": "enabled"

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "stream-deck-ical",
3-
"version": "2.0.0",
3+
"version": "2.1.0",
44
"description": "An elgato Stream Deck plugin that displays information from your calendar using an iCal URL. Visual cues and a countdown will help you end meetings on time and be ready for the next one.",
55
"private": true,
66
"type": "module",

pi/setup.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,24 @@
3737
</div>
3838
</div>
3939

40+
<div class="sdpi-item">
41+
<div class="sdpi-item-label">Title Display</div>
42+
<select id="titleDisplayDuration" class="sdpi-item-value select">
43+
<option value="5">5 seconds</option>
44+
<option value="10">10 seconds</option>
45+
<option value="15" selected>15 seconds</option>
46+
<option value="30">30 seconds</option>
47+
</select>
48+
</div>
49+
50+
<div class="sdpi-item" type="checkbox">
51+
<div class="sdpi-item-label">Meeting Alert</div>
52+
<div class="sdpi-item-value">
53+
<input type="checkbox" id="flashOnMeetingStart">
54+
<label for="flashOnMeetingStart"><span></span>Flash when meeting starts</label>
55+
</div>
56+
</div>
57+
4058
<div class="sdpi-item">
4159
<button class="sdpi-item-value" id="save">Save Settings</button>
4260
<button class="sdpi-item-value" id="refresh">Force Refresh &#128472;</button>
@@ -45,6 +63,8 @@
4563
<div class="sdpi-heading">Features</div>
4664
<div class="content">
4765
<ul>
66+
<li><strong>New:</strong> Configurable title display duration (5, 10, 15, or 30 seconds)</li>
67+
<li><strong>New:</strong> Flash button when meeting starts (can be disabled)</li>
4868
<li><strong>New:</strong> Support for recurring events (daily, weekly, monthly, etc.)</li>
4969
<li><strong>New:</strong> Configurable time window (1, 3, 5, or 7 days)</li>
5070
<li><strong>New:</strong> Improved timezone handling for Outlook, Google, and Apple calendars</li>

pi/setup.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ function saveUrl() {
4444
const timeWindow = parseInt(document.getElementById('timeWindow').value, 10);
4545
const excludeAllDayEl = document.getElementById('excludeAllDay');
4646
const excludeAllDay = excludeAllDayEl ? excludeAllDayEl.checked : true;
47+
const titleDisplayDurationEl = document.getElementById('titleDisplayDuration');
48+
const titleDisplayDuration = titleDisplayDurationEl ? parseInt(titleDisplayDurationEl.value, 10) : 15;
49+
const flashOnMeetingStartEl = document.getElementById('flashOnMeetingStart');
50+
const flashOnMeetingStart = flashOnMeetingStartEl ? flashOnMeetingStartEl.checked : true;
4751

4852
if (!url) {
4953
showAlert('Please enter an iCal URL');
@@ -62,6 +66,8 @@ function saveUrl() {
6266
url: url,
6367
timeWindow: timeWindow,
6468
excludeAllDay: excludeAllDay,
69+
titleDisplayDuration: titleDisplayDuration,
70+
flashOnMeetingStart: flashOnMeetingStart,
6571
urlVersion: (opener.globalSettings.urlVersion || 0) + 1
6672
};
6773

@@ -152,6 +158,17 @@ document.addEventListener('DOMContentLoaded', function() {
152158
// Default to true if not set
153159
excludeAllDayCheckbox.checked = opener.globalSettings.excludeAllDay !== false;
154160
}
161+
162+
// New settings
163+
const titleDisplayDurationSelect = document.getElementById('titleDisplayDuration');
164+
if (titleDisplayDurationSelect) {
165+
titleDisplayDurationSelect.value = opener.globalSettings.titleDisplayDuration || 15;
166+
}
167+
const flashOnMeetingStartCheckbox = document.getElementById('flashOnMeetingStart');
168+
if (flashOnMeetingStartCheckbox) {
169+
// Default to true if not set
170+
flashOnMeetingStartCheckbox.checked = opener.globalSettings.flashOnMeetingStart === true;
171+
}
155172
}
156173

157174
// Add event listeners

0 commit comments

Comments
 (0)