mirror of
https://github.com/runbear-io/beardrive.git
synced 2026-08-25 08:08:08 +02:00
fix(webapp): show how many times a public link has been opened (BEA-76) (#125)
Every /s/<token> hit was already recorded as a share-kind read, carrying
both a count and a timestamp — and then thrown away at the UI layer. The
Public links table showed only who shared a file and when, six inches
below a file header that already said "1 shared". Two personas filed it
independently on the same tour.
The number now rides the shares list:
* ReadLedger.ShareOpens(project) aggregates share-kind buckets per path,
all-time. Share-kind only is what makes Last mean *last opened* —
HeatEntry.LastRead is cross-kind, so a member viewing the file in the
hub would otherwise move the date.
* shareJSON takes the project's opens map, built ONCE per project by the
caller and indexed per row. Both callers — the project list and the
org-wide audit — hoist it above their loops; a per-share call would be
a full byKey scan per row.
* Counts, never openers. The share actor is token+"/"+IP, a public
credential joined to an IP, and it stays in the ledger. There is no
distinct-openers field, deliberately.
* Reads off means the keys are ABSENT, not zero: `0` would claim nobody
has opened a link on a hub that never looked.
shareDetail() is the leverage — the settings table, the org-wide audit and
the file page's share banner all render through it, so one string function
covers three surfaces. Once the row carried the receipt it truncated to
"3 op…", so the detail cell wraps instead of ellipsizing; the path keeps
its ellipsis, since it is a link with a tooltip and the column that can be
arbitrarily long.
Counted per FILE, not per link: heat is keyed by path, so two tokens on one
file report the same number. Worded that way in the section copy, alongside
the other honesty — opens are debounced visits, not requests.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
119d4abf79
commit
826d13795f
@@ -265,6 +265,7 @@ classDiagram
|
||||
-byKey, dirty, seen
|
||||
+Record(...)
|
||||
+Heat(project, prefix, days)
|
||||
+ShareOpens(project)
|
||||
}
|
||||
class ReadStat {
|
||||
+Project +Path +Day +Kind +Actor +Count +Last
|
||||
@@ -272,6 +273,10 @@ classDiagram
|
||||
class HeatEntry {
|
||||
+Human +Agent +Share +Readers +LastRead
|
||||
}
|
||||
class ShareOpen {
|
||||
+Count +Last
|
||||
}
|
||||
note for ShareOpen "The receipt on a public link: share-kind buckets only, which is what makes Last mean last OPENED — HeatEntry.LastRead is cross-kind, so a member viewing the file in the hub would otherwise move the date. Counts, never openers: the share actor is token+IP. Keyed by path, so two tokens on one file report the same number. Callers build the map ONCE per project and index it; a per-share call is a full byKey scan per row"
|
||||
|
||||
class QuotaProvider {
|
||||
<<interface>>
|
||||
@@ -371,6 +376,8 @@ classDiagram
|
||||
RemoteSource ..> sourcedOp : attribution comes from the journal key
|
||||
ReadLedger ..> ReadStat
|
||||
ReadLedger ..> HeatEntry
|
||||
ReadLedger ..> ShareOpen
|
||||
ShareDB ..> ShareOpen : shares list joins the open count per path
|
||||
QuotaProvider <|.. UnlimitedQuota
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user