Skip to content

Commit 558e613

Browse files
author
Developer
committed
More select fields, show checked/live timestamps
1 parent b9db0b7 commit 558e613

File tree

8 files changed

+169
-35
lines changed

8 files changed

+169
-35
lines changed

app/assets/builds/application.js

Lines changed: 54 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/assets/builds/application.js.map

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/helpers/application_helper.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,9 @@ def user_color(user)
33
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E2']
44
colors[user.id % colors.length]
55
end
6+
7+
def time_ago_in_words_with_nil(time)
8+
return 'Never' if time.nil?
9+
"#{time_ago_in_words(time)} ago"
10+
end
611
end

app/javascript/controllers/collaborative_spreadsheet/action_cable_manager.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,15 @@ export class ActionCableManager {
4747
case 'cell_updated':
4848
this.controller.cellRenderer.updateCell(data.cell_id, data.field, data.value, data.stream_id)
4949
break
50+
case 'stream_updated':
51+
// Handle updates to non-editable fields like last_checked_at and last_live_at
52+
if (data.last_checked_at !== undefined) {
53+
this.controller.cellRenderer.updateTimeAgoField(data.stream_id, 'last_checked_at', data.last_checked_at)
54+
}
55+
if (data.last_live_at !== undefined) {
56+
this.controller.cellRenderer.updateTimeAgoField(data.stream_id, 'last_live_at', data.last_live_at)
57+
}
58+
break
5059
}
5160
}
5261
}

