Compare commits
2 Commits
f386e0b574
...
e8dcb5fcaf
| Author | SHA1 | Date | |
|---|---|---|---|
|
e8dcb5fcaf
|
|||
|
b41e8c330a
|
@@ -130,7 +130,7 @@ async fn list_sources(
|
|||||||
) -> Result<Json<Vec<SourceSummary>>, ApiError> {
|
) -> Result<Json<Vec<SourceSummary>>, ApiError> {
|
||||||
let summaries = state
|
let summaries = state
|
||||||
.store
|
.store
|
||||||
.source_summaries(/* include_private */ false)
|
.source_summaries(/* include_private */ true)
|
||||||
.await
|
.await
|
||||||
.map_err(internal)?;
|
.map_err(internal)?;
|
||||||
Ok(Json(summaries))
|
Ok(Json(summaries))
|
||||||
@@ -155,7 +155,7 @@ async fn daily_counts(
|
|||||||
) -> Result<Json<Vec<DailyCount>>, ApiError> {
|
) -> Result<Json<Vec<DailyCount>>, ApiError> {
|
||||||
let to = params.to.unwrap_or_else(|| Utc::now().date_naive());
|
let to = params.to.unwrap_or_else(|| Utc::now().date_naive());
|
||||||
let from = params.from.unwrap_or_else(|| to - chrono::Duration::days(365));
|
let from = params.from.unwrap_or_else(|| to - chrono::Duration::days(365));
|
||||||
let counts = state.store.daily_counts(from, to).await.map_err(internal)?;
|
let counts = state.store.daily_counts(from, to, /* include_private */ true).await.map_err(internal)?;
|
||||||
Ok(Json(counts))
|
Ok(Json(counts))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ async fn language_daily_counts(
|
|||||||
) -> Result<Json<Vec<LanguageDailyCount>>, ApiError> {
|
) -> Result<Json<Vec<LanguageDailyCount>>, ApiError> {
|
||||||
let to = params.to.unwrap_or_else(|| Utc::now().date_naive());
|
let to = params.to.unwrap_or_else(|| Utc::now().date_naive());
|
||||||
let from = params.from.unwrap_or_else(|| to - chrono::Duration::days(365));
|
let from = params.from.unwrap_or_else(|| to - chrono::Duration::days(365));
|
||||||
let counts = state.store.language_daily_counts(from, to).await.map_err(internal)?;
|
let counts = state.store.language_daily_counts(from, to, /* include_private */ true).await.map_err(internal)?;
|
||||||
Ok(Json(counts))
|
Ok(Json(counts))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ async fn og_contributions(
|
|||||||
// Get date range from source summaries
|
// Get date range from source summaries
|
||||||
let summaries = state
|
let summaries = state
|
||||||
.store
|
.store
|
||||||
.source_summaries(false)
|
.source_summaries(/* include_private */ true)
|
||||||
.await
|
.await
|
||||||
.map_err(internal)?;
|
.map_err(internal)?;
|
||||||
let earliest = summaries
|
let earliest = summaries
|
||||||
@@ -195,7 +195,7 @@ async fn og_contributions(
|
|||||||
|
|
||||||
let counts = state
|
let counts = state
|
||||||
.store
|
.store
|
||||||
.daily_counts(earliest, today)
|
.daily_counts(earliest, today, /* include_private */ true)
|
||||||
.await
|
.await
|
||||||
.map_err(internal)?;
|
.map_err(internal)?;
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ pub trait EventReader: Send + Sync {
|
|||||||
async fn list_events(&self, query: &EventQuery) -> Result<Vec<Event>, StoreError>;
|
async fn list_events(&self, query: &EventQuery) -> Result<Vec<Event>, StoreError>;
|
||||||
async fn source_summaries(&self, include_private: bool) -> Result<Vec<SourceSummary>, StoreError>;
|
async fn source_summaries(&self, include_private: bool) -> Result<Vec<SourceSummary>, StoreError>;
|
||||||
async fn list_projects(&self) -> Result<Vec<ProjectSummary>, StoreError>;
|
async fn list_projects(&self) -> Result<Vec<ProjectSummary>, StoreError>;
|
||||||
async fn daily_counts(&self, from: NaiveDate, to: NaiveDate) -> Result<Vec<DailyCount>, StoreError>;
|
async fn daily_counts(&self, from: NaiveDate, to: NaiveDate, include_private: bool) -> Result<Vec<DailyCount>, StoreError>;
|
||||||
async fn language_daily_counts(&self, from: NaiveDate, to: NaiveDate) -> Result<Vec<LanguageDailyCount>, StoreError>;
|
async fn language_daily_counts(&self, from: NaiveDate, to: NaiveDate, include_private: bool) -> Result<Vec<LanguageDailyCount>, StoreError>;
|
||||||
async fn repo_languages(&self) -> Result<Vec<RepoLanguage>, StoreError>;
|
async fn repo_languages(&self) -> Result<Vec<RepoLanguage>, StoreError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ impl EventReader for PgStore {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn daily_counts(&self, from: NaiveDate, to: NaiveDate) -> Result<Vec<DailyCount>, StoreError> {
|
async fn daily_counts(&self, from: NaiveDate, to: NaiveDate, include_private: bool) -> Result<Vec<DailyCount>, StoreError> {
|
||||||
let rows = sqlx::query(
|
let rows = sqlx::query(
|
||||||
r#"
|
r#"
|
||||||
SELECT d::date AS date,
|
SELECT d::date AS date,
|
||||||
@@ -205,13 +205,14 @@ impl EventReader for PgStore {
|
|||||||
LEFT JOIN events e
|
LEFT JOIN events e
|
||||||
ON e.occurred_at >= (d::date || 'T00:00:00Z')::timestamptz
|
ON e.occurred_at >= (d::date || 'T00:00:00Z')::timestamptz
|
||||||
AND e.occurred_at < ((d::date + 1) || 'T00:00:00Z')::timestamptz
|
AND e.occurred_at < ((d::date + 1) || 'T00:00:00Z')::timestamptz
|
||||||
AND e.public = true
|
AND ($3::bool OR e.public = true)
|
||||||
GROUP BY d::date
|
GROUP BY d::date
|
||||||
ORDER BY d::date
|
ORDER BY d::date
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
.bind(from)
|
.bind(from)
|
||||||
.bind(to)
|
.bind(to)
|
||||||
|
.bind(include_private)
|
||||||
.fetch_all(&self.pool)
|
.fetch_all(&self.pool)
|
||||||
.await
|
.await
|
||||||
.map_err(map_err)?;
|
.map_err(map_err)?;
|
||||||
@@ -226,7 +227,7 @@ impl EventReader for PgStore {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn language_daily_counts(&self, from: NaiveDate, to: NaiveDate) -> Result<Vec<LanguageDailyCount>, StoreError> {
|
async fn language_daily_counts(&self, from: NaiveDate, to: NaiveDate, include_private: bool) -> Result<Vec<LanguageDailyCount>, StoreError> {
|
||||||
let rows = sqlx::query(
|
let rows = sqlx::query(
|
||||||
r#"
|
r#"
|
||||||
SELECT date, language, color,
|
SELECT date, language, color,
|
||||||
@@ -244,7 +245,7 @@ impl EventReader for PgStore {
|
|||||||
JOIN events e
|
JOIN events e
|
||||||
ON e.occurred_at >= (d::date || 'T00:00:00Z')::timestamptz
|
ON e.occurred_at >= (d::date || 'T00:00:00Z')::timestamptz
|
||||||
AND e.occurred_at < ((d::date + 1) || 'T00:00:00Z')::timestamptz
|
AND e.occurred_at < ((d::date + 1) || 'T00:00:00Z')::timestamptz
|
||||||
AND e.public = true
|
AND ($3::bool OR e.public = true)
|
||||||
AND e.action IN ('Commit', 'PushEvent', 'commit_repo')
|
AND e.action IN ('Commit', 'PushEvent', 'commit_repo')
|
||||||
JOIN repo_languages rl
|
JOIN repo_languages rl
|
||||||
ON rl.source = e.source
|
ON rl.source = e.source
|
||||||
@@ -273,6 +274,7 @@ impl EventReader for PgStore {
|
|||||||
)
|
)
|
||||||
.bind(from)
|
.bind(from)
|
||||||
.bind(to)
|
.bind(to)
|
||||||
|
.bind(include_private)
|
||||||
.fetch_all(&self.pool)
|
.fetch_all(&self.pool)
|
||||||
.await
|
.await
|
||||||
.map_err(map_err)?;
|
.map_err(map_err)?;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import Col from 'react-bootstrap/Col';
|
|||||||
import Row from 'react-bootstrap/Row';
|
import Row from 'react-bootstrap/Row';
|
||||||
import { VerticalTimeline } from 'react-vertical-timeline-component';
|
import { VerticalTimeline } from 'react-vertical-timeline-component';
|
||||||
|
|
||||||
import { fetchEvents, fetchSources, type Source } from '../api/client';
|
import { fetchDailyCounts, fetchEvents, fetchSources, type Source } from '../api/client';
|
||||||
import { Filters } from '../components/Filters';
|
import { Filters } from '../components/Filters';
|
||||||
import { TimelineEntry } from '../components/TimelineEntry';
|
import { TimelineEntry } from '../components/TimelineEntry';
|
||||||
|
|
||||||
@@ -82,6 +82,19 @@ export function TimelineHome() {
|
|||||||
|
|
||||||
const events = eventsQ.data ?? [];
|
const events = eventsQ.data ?? [];
|
||||||
|
|
||||||
|
const fromStr = new Date(rangeValue[0]).toISOString().slice(0, 10);
|
||||||
|
const toStr = new Date(rangeValue[1]).toISOString().slice(0, 10);
|
||||||
|
const dailyQ = useQuery({
|
||||||
|
queryKey: ['daily-counts', fromStr, toStr],
|
||||||
|
queryFn: () => fetchDailyCounts(fromStr, toStr),
|
||||||
|
staleTime: 5 * 60_000,
|
||||||
|
});
|
||||||
|
const totalCount = useMemo(
|
||||||
|
() => (dailyQ.data ?? []).reduce((sum, d) => sum + d.count, 0),
|
||||||
|
[dailyQ.data],
|
||||||
|
);
|
||||||
|
const privateCount = totalCount - events.length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Filters
|
<Filters
|
||||||
@@ -105,7 +118,7 @@ export function TimelineHome() {
|
|||||||
? 'loading…'
|
? 'loading…'
|
||||||
: eventsQ.isError
|
: eventsQ.isError
|
||||||
? `error: ${(eventsQ.error as Error).message}`
|
? `error: ${(eventsQ.error as Error).message}`
|
||||||
: `showing ${events.length} ${events.length === 1 ? 'activity' : 'activities'}`}
|
: `showing ${events.length} public ${events.length === 1 ? 'activity' : 'activities'}${privateCount > 0 ? `, ${privateCount} private` : ''}`}
|
||||||
</p>
|
</p>
|
||||||
<VerticalTimeline>
|
<VerticalTimeline>
|
||||||
{events.map((item) => (
|
{events.map((item) => (
|
||||||
|
|||||||
Reference in New Issue
Block a user