Compare commits
No commits in common. "026d0cfd56f3d6ee99fabd787b15a22fc9229996" and "89558cdd1a1380993137e79998b7476f1382e288" have entirely different histories.
026d0cfd56
...
89558cdd1a
28
.github/workflows/build.yml
vendored
28
.github/workflows/build.yml
vendored
@ -25,35 +25,9 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
- name: Build and Push Docker image
|
- name: Build and Push Docker image -- finn-board
|
||||||
uses: docker/build-push-action@675965c0e16f1a0f94ecafff969d8c966f92c17b
|
uses: docker/build-push-action@675965c0e16f1a0f94ecafff969d8c966f92c17b
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
tags: git.joshuacoles.me/joshuacoles/revision-ui:latest
|
tags: git.joshuacoles.me/joshuacoles/revision-ui:latest
|
||||||
|
|
||||||
build-arm:
|
|
||||||
runs-on: macos-latest
|
|
||||||
container:
|
|
||||||
image: catthehacker/ubuntu:act-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
|
|
||||||
- name: Login to Docker
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
registry: git.joshuacoles.me
|
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
|
||||||
|
|
||||||
- name: Build and Push Docker image
|
|
||||||
uses: docker/build-push-action@675965c0e16f1a0f94ecafff969d8c966f92c17b
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: true
|
|
||||||
tags: git.joshuacoles.me/joshuacoles/revision-ui:arm
|
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -40,6 +40,3 @@ next-env.d.ts
|
|||||||
|
|
||||||
# Private env files
|
# Private env files
|
||||||
.env
|
.env
|
||||||
|
|
||||||
# Caddyfile for local development when testing weird deploys
|
|
||||||
/Caddyfile
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import {Tooltip} from 'react-tooltip';
|
|||||||
import {Data} from "@/data/fetchData";
|
import {Data} from "@/data/fetchData";
|
||||||
import HeatMap from "@/components/HeatMap";
|
import HeatMap from "@/components/HeatMap";
|
||||||
|
|
||||||
function useCalendarData(data: Data) {
|
function useCalendarData(data: Data, initialDate: Date, endDate: Date) {
|
||||||
const timeEntries = data.timeEntries;
|
const timeEntries = data.timeEntries;
|
||||||
|
|
||||||
// Group by day, sum up seconds
|
// Group by day, sum up seconds
|
||||||
@ -17,6 +17,17 @@ function useCalendarData(data: Data) {
|
|||||||
return R.sum((entries ?? []).map((entry) => entry.duration))
|
return R.sum((entries ?? []).map((entry) => entry.duration))
|
||||||
}, grouped);
|
}, grouped);
|
||||||
|
|
||||||
|
// Fill in missing days, hacky
|
||||||
|
dFns.eachDayOfInterval({
|
||||||
|
start: initialDate,
|
||||||
|
end: endDate,
|
||||||
|
}).forEach((date) => {
|
||||||
|
const key = dFns.formatISO(date);
|
||||||
|
if (summed[key] == undefined) {
|
||||||
|
summed[key] = 0;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return Object.entries(summed)
|
return Object.entries(summed)
|
||||||
.map(([key, value]) => ({
|
.map(([key, value]) => ({
|
||||||
date: dFns.parseISO(key),
|
date: dFns.parseISO(key),
|
||||||
@ -39,7 +50,7 @@ export function CalendarOverviewCard({
|
|||||||
}) {
|
}) {
|
||||||
const initialDate = dFns.parseISO(startTime);
|
const initialDate = dFns.parseISO(startTime);
|
||||||
const endDate = dFns.parseISO(endTime);
|
const endDate = dFns.parseISO(endTime);
|
||||||
const calendarData = useCalendarData(data);
|
const calendarData = useCalendarData(data, initialDate, endDate);
|
||||||
|
|
||||||
return <Card className="col-span-1">
|
return <Card className="col-span-1">
|
||||||
<Tooltip id="calendar-tooltip"/>
|
<Tooltip id="calendar-tooltip"/>
|
||||||
|
|||||||
75
src/data/db.d.ts
vendored
75
src/data/db.d.ts
vendored
@ -1,8 +1,8 @@
|
|||||||
import type {ColumnType} from "kysely";
|
import type {ColumnType, JSONColumnType} from "kysely";
|
||||||
|
|
||||||
export type Generated<T> = T extends ColumnType<infer S, infer I, infer U>
|
export type Generated<T> = T extends ColumnType<infer S, infer I, infer U>
|
||||||
? ColumnType<S, I | undefined, U>
|
? ColumnType<S, I | undefined, U>
|
||||||
: ColumnType<T, T | undefined, T>;
|
: ColumnType<T, T | undefined, T>;
|
||||||
|
|
||||||
export type Int8 = ColumnType<string, bigint | number | string, bigint | number | string>;
|
export type Int8 = ColumnType<string, bigint | number | string, bigint | number | string>;
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ export type Json = ColumnType<JsonValue, string, string>;
|
|||||||
export type JsonArray = JsonValue[];
|
export type JsonArray = JsonValue[];
|
||||||
|
|
||||||
export type JsonObject = {
|
export type JsonObject = {
|
||||||
[K in string]?: JsonValue;
|
[K in string]?: JsonValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type JsonPrimitive = boolean | number | string | null;
|
export type JsonPrimitive = boolean | number | string | null;
|
||||||
@ -21,49 +21,50 @@ export type JsonValue = JsonArray | JsonObject | JsonPrimitive;
|
|||||||
export type Timestamp = ColumnType<Date, Date | string, Date | string>;
|
export type Timestamp = ColumnType<Date, Date | string, Date | string>;
|
||||||
|
|
||||||
export interface Client {
|
export interface Client {
|
||||||
archived: boolean;
|
archived: boolean;
|
||||||
at: Timestamp;
|
at: Timestamp;
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
server_deleted_at: Timestamp | null;
|
server_deleted_at: Timestamp | null;
|
||||||
workspace_id: number;
|
workspace_id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Project {
|
export interface Project {
|
||||||
active: boolean;
|
active: boolean;
|
||||||
client_id: number | null;
|
client_id: number | null;
|
||||||
color: string;
|
id: Generated<number>;
|
||||||
id: Generated<number>;
|
name: string;
|
||||||
name: string;
|
raw_json: JSONColumnType<{
|
||||||
raw_json: Json;
|
color: string;
|
||||||
server_created_at: Timestamp;
|
id: number;
|
||||||
server_deleted_at: Timestamp | null;
|
name: string;
|
||||||
server_updated_at: Timestamp;
|
}>;
|
||||||
toggl_id: Int8;
|
toggl_id: Int8;
|
||||||
workspace_id: Int8;
|
workspace_id: Int8;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TimeEntry {
|
export interface TimeEntry {
|
||||||
description: string;
|
description: string;
|
||||||
id: Generated<number>;
|
id: Generated<number>;
|
||||||
project_id: Int8 | null;
|
project_id: Int8 | null;
|
||||||
raw_json: Json;
|
raw_json: JSONColumnType<{
|
||||||
server_deleted_at: Timestamp | null;
|
start: string;
|
||||||
server_updated_at: Timestamp;
|
end: string;
|
||||||
start: Timestamp;
|
seconds: number;
|
||||||
stop: Timestamp;
|
}>;
|
||||||
tags: Generated<Json>;
|
start: Timestamp;
|
||||||
toggl_id: Int8;
|
stop: Timestamp;
|
||||||
|
toggl_id: Int8;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TogglPortalSeaqlMigrations {
|
export interface TogglPortalSeaqlMigrations {
|
||||||
applied_at: Int8;
|
applied_at: Int8;
|
||||||
version: string;
|
version: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DB {
|
export interface DB {
|
||||||
client: Client;
|
client: Client;
|
||||||
project: Project;
|
project: Project;
|
||||||
time_entry: TimeEntry;
|
time_entry: TimeEntry;
|
||||||
toggl_portal_seaql_migrations: TogglPortalSeaqlMigrations;
|
toggl_portal_seaql_migrations: TogglPortalSeaqlMigrations;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,12 +52,12 @@ export async function getData(config: OverviewConfig): Promise<Data> {
|
|||||||
let projectIds = config.subjects.map((subject) => subject.projectId.toString());
|
let projectIds = config.subjects.map((subject) => subject.projectId.toString());
|
||||||
|
|
||||||
const projects = await db.selectFrom('project')
|
const projects = await db.selectFrom('project')
|
||||||
.select(['toggl_id', 'name', 'color'])
|
.select('raw_json')
|
||||||
.where('toggl_id', 'in', projectIds)
|
.where('project.toggl_id', 'in', projectIds)
|
||||||
.execute()
|
.execute();
|
||||||
|
|
||||||
const timeEntries = await db.selectFrom('time_entry')
|
const timeEntries = await db.selectFrom('time_entry')
|
||||||
.select(['project_id', 'start', 'stop'])
|
.select(['project_id', 'raw_json'])
|
||||||
.where('project_id', 'in', projectIds)
|
.where('project_id', 'in', projectIds)
|
||||||
.where('start', '>', dFns.parseISO(config.timePeriod.start))
|
.where('start', '>', dFns.parseISO(config.timePeriod.start))
|
||||||
.where('start', '<', dFns.parseISO(config.timePeriod.end))
|
.where('start', '<', dFns.parseISO(config.timePeriod.end))
|
||||||
@ -65,16 +65,16 @@ export async function getData(config: OverviewConfig): Promise<Data> {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
projects: projects.map((project) => ({
|
projects: projects.map((project) => ({
|
||||||
projectId: parseInt(project.toggl_id),
|
projectId: project.raw_json.id,
|
||||||
name: project.name,
|
name: project.raw_json.name,
|
||||||
color: project.color,
|
color: project.raw_json.color,
|
||||||
})),
|
})),
|
||||||
|
|
||||||
timeEntries: timeEntries.map((timeEntry) => ({
|
timeEntries: timeEntries.map((timeEntry) => ({
|
||||||
projectId: parseInt(timeEntry.project_id!),
|
projectId: parseInt(timeEntry.project_id!),
|
||||||
start: dFns.formatISO(timeEntry.start),
|
start: timeEntry.raw_json.start,
|
||||||
end: dFns.formatISO(timeEntry.stop),
|
end: timeEntry.raw_json.end,
|
||||||
duration: dFns.differenceInSeconds(timeEntry.stop, timeEntry.start)
|
duration: timeEntry.raw_json.seconds,
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user