feat(admin): music library admin + fix CRM analytics UTC
Build backend images / build content-svc (push) Failing after 1m7s
Build backend images / build file-svc (push) Failing after 50s
Build backend images / build gateway (push) Failing after 59s
Build backend images / build identity-svc (push) Failing after 56s
Build backend images / build notification-svc (push) Failing after 1m0s
Build backend images / build render-svc (push) Failing after 1m0s
Build backend images / build studio-svc (push) Failing after 56s
Build backend images / build content-svc (push) Failing after 1m7s
Build backend images / build file-svc (push) Failing after 50s
Build backend images / build gateway (push) Failing after 59s
Build backend images / build identity-svc (push) Failing after 56s
Build backend images / build notification-svc (push) Failing after 1m0s
Build backend images / build render-svc (push) Failing after 1m0s
Build backend images / build studio-svc (push) Failing after 56s
- /admin/music: list / upload / delete studio audio tracks (content-svc GET/POST/DELETE /v1/music) — fills the legacy music-library gap - fix: CRM analytics coerced query-bound dates to UTC (Npgsql timestamptz rejects Kind=Unspecified) — endpoint was returning 400 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+2
-1
@@ -328,7 +328,8 @@
|
|||||||
"marketing": "Marketing",
|
"marketing": "Marketing",
|
||||||
"crm": "CRM",
|
"crm": "CRM",
|
||||||
"ranking": "Ranking",
|
"ranking": "Ranking",
|
||||||
"stats": "Dashboard"
|
"stats": "Dashboard",
|
||||||
|
"music": "Music"
|
||||||
},
|
},
|
||||||
"appAdminNodesPage": {
|
"appAdminNodesPage": {
|
||||||
"title": "Render Nodes",
|
"title": "Render Nodes",
|
||||||
|
|||||||
+2
-1
@@ -328,7 +328,8 @@
|
|||||||
"marketing": "بازاریابی",
|
"marketing": "بازاریابی",
|
||||||
"crm": "مدیریت مشتریان",
|
"crm": "مدیریت مشتریان",
|
||||||
"ranking": "رتبهبندی",
|
"ranking": "رتبهبندی",
|
||||||
"stats": "داشبورد"
|
"stats": "داشبورد",
|
||||||
|
"music": "موسیقی"
|
||||||
},
|
},
|
||||||
"appAdminNodesPage": {
|
"appAdminNodesPage": {
|
||||||
"title": "نودهای رندر",
|
"title": "نودهای رندر",
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ public class AdminService(IdentityDbContext db)
|
|||||||
|
|
||||||
public async Task<CrmAnalyticsResponse> GetCrmAnalyticsAsync(Guid tenantId, DateTime start, DateTime end)
|
public async Task<CrmAnalyticsResponse> GetCrmAnalyticsAsync(Guid tenantId, DateTime start, DateTime end)
|
||||||
{
|
{
|
||||||
start = start.Date;
|
// Query-bound dates arrive Kind=Unspecified; Npgsql requires UTC for timestamptz.
|
||||||
end = end.Date.AddDays(1); // inclusive of the end day
|
start = DateTime.SpecifyKind(start.Date, DateTimeKind.Utc);
|
||||||
|
end = DateTime.SpecifyKind(end.Date.AddDays(1), DateTimeKind.Utc); // inclusive of the end day
|
||||||
if ((end - start).TotalDays > 366) end = start.AddDays(366);
|
if ((end - start).TotalDays > 366) end = start.AddDays(366);
|
||||||
|
|
||||||
var signups = await db.Users
|
var signups = await db.Users
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export default async function AdminLayout({
|
|||||||
{ href: "/admin/ranking", label: t("ranking") },
|
{ href: "/admin/ranking", label: t("ranking") },
|
||||||
{ href: "/admin/tags", label: t("tags") },
|
{ href: "/admin/tags", label: t("tags") },
|
||||||
{ href: "/admin/fonts", label: t("fonts") },
|
{ href: "/admin/fonts", label: t("fonts") },
|
||||||
|
{ href: "/admin/music", label: t("music") },
|
||||||
{ href: "/admin/blogs", label: t("blogs") },
|
{ href: "/admin/blogs", label: t("blogs") },
|
||||||
{ href: "/admin/slides", label: t("slides") },
|
{ href: "/admin/slides", label: t("slides") },
|
||||||
{ href: "/admin/files", label: t("media") },
|
{ href: "/admin/files", label: t("media") },
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { AdminResource } from "@/components/admin/AdminResource";
|
||||||
|
import { musicConfig } from "@/components/admin/admin-resources";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <AdminResource config={musicConfig} />;
|
||||||
|
}
|
||||||
@@ -109,6 +109,34 @@ export const fontsConfig: ResourceConfig = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const musicConfig: ResourceConfig = {
|
||||||
|
title: "Music",
|
||||||
|
description: "Audio tracks available in the studio music library.",
|
||||||
|
basePath: "music",
|
||||||
|
listKey: "items",
|
||||||
|
canCreate: true,
|
||||||
|
canEdit: false,
|
||||||
|
canDelete: true,
|
||||||
|
columns: [
|
||||||
|
{ key: "name", label: "Name" },
|
||||||
|
{ key: "genre", label: "Genre" },
|
||||||
|
{ key: "mood", label: "Mood" },
|
||||||
|
{ key: "duration_sec", label: "Duration (s)" },
|
||||||
|
{ key: "is_premium", label: "Premium", render: (r) => badge(!!r.is_premium, "premium", "free") },
|
||||||
|
],
|
||||||
|
fields: [
|
||||||
|
{ key: "name", label: "Name", required: true },
|
||||||
|
{ key: "caption", label: "Caption" },
|
||||||
|
{ key: "keywords", label: "Keywords" },
|
||||||
|
{ key: "url", label: "Audio file", type: "file", required: true },
|
||||||
|
{ key: "duration_sec", label: "Duration (seconds)", type: "number", required: true },
|
||||||
|
{ key: "bpm", label: "BPM", type: "number" },
|
||||||
|
{ key: "genre", label: "Genre" },
|
||||||
|
{ key: "mood", label: "Mood" },
|
||||||
|
{ key: "is_premium", label: "Premium", type: "checkbox" },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
export const blogsConfig: ResourceConfig = {
|
export const blogsConfig: ResourceConfig = {
|
||||||
title: "Blog Posts",
|
title: "Blog Posts",
|
||||||
description: "CMS articles (also created by the AI SEO generator).",
|
description: "CMS articles (also created by the AI SEO generator).",
|
||||||
|
|||||||
Reference in New Issue
Block a user