app/javascript/controllers/collaborative_spreadsheet/cell_editor.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@ export class CellEditor {
2525
if (fieldType === 'select') {
2626
this.controller.cellRenderer.showSelectDropdown(cell)
2727
} else {
28-
// For status field and other fields with special formatting,
29-
// replace content with plain text for editing
30-
if (field === 'status') {
31-
const currentValue = cell.dataset.originalValue || cell.textContent.trim()
32-
cell.textContent = currentValue
33-
}
34-
3528
// Make cell editable
3629
cell.contentEditable = true
3730
cell.focus()
@@ -73,11 +66,6 @@ export class CellEditor {
7366
// Make cell non-editable
7467
cell.contentEditable = false
7568

76-
// For status field, restore the formatted display with current value
77-
if (field === 'status') {
78-
this.controller.cellRenderer.formatStatusCell(cell)
79-
}
80-
8169
// Clear edit timeout
8270
this.controller.editTimeoutManager.clearEditTimeout(cellId)
8371
}

app/javascript/controllers/collaborative_spreadsheet/cell_renderer.js

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,59 @@ export class CellRenderer {
112112
cell.appendChild(span)
113113
}
114114

115+
updateTimeAgoField(streamId, field, timeValue) {
116+
const elementId = `stream_${streamId}_${field}`
117+
const element = document.getElementById(elementId)
118+
if (!element) {
119+
console.warn(`Time field element not found: ${elementId}`)
120+
return
121+
}
122+
123+
// Update the time display
124+
if (timeValue) {
125+
const date = new Date(timeValue)
126+
const now = new Date()
127+
const diffSeconds = Math.floor((now - date) / 1000)
128+
129+
let timeAgo = ''
130+
if (diffSeconds < 60) {
131+
timeAgo = 'less than a minute ago'
132+
} else if (diffSeconds < 3600) {
133+
const minutes = Math.floor(diffSeconds / 60)
134+
timeAgo = `${minutes} ${minutes === 1 ? 'minute' : 'minutes'} ago`
135+
} else if (diffSeconds < 86400) {
136+
const hours = Math.floor(diffSeconds / 3600)
137+
timeAgo = `${hours} ${hours === 1 ? 'hour' : 'hours'} ago`
138+
} else {
139+
const days = Math.floor(diffSeconds / 86400)
140+
timeAgo = `${days} ${days === 1 ? 'day' : 'days'} ago`
141+
}
142+
143+
element.textContent = timeAgo
144+
} else {
145+
element.textContent = 'Never'
146+
}
147+
148+
// Flash update animation
149+
element.classList.add('bg-green-50')
150+
setTimeout(() => {
151+
element.classList.remove('bg-green-50')
152+
}, 500)
153+
}
154+
115155
showSelectDropdown(cell) {
116156
const cellId = cell.dataset.cellId
117-
const currentValue = cell.dataset.originalValue || cell.textContent.trim()
157+
const field = cell.dataset.field
158+
let currentValue = cell.dataset.originalValue || cell.textContent.trim()
159+
160+
// For status field, get the actual value from the span
161+
if (field === 'status') {
162+
const span = cell.querySelector('span')
163+
if (span) {
164+
currentValue = span.textContent.trim()
165+
}
166+
}
167+
118168
const selectOptions = JSON.parse(cell.dataset.selectOptions || '{}')
119169

120170
// Create dropdown container
@@ -202,7 +252,11 @@ export class CellRenderer {
202252

203253
// Update cell display but NOT the originalValue yet
204254
// Let saveCell handle updating originalValue after successful save
205-
cell.textContent = newValue
255+
if (field === 'status') {
256+
this.formatStatusCell(cell, newValue)
257+
} else {
258+
cell.textContent = newValue
259+
}
206260

207261
// Save the change
208262
this.controller.cellEditor.saveCell(cell)

app/models/stream.rb

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ class Stream < ApplicationRecord
6262

6363
# Callbacks for broadcasting
6464
after_create_commit -> { broadcast_prepend_later_to "streams", target: "streams", partial: "admin/streams/stream", locals: { stream: self } }
65-
after_update_commit -> { broadcast_replace_later_to "streams", target: "stream_#{id}", partial: "admin/streams/stream", locals: { stream: self } }
65+
after_update_commit -> {
66+
broadcast_replace_later_to "streams", target: "stream_#{id}", partial: "admin/streams/stream", locals: { stream: self }
67+
broadcast_time_updates if saved_change_to_last_checked_at? || saved_change_to_last_live_at?
68+
}
6669
after_destroy_commit -> { broadcast_remove_to "streams", target: "stream_#{id}" }
6770

6871
# Validations
@@ -212,6 +215,15 @@ def duration_in_words
212215
end
213216
end
214217

218+
def broadcast_time_updates
219+
ActionCable.server.broadcast('collaborative_streams', {
220+
action: 'stream_updated',
221+
stream_id: id,
222+
last_checked_at: last_checked_at&.iso8601,
223+
last_live_at: last_live_at&.iso8601
224+
})
225+
end
226+
215227
private
216228

217229
def normalize_link

app/views/admin/streams/_spreadsheet.html.erb

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@
5050
<th scope="col" class="px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
5151
Started At
5252
</th>
53+
<th scope="col" class="px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
54+
Last Checked
55+
</th>
56+
<th scope="col" class="px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
57+
Last Live
58+
</th>
5359
<th scope="col" class="px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
5460
Actions
5561
</th>
@@ -114,7 +120,9 @@
114120
data-cell-id="stream_<%= stream.id %>_platform"
115121
data-stream-id="<%= stream.id %>"
116122
data-field="platform"
123+
data-field-type="select"
117124
data-original-value="<%= stream.platform %>"
125+
data-select-options='<%= Stream.platforms.to_json %>'
118126
class="text-sm text-gray-900 cursor-pointer hover:bg-gray-100 px-2 py-1 rounded transition-colors min-h-[1.5rem]">
119127
<%= stream.platform || '-' %>
120128
</div>
@@ -126,7 +134,9 @@
126134
data-cell-id="stream_<%= stream.id %>_status"
127135
data-stream-id="<%= stream.id %>"
128136
data-field="status"
137+
data-field-type="select"
129138
data-original-value="<%= stream.status %>"
139+
data-select-options='<%= Stream.statuses.to_json %>'
130140
class="text-sm cursor-pointer hover:bg-gray-100 px-2 py-1 rounded transition-colors min-h-[1.5rem]">
131141
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full
132142
<%= stream.status == 'Live' ? 'bg-green-100 text-green-800' :
@@ -181,24 +191,35 @@
181191
data-cell-id="stream_<%= stream.id %>_orientation"
182192
data-stream-id="<%= stream.id %>"
183193
data-field="orientation"
194+
data-field-type="select"
184195
data-original-value="<%= stream.orientation %>"
196+
data-select-options='<%= Stream.orientations.to_json %>'
185197
class="text-sm text-gray-900 cursor-pointer hover:bg-gray-100 px-2 py-1 rounded transition-colors min-h-[1.5rem]">
186198
<%= stream.orientation || '-' %>
187199
</div>
188200
</td>
189201

190-
<!-- Started At -->
191-
<td class="px-3 py-4 whitespace-nowrap relative">
192-
<div data-collaborative-spreadsheet-target="cell"
193-
data-cell-id="stream_<%= stream.id %>_started_at"
194-
data-stream-id="<%= stream.id %>"
195-
data-field="started_at"
196-
data-original-value="<%= stream.started_at&.iso8601 %>"
197-
class="text-sm text-gray-500 cursor-pointer hover:bg-gray-100 px-2 py-1 rounded transition-colors min-h-[1.5rem]">
202+
<!-- Started At (non-editable) -->
203+
<td class="px-3 py-4 whitespace-nowrap">
204+
<div class="text-sm text-gray-500 px-2 py-1">
198205
<%= stream.started_at&.strftime('%b %d, %Y %I:%M %p') || '-' %>
199206
</div>
200207
</td>
201208

209+
<!-- Last Checked (non-editable) -->
210+
<td class="px-3 py-4 whitespace-nowrap">
211+
<div id="stream_<%= stream.id %>_last_checked_at" class="text-sm text-gray-500 px-2 py-1">
212+
<%= time_ago_in_words_with_nil(stream.last_checked_at) %>
213+
</div>
214+
</td>
215+
216+
<!-- Last Live (non-editable) -->
217+
<td class="px-3 py-4 whitespace-nowrap">
218+
<div id="stream_<%= stream.id %>_last_live_at" class="text-sm text-gray-500 px-2 py-1">
219+
<%= time_ago_in_words_with_nil(stream.last_live_at) %>
220+
</div>
221+
</td>
222+
202223
<!-- Actions -->
203224
<td class="px-3 py-4 whitespace-nowrap text-right text-sm font-medium">
204225
<div class="flex items-center space-x-2">

0 commit comments

Comments
 (0)