133 lines
3.7 KiB
Go
133 lines
3.7 KiB
Go
// Package dummydata is a development-only data source that emits a hardcoded
|
|
// set of ClassMessage graph nodes to exercise the Conversations UI without
|
|
// needing a real data export. Triggered by any file named
|
|
// IMPORT_FOR_DUMMY_DATA.txt; the file contents are ignored.
|
|
package dummydata
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/timelinize/timelinize/timeline"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func init() {
|
|
err := timeline.RegisterDataSource(timeline.DataSource{
|
|
Name: "dummy_data",
|
|
Title: "Dummy Data",
|
|
Description: "Emits hardcoded message graphs for UI development. Triggered by IMPORT_FOR_DUMMY_DATA.txt.",
|
|
NewFileImporter: func() timeline.FileImporter { return new(Importer) },
|
|
})
|
|
if err != nil {
|
|
timeline.Log.Fatal("registering data source", zap.Error(err))
|
|
}
|
|
}
|
|
|
|
// Importer is the dummy data importer.
|
|
type Importer struct{}
|
|
|
|
// Recognize returns a confident match for any file named IMPORT_FOR_DUMMY_DATA.txt.
|
|
func (Importer) Recognize(_ context.Context, dirEntry timeline.DirEntry, _ timeline.RecognizeParams) (timeline.Recognition, error) {
|
|
if strings.EqualFold(dirEntry.Name(), "IMPORT_FOR_DUMMY_DATA.txt") {
|
|
return timeline.Recognition{Confidence: 1}, nil
|
|
}
|
|
return timeline.Recognition{}, nil
|
|
}
|
|
|
|
// FileImport emits a hardcoded conversation between three participants.
|
|
// The file contents are ignored.
|
|
func (imp *Importer) FileImport(ctx context.Context, _ timeline.DirEntry, params timeline.ImportParams) error {
|
|
alice := entity("Alice Smith", "alice.smith")
|
|
bob := entity("Bob Jones", "bob.jones")
|
|
charlie := entity("Charlie Lee", "charlie.lee")
|
|
|
|
type msg struct {
|
|
sender timeline.Entity
|
|
recipients []timeline.Entity
|
|
text string
|
|
ts time.Time
|
|
}
|
|
|
|
base := time.Date(2024, 6, 14, 10, 0, 0, 0, time.UTC)
|
|
|
|
messages := []msg{
|
|
{
|
|
sender: alice,
|
|
recipients: []timeline.Entity{bob, charlie},
|
|
text: "Hey everyone, are we still on for Friday?",
|
|
ts: base,
|
|
},
|
|
{
|
|
sender: bob,
|
|
recipients: []timeline.Entity{alice, charlie},
|
|
text: "Yep! I'll be there. Should I bring anything?",
|
|
ts: base.Add(3 * time.Minute),
|
|
},
|
|
{
|
|
sender: charlie,
|
|
recipients: []timeline.Entity{alice, bob},
|
|
text: "Really sorry, I can't make it this time 😢",
|
|
ts: base.Add(7 * time.Minute),
|
|
},
|
|
{
|
|
sender: alice,
|
|
recipients: []timeline.Entity{bob, charlie},
|
|
text: "Aw no! We'll miss you Charlie. Bob, just bring yourself 😄",
|
|
ts: base.Add(9 * time.Minute),
|
|
},
|
|
{
|
|
sender: bob,
|
|
recipients: []timeline.Entity{alice, charlie},
|
|
text: "Sounds good, see you Friday Alice!",
|
|
ts: base.Add(12 * time.Minute),
|
|
},
|
|
{
|
|
sender: charlie,
|
|
recipients: []timeline.Entity{alice, bob},
|
|
text: "Have fun you two! Let's catch up the week after.",
|
|
ts: base.Add(15 * time.Minute),
|
|
},
|
|
}
|
|
|
|
for _, m := range messages {
|
|
if err := ctx.Err(); err != nil {
|
|
return err
|
|
}
|
|
|
|
item := &timeline.Item{
|
|
Classification: timeline.ClassMessage,
|
|
Timestamp: m.ts,
|
|
Owner: m.sender,
|
|
Content: timeline.ItemData{
|
|
Data: timeline.StringData(m.text),
|
|
MediaType: "text/plain",
|
|
},
|
|
}
|
|
|
|
g := &timeline.Graph{Item: item}
|
|
for _, recip := range m.recipients {
|
|
r := recip // avoid loop-variable capture
|
|
g.ToEntity(timeline.RelSent, &r)
|
|
}
|
|
|
|
params.Pipeline <- g
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// entity constructs a named Entity with a datasource-scoped identity attribute.
|
|
func entity(name, handle string) timeline.Entity {
|
|
return timeline.Entity{
|
|
Name: name,
|
|
Attributes: []timeline.Attribute{
|
|
{
|
|
Name: "dummy_handle",
|
|
Value: handle,
|
|
Identity: true,
|
|
},
|
|
},
|
|
}
|
|
}
|