Build Cobble project structure from the handoff
- Remove the preset document suite (letters, emails, invoices, quotes, PDF generation, line items) with its routes, API handlers and tables - Rebrand to Cobble: site data, Lato, handoff design tokens (light and dark) in main.css, brand assets in public/brand, ember stone logo and regenerated favicons - Add bots, bot_messages, bot_tasks and bot_task_steps tables, regenerate DB types (BUN_SQLITE_COBBLE_*) and add a sample crew seed (seed:bots) - Add the chat shell at /admin/bots: rail with pinned coordinator and user popover, bottom-anchored conversation with composer, working-on panel, and a send-message API scoped to the session user - Add BotStone and Wordmark components, crew status and relative time utils with tests, and update AGENTS.md Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -7,7 +7,7 @@ import { AppContext } from "@/src/pages/__root";
|
||||
import checkUserAccess from "@/src/functions/backend/auth/check-user-access";
|
||||
import EJSON from "@/src/utils/ejson";
|
||||
import { useUsersGet } from "@/src/hooks/use-users-get";
|
||||
import type { BUN_SQLITE_BSQLITE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
|
||||
type Props = {
|
||||
users_type?: UserType | null;
|
||||
@@ -49,7 +49,7 @@ export default function useAllPeopleListInit({ users_type }: Props) {
|
||||
query: location_query,
|
||||
});
|
||||
|
||||
const selected = useRef(new Set<BUN_SQLITE_BSQLITE_USERS_JOIN>());
|
||||
const selected = useRef(new Set<BUN_SQLITE_COBBLE_USERS_JOIN>());
|
||||
|
||||
const { refresh, setRefresh } = useStatus();
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useRef } from "react";
|
||||
import _ from "lodash";
|
||||
import twuiSlugToNormalText from "@moduletrace/twui/utils/slug-to-normal-text";
|
||||
import type useAllPeopleListInit from "../(hooks)/use-all-people-list-init";
|
||||
import type { BUN_SQLITE_BSQLITE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
import searchableFieldToQueryField from "@/src/utils/searchable-field-to-query-field";
|
||||
import type { ApiReqParams } from "@/src/types";
|
||||
|
||||
@@ -13,7 +13,7 @@ export default function AllPeopleListSearch({
|
||||
setUsersQuery,
|
||||
location_query,
|
||||
}: ReturnType<typeof useAllPeopleListInit>) {
|
||||
const searchable_fields: (keyof BUN_SQLITE_BSQLITE_USERS_JOIN)[] = [
|
||||
const searchable_fields: (keyof BUN_SQLITE_COBBLE_USERS_JOIN)[] = [
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email",
|
||||
|
||||
@@ -3,10 +3,10 @@ import _ from "lodash";
|
||||
import Span from "@moduletrace/twui/layout/Span";
|
||||
import Card from "@moduletrace/twui/elements/Card";
|
||||
import type { RefObject } from "react";
|
||||
import type { BUN_SQLITE_BSQLITE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
|
||||
type Props = {
|
||||
selected: RefObject<Set<BUN_SQLITE_BSQLITE_USERS_JOIN>>;
|
||||
selected: RefObject<Set<BUN_SQLITE_COBBLE_USERS_JOIN>>;
|
||||
};
|
||||
|
||||
export default function AllPeopleListSelections({ selected }: Props) {
|
||||
|
||||
@@ -8,14 +8,14 @@ import Row from "@moduletrace/twui/layout/Row";
|
||||
import Span from "@moduletrace/twui/layout/Span";
|
||||
import Stack from "@moduletrace/twui/layout/Stack";
|
||||
import grabMediaURL from "@/src/functions/backend/media/grab-media-url";
|
||||
import type { BUN_SQLITE_BSQLITE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
import { AppContext } from "@/src/pages/__root";
|
||||
import isReadOnlyUser from "@/src/utils/rbac/is-read-only-user";
|
||||
import { useContext } from "react";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
type Props = {
|
||||
person: BUN_SQLITE_BSQLITE_USERS_JOIN;
|
||||
person: BUN_SQLITE_COBBLE_USERS_JOIN;
|
||||
};
|
||||
|
||||
export default function PeopleListCard({ person }: Props) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useContext } from "react";
|
||||
import UserForm from "../../../create/(partials)/user-form";
|
||||
import _ from "lodash";
|
||||
import type { UserFormObject, UserType } from "@/src/types";
|
||||
import type { BUN_SQLITE_BSQLITE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
|
||||
export default function EditPersonFormSection() {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
@@ -21,8 +21,8 @@ export default function EditPersonFormSection() {
|
||||
<UserForm
|
||||
existing_user={{
|
||||
...(_.pick<
|
||||
BUN_SQLITE_BSQLITE_USERS_JOIN,
|
||||
keyof BUN_SQLITE_BSQLITE_USERS_JOIN
|
||||
BUN_SQLITE_COBBLE_USERS_JOIN,
|
||||
keyof BUN_SQLITE_COBBLE_USERS_JOIN
|
||||
>(person, [
|
||||
"first_name",
|
||||
"last_name",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type {
|
||||
BUN_SQLITE_BSQLITE_USER_TYPES,
|
||||
BUN_SQLITE_BSQLITE_USERS,
|
||||
BUN_SQLITE_COBBLE_USER_TYPES,
|
||||
BUN_SQLITE_COBBLE_USERS,
|
||||
} from "@/db/types/db";
|
||||
import adminCrudHandler from "@/src/functions/frontend/admin-crud-handler";
|
||||
import clientDeleteMediaHandler from "@/src/functions/frontend/client-delete-media-handler";
|
||||
@@ -26,7 +26,7 @@ export default async function submitUserForm({
|
||||
return;
|
||||
}
|
||||
|
||||
const new_user_data: BUN_SQLITE_BSQLITE_USERS = _.pick<
|
||||
const new_user_data: BUN_SQLITE_COBBLE_USERS = _.pick<
|
||||
UserFormObject,
|
||||
keyof UserFormObject
|
||||
>(form, ["first_name", "last_name", "email", "username", "bio"]);
|
||||
@@ -99,7 +99,7 @@ export default async function submitUserForm({
|
||||
|
||||
if (user_types?.[0]) {
|
||||
const add_user_types =
|
||||
await adminCrudHandler<BUN_SQLITE_BSQLITE_USER_TYPES>({
|
||||
await adminCrudHandler<BUN_SQLITE_COBBLE_USER_TYPES>({
|
||||
action: "insert",
|
||||
table: "user_types",
|
||||
insert_data: user_types.map((ut) => ({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Form from "@moduletrace/twui/form/Form";
|
||||
import LoadingOverlay from "@moduletrace/twui/elements/LoadingOverlay";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
|
||||
import type { BUN_SQLITE_COBBLE_USERS } from "@/db/types/db";
|
||||
import submitUserForm from "../../(functions)/submit-user-form";
|
||||
import UserFormName from "./user-form-name";
|
||||
import Tag from "@moduletrace/twui/elements/Tag";
|
||||
@@ -16,7 +16,7 @@ import UserFormImage from "./user-form-image";
|
||||
|
||||
type Props = {
|
||||
existing_user?: UserFormObject;
|
||||
existing_user_full?: BUN_SQLITE_BSQLITE_USERS;
|
||||
existing_user_full?: BUN_SQLITE_COBBLE_USERS;
|
||||
};
|
||||
|
||||
export default function UserForm({ existing_user, existing_user_full }: Props) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
|
||||
import type { BUN_SQLITE_COBBLE_USERS } from "@/db/types/db";
|
||||
import Button from "@moduletrace/twui/layout/Button";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
|
||||
@@ -6,7 +6,7 @@ export default function UserFormAction({
|
||||
setForm,
|
||||
existing,
|
||||
existing_full,
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_COBBLE_USERS>>) {
|
||||
const title = existing_full?.id ? "Update User" : "Create New User";
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
|
||||
import type { BUN_SQLITE_COBBLE_USERS } from "@/db/types/db";
|
||||
import TinyMCEEditor from "@moduletrace/twui/editors/TinyMCE";
|
||||
import Button from "@moduletrace/twui/layout/Button";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
@@ -8,7 +8,7 @@ export default function UserFormBio({
|
||||
existing,
|
||||
existing_full,
|
||||
form,
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_COBBLE_USERS>>) {
|
||||
const title = existing_full?.id ? "Update User" : "Create New User";
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
|
||||
import type { BUN_SQLITE_COBBLE_USERS } from "@/db/types/db";
|
||||
import Input from "@moduletrace/twui/form/Input";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
|
||||
export default function UserFormEmail({
|
||||
setForm,
|
||||
form,
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_COBBLE_USERS>>) {
|
||||
return (
|
||||
<>
|
||||
<Input
|
||||
|
||||
@@ -2,7 +2,7 @@ import ImageUpload from "@moduletrace/twui/form/ImageUpload";
|
||||
import grabMediaURL from "@/src/functions/backend/media/grab-media-url";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
import type { UserFormObject } from "@/src/types";
|
||||
import type { BUN_SQLITE_BSQLITE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "@/src/types/sql-joins";
|
||||
|
||||
export default function UserFormImage({
|
||||
setForm,
|
||||
@@ -11,7 +11,7 @@ export default function UserFormImage({
|
||||
}: ReturnType<typeof useFormInit<UserFormObject>>) {
|
||||
const title = existing_full?.id ? "Update User" : "Create New User";
|
||||
|
||||
const person = existing_full as BUN_SQLITE_BSQLITE_USERS_JOIN | undefined;
|
||||
const person = existing_full as BUN_SQLITE_COBBLE_USERS_JOIN | undefined;
|
||||
|
||||
const user_image_url = person?.profile_media_id
|
||||
? grabMediaURL({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
|
||||
import type { BUN_SQLITE_COBBLE_USERS } from "@/db/types/db";
|
||||
import Input from "@moduletrace/twui/form/Input";
|
||||
import Row from "@moduletrace/twui/layout/Row";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
@@ -6,7 +6,7 @@ import useFormInit from "@/src/hooks/use-form-init";
|
||||
export default function UserFormName({
|
||||
setForm,
|
||||
form,
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_COBBLE_USERS>>) {
|
||||
return (
|
||||
<Row className="w-full grid xl:grid-cols-2">
|
||||
<Input
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { BUN_SQLITE_BSQLITE_USERS } from "@/db/types/db";
|
||||
import type { BUN_SQLITE_COBBLE_USERS } from "@/db/types/db";
|
||||
import Input from "@moduletrace/twui/form/Input";
|
||||
import useFormInit from "@/src/hooks/use-form-init";
|
||||
|
||||
export default function UserFormUsername({
|
||||
setForm,
|
||||
form,
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_BSQLITE_USERS>>) {
|
||||
}: ReturnType<typeof useFormInit<BUN_SQLITE_COBBLE_USERS>>) {
|
||||
return (
|
||||
<>
|
||||
<Input
|
||||
|
||||
Reference in New Issue
Block a user