mirror of https://github.com/buster-so/buster.git
super nested list items
This commit is contained in:
parent
69eb14c836
commit
75950ae108
|
@ -9,31 +9,22 @@ export async function getReportHandler(
|
|||
reportId: string,
|
||||
user: { id: string }
|
||||
): Promise<GetReportIndividualResponse> {
|
||||
try {
|
||||
const report = await getReport({ reportId, userId: user.id });
|
||||
const report = await getReport({ reportId, userId: user.id });
|
||||
|
||||
const platejsResult = await markdownToPlatejs(report.content);
|
||||
const platejsResult = await markdownToPlatejs(report.content);
|
||||
|
||||
if (platejsResult.error) {
|
||||
throw new HTTPException(500, {
|
||||
message: `Error converting markdown to PlateJS: ${platejsResult.error.message}`,
|
||||
});
|
||||
}
|
||||
|
||||
const content = platejsResult.elements ?? [];
|
||||
|
||||
const response: GetReportIndividualResponse = {
|
||||
...report,
|
||||
content,
|
||||
};
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error('Error getting report:', error);
|
||||
throw new HTTPException(500, {
|
||||
message: `Error getting report: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
});
|
||||
if (platejsResult.error) {
|
||||
throw platejsResult.error;
|
||||
}
|
||||
|
||||
const content = platejsResult.elements ?? [];
|
||||
|
||||
const response: GetReportIndividualResponse = {
|
||||
...report,
|
||||
content,
|
||||
};
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
const app = new Hono()
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
"@buster/data-source#dev",
|
||||
"@buster-app/trigger#dev",
|
||||
"@buster-app/electric-server#dev",
|
||||
"@buster-app/api-legacy#dev"
|
||||
"@buster-app/api-legacy#dev",
|
||||
"@buster/server-utils#dev"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -322,8 +322,8 @@ const ListTypeEnum = z.enum(['ul', 'ol']);
|
|||
|
||||
// Nested list item for complex lists
|
||||
const NestedListElementSchema = z.object({
|
||||
type: z.enum(['li', 'lic', 'lii']),
|
||||
children: z.array(z.union([TextSchema, ParagraphElementSchema])).default([]),
|
||||
type: z.enum(['li', 'lic', 'lii', 'ul', 'ol']),
|
||||
children: z.array(z.any()).default([]),
|
||||
});
|
||||
|
||||
// List container (unordered or ordered)
|
||||
|
|
|
@ -71,6 +71,37 @@ Here's an unordered list:
|
|||
const platejs = await markdownToPlatejs(markdown);
|
||||
expect(platejs).toBeDefined();
|
||||
});
|
||||
|
||||
it('real world markdown', async () => {
|
||||
const markdown = `Our most popular mountain bike over the last 12 months is Mountain-200 Black, 38 with 825 units sold.
|
||||
## Key Findings
|
||||
- The top-selling mountain bike model is **Mountain-200 Black, 38**.
|
||||
- It sold **825 units** in the last 12 months.
|
||||
## Metric
|
||||
<metric metricId="d3bf75d2-28f7-408e-93ec-ae06b509ad27" />
|
||||
## Context
|
||||
- I focused specifically on complete bicycle products in the **Mountain Bikes** subcategory within the broader **Bikes** category to avoid counting components or frames.
|
||||
- I measured popularity by **units sold**, which reflects the number of bikes customers purchased.
|
||||
- Timeframe defaults to the **last 12 months** to show a current view.
|
||||
## Methodology
|
||||
- Data sources: Sales order lines and headers, and product catalog tables in the operational analytics database.
|
||||
- Filters:
|
||||
- Product Category = "Bikes"
|
||||
- Product Subcategory = "Mountain Bikes"
|
||||
- Order Date between CURRENT_DATE - 12 months and CURRENT_DATE
|
||||
- Calculation:
|
||||
- For each mountain bike product, sum of sales order quantities from sales order details.
|
||||
- Select the product with the highest total units sold.
|
||||
- Notes on definitions:
|
||||
- "Most popular" defined as highest **units sold**; alternative definitions could use revenue or number of distinct orders, but units sold most directly represents product popularity by volume.
|
||||
- Product names are used as the display label to identify the specific model.
|
||||
- Alternatives considered:
|
||||
- Using revenue-based popularity could favor higher-priced bikes; I chose units to avoid price bias.
|
||||
- Using the riding discipline filter (e.g., Mountain) was considered, but I used the explicit Mountain Bikes subcategory to exclude components.
|
||||
`;
|
||||
const platejs = await markdownToPlatejs(markdown);
|
||||
expect(platejs).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('platejsToMarkdown', () => {
|
||||
|
@ -144,4 +175,394 @@ describe('platejsToMarkdown', () => {
|
|||
const expectedMarkdown = `<callout icon="⚠️">This is a simple paragraph.\n</callout>\n`;
|
||||
expect(markdownFromPlatejs).toBe(expectedMarkdown);
|
||||
});
|
||||
|
||||
it('should convert callout platejs element to markdown', async () => {
|
||||
const elements: ReportElements = [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Our most popular mountain bike over the last 12 months is Mountain-200 Black, 38 with 825 units sold.',
|
||||
},
|
||||
],
|
||||
type: 'p',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Key Findings',
|
||||
},
|
||||
],
|
||||
type: 'h2',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'The top-selling mountain bike model is ',
|
||||
},
|
||||
{
|
||||
bold: true,
|
||||
text: 'Mountain-200 Black, 38',
|
||||
},
|
||||
{
|
||||
text: '.',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'It sold ',
|
||||
},
|
||||
{
|
||||
bold: true,
|
||||
text: '825 units',
|
||||
},
|
||||
{
|
||||
text: ' in the last 12 months.',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
],
|
||||
type: 'ul',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Metric',
|
||||
},
|
||||
],
|
||||
type: 'h2',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: '<metric>\n',
|
||||
},
|
||||
{
|
||||
text: '',
|
||||
},
|
||||
{
|
||||
text: '\n</metric>',
|
||||
},
|
||||
],
|
||||
type: 'p',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Context',
|
||||
},
|
||||
],
|
||||
type: 'h2',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'I focused specifically on complete bicycle products in the ',
|
||||
},
|
||||
{
|
||||
bold: true,
|
||||
text: 'Mountain Bikes',
|
||||
},
|
||||
{
|
||||
text: ' subcategory within the broader ',
|
||||
},
|
||||
{
|
||||
bold: true,
|
||||
text: 'Bikes',
|
||||
},
|
||||
{
|
||||
text: ' category to avoid counting components or frames.',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'I measured popularity by ',
|
||||
},
|
||||
{
|
||||
bold: true,
|
||||
text: 'units sold',
|
||||
},
|
||||
{
|
||||
text: ', which reflects the number of bikes customers purchased.',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Timeframe defaults to the ',
|
||||
},
|
||||
{
|
||||
bold: true,
|
||||
text: 'last 12 months',
|
||||
},
|
||||
{
|
||||
text: ' to show a current view.',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
],
|
||||
type: 'ul',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Methodology',
|
||||
},
|
||||
],
|
||||
type: 'h2',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Data sources: Sales order lines and headers, and product catalog tables in the operational analytics database.',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Filters:',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Product Category = "Bikes"',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Product Subcategory = "Mountain Bikes"',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Order Date between CURRENT_DATE - 12 months and CURRENT_DATE',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
],
|
||||
type: 'ul',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Calculation:',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'For each mountain bike product, sum of sales order quantities from sales order details.',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Select the product with the highest total units sold.',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
],
|
||||
type: 'ul',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Notes on definitions:',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: '"Most popular" defined as highest ',
|
||||
},
|
||||
{
|
||||
bold: true,
|
||||
text: 'units sold',
|
||||
},
|
||||
{
|
||||
text: '; alternative definitions could use revenue or number of distinct orders, but units sold most directly represents product popularity by volume.',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Product names are used as the display label to identify the specific model.',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
],
|
||||
type: 'ul',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Alternatives considered:',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Using revenue-based popularity could favor higher-priced bikes; I chose units to avoid price bias.',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Using the riding discipline filter (e.g., Mountain) was considered, but I used the explicit Mountain Bikes subcategory to exclude components.',
|
||||
},
|
||||
],
|
||||
type: 'lic',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
],
|
||||
type: 'ul',
|
||||
},
|
||||
],
|
||||
type: 'li',
|
||||
},
|
||||
],
|
||||
type: 'ul',
|
||||
},
|
||||
];
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,9 +5,14 @@ import { SERVER_EDITOR } from './server-editor';
|
|||
export const markdownToPlatejs = async (markdown: string) => {
|
||||
try {
|
||||
const descendants = SERVER_EDITOR.api.markdown.deserialize(markdown);
|
||||
console.log('descendants', descendants);
|
||||
|
||||
console.log('descendants.json', JSON.stringify(descendants, null, 2));
|
||||
|
||||
const safeParsedElements = ReportElementsSchema.safeParse(descendants);
|
||||
|
||||
console.log('safeParsedElements', safeParsedElements);
|
||||
|
||||
return {
|
||||
error: safeParsedElements.error,
|
||||
elements: safeParsedElements.data,
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"$schema": "https://turbo.build/schema.json",
|
||||
"extends": ["//"],
|
||||
"tasks": {
|
||||
"build": {
|
||||
"inputs": [
|
||||
"src/**/*",
|
||||
"!src/**/*.test.{ts,tsx,js,jsx}",
|
||||
"!src/**/*.spec.{ts,tsx,js,jsx}",
|
||||
"package.json",
|
||||
"tsconfig.json"
|
||||
],
|
||||
"outputs": ["dist/**/*"]
|
||||
},
|
||||
"dev": {
|
||||
"cache": false,
|
||||
"persistent": true,
|
||||
"dependsOn": ["^build"],
|
||||
"with": []
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue