Rebuild AgentCompany-New renderer to match design spec
- Port design tokens, sidebar, topbar, and icons to inline SVG set - Rewrite each page (Home/Team/Work/Chat/Files/Approvals/Social/Settings) to drive real snapshot data and match the bento, kanban, three-pane chat, file tree + pinned cards, approval queue, social schedule + calendar, and settings sub-nav layouts - Split Chat and Settings into per-concern subcomponents so every file stays under 500 lines - Add schema v4 for pinned files and scheduled posts plus IPC + service wiring; cover new behavior in unit tests - Update onboarding labels and Hire form to remove ambiguity for the expanded e2e suite (all settings tabs + 8 routes at 1280 and 980)
This commit is contained in:
1 parent
00736d5719
commit
74266566b7
47 files changed
+4609
-1552
No files matched your search
@@ -49,8 +49,11 @@ export class FileService {
|
||||
const target = join(orgDir, `${id}-${basename(sourcePath)}`);
|
||||
copyFileSync(sourcePath, target);
|
||||
this.db.prepare(`
|
||||
insert into file_objects(id, org_id, name, kind, size_bytes, sha256, storage_path, owner_type, owner_id, created_at)
|
||||
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
insert into file_objects(
|
||||
id, org_id, name, kind, size_bytes, sha256, storage_path,
|
||||
owner_type, owner_id, space_id, pinned, created_at, updated_at
|
||||
)
|
||||
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`).run(
|
||||
id,
|
||||
orgId,
|
||||
@@ -61,6 +64,9 @@ export class FileService {
|
||||
target,
|
||||
"system",
|
||||
null,
|
||||
null,
|
||||
0,
|
||||
now,
|
||||
now,
|
||||
);
|
||||
this.audit.record({
|
||||
@@ -74,4 +80,20 @@ export class FileService {
|
||||
});
|
||||
return id;
|
||||
}
|
||||
|
||||
setPinned(orgId: string, fileId: string, pinned: boolean): void {
|
||||
const result = this.db.prepare(
|
||||
"update file_objects set pinned = ?, updated_at = ? where id = ? and org_id = ?",
|
||||
).run(pinned ? 1 : 0, new Date().toISOString(), fileId, orgId);
|
||||
if (result.changes === 0) throw new Error("File was not found.");
|
||||
this.audit.record({
|
||||
orgId,
|
||||
entityType: "file_object",
|
||||
entityId: fileId,
|
||||
actorType: "employee",
|
||||
actorId: null,
|
||||
action: pinned ? "pinned" : "unpinned",
|
||||
payload: { fileId },
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,8 @@ export class SnapshotService {
|
||||
.map((provider) => ({ ...provider, enabled: toBool(provider.enabled) }));
|
||||
const skillBindings = list<AppSnapshot["skillBindings"][number]>(this.db, "skill_bindings", "priority asc")
|
||||
.map((binding) => ({ ...binding, enabled: toBool(binding.enabled) }));
|
||||
const files = list<AppSnapshot["files"][number]>(this.db, "file_objects", "created_at desc")
|
||||
.map((file) => ({ ...file, pinned: toBool(file.pinned) }));
|
||||
|
||||
return {
|
||||
activeOrgId,
|
||||
@@ -62,7 +64,8 @@ export class SnapshotService {
|
||||
chatThreads: list(this.db, "chat_threads", "updated_at desc"),
|
||||
chatAttachments: list(this.db, "chat_attachments", "message_id asc"),
|
||||
chatPresence: list(this.db, "chat_presence", "last_seen_at desc"),
|
||||
files: list(this.db, "file_objects", "created_at desc"),
|
||||
files,
|
||||
scheduledPosts: list(this.db, "scheduled_posts", "scheduled_for asc"),
|
||||
providers,
|
||||
providerCatalog: PROVIDER_CATALOG,
|
||||
providerRequests: list(this.db, "provider_requests", "created_at desc"),
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { DatabaseSync } from "node:sqlite";
|
||||
import { BrowserWindow, session } from "electron";
|
||||
import type { CreateSocialAccountInput } from "../../shared/commands";
|
||||
import type {
|
||||
CreateScheduledPostInput,
|
||||
CreateSocialAccountInput,
|
||||
SetScheduledPostStateInput,
|
||||
} from "../../shared/commands";
|
||||
import { SOCIAL_PLATFORM, type SocialPlatform } from "../../shared/domain";
|
||||
import { createId } from "../../shared/ids";
|
||||
import { AuditService } from "./audit-service";
|
||||
@@ -26,6 +30,63 @@ export class SocialService {
|
||||
this.audit = new AuditService(db);
|
||||
}
|
||||
|
||||
createScheduledPost(input: CreateScheduledPostInput): string {
|
||||
const account = this.db.prepare("select id from social_accounts where id = ? and org_id = ?")
|
||||
.get(input.socialAccountId, input.orgId) as { id: string } | undefined;
|
||||
if (!account) throw new Error("Social account was not found.");
|
||||
const body = input.bodyMd.trim();
|
||||
if (!body) throw new Error("Post body is required.");
|
||||
const scheduledFor = input.scheduledFor.trim();
|
||||
if (!scheduledFor) throw new Error("Scheduled date is required.");
|
||||
const id = createId("spost");
|
||||
const now = new Date().toISOString();
|
||||
this.db.prepare(`
|
||||
insert into scheduled_posts(
|
||||
id, org_id, social_account_id, body_md, scheduled_for,
|
||||
state, approval_id, created_by_employee_id, created_at, updated_at
|
||||
) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`).run(
|
||||
id,
|
||||
input.orgId,
|
||||
input.socialAccountId,
|
||||
body,
|
||||
scheduledFor,
|
||||
input.state,
|
||||
null,
|
||||
input.createdByEmployeeId,
|
||||
now,
|
||||
now,
|
||||
);
|
||||
this.audit.record({
|
||||
orgId: input.orgId,
|
||||
entityType: "scheduled_post",
|
||||
entityId: id,
|
||||
actorType: input.createdByEmployeeId ? "employee" : "system",
|
||||
actorId: input.createdByEmployeeId,
|
||||
action: "scheduled",
|
||||
payload: { socialAccountId: input.socialAccountId, scheduledFor, state: input.state },
|
||||
});
|
||||
return id;
|
||||
}
|
||||
|
||||
setScheduledPostState(input: SetScheduledPostStateInput): void {
|
||||
const now = new Date().toISOString();
|
||||
const result = this.db.prepare(`
|
||||
update scheduled_posts set state = ?, updated_at = ?
|
||||
where id = ? and org_id = ?
|
||||
`).run(input.state, now, input.scheduledPostId, input.orgId);
|
||||
if (result.changes === 0) throw new Error("Scheduled post was not found.");
|
||||
this.audit.record({
|
||||
orgId: input.orgId,
|
||||
entityType: "scheduled_post",
|
||||
entityId: input.scheduledPostId,
|
||||
actorType: "employee",
|
||||
actorId: null,
|
||||
action: `state_${input.state}`,
|
||||
payload: { state: input.state },
|
||||
});
|
||||
}
|
||||
|
||||
createAccount(input: CreateSocialAccountInput): string {
|
||||
const id = createId("soc");
|
||||
const now = new Date().toISOString();
|
||||
|
||||
Reference in new issue
Block a user