diff --git a/.github/workflows/bun-test.yml b/.github/workflows/bun-test.yml index f562cc5a..6158e4d3 100644 --- a/.github/workflows/bun-test.yml +++ b/.github/workflows/bun-test.yml @@ -7,7 +7,7 @@ on: jobs: test: runs-on: ubuntu-latest - timeout-minutes: 20 + timeout-minutes: 60 steps: - name: Checkout code @@ -21,15 +21,21 @@ jobs: - name: Install dependencies run: bun install + - name: Install cf-proxy dependencies + working-directory: cf-proxy + run: bun install + - name: Cache setup artifacts id: cache-setup uses: actions/cache@v4 with: path: ./db.sqlite3 key: db-sqlite3-${{ hashFiles('scripts/setup-*.ts') }} + restore-keys: | + db-sqlite3- - name: Run setup if cache miss - if: steps.cache-setup.outputs.cache-hit != 'true' + if: steps.cache-setup.outputs.cache-hit != 'true' && hashFiles('db.sqlite3') == '' run: bun run setup - name: Run tests diff --git a/cf-proxy/src/components.ts b/cf-proxy/src/components.ts index 6b25a12a..c3c5c4bb 100644 --- a/cf-proxy/src/components.ts +++ b/cf-proxy/src/components.ts @@ -8,6 +8,7 @@ export interface ComponentCatalogQueryParams { search?: string is_basic?: string is_preferred?: string + is_extended_promotional?: string } export async function queryComponentCatalog( @@ -34,6 +35,7 @@ export async function queryComponentCatalog( subcategory_name: params.subcategory_name, is_basic: params.is_basic, is_preferred: params.is_preferred, + is_extended_promotional: params.is_extended_promotional, limit: "100", }) diff --git a/cf-proxy/src/index.ts b/cf-proxy/src/index.ts index 36b6160c..e340ddcd 100644 --- a/cf-proxy/src/index.ts +++ b/cf-proxy/src/index.ts @@ -367,6 +367,7 @@ async function handleD1Search( package: row.package ?? "", is_basic: Boolean(row.basic), is_preferred: Boolean(row.preferred), + is_extended_promotional: Boolean(row.preferred) && !Boolean(row.basic), description: row.description ?? "", stock: row.stock ?? 0, price: row.price1 ?? extractSmallQuantityPrice(row.price), @@ -491,6 +492,7 @@ async function handleD1ComponentsList( subcategory: row.subcategory ?? "", is_basic: Boolean(row.basic), is_preferred: Boolean(row.preferred), + is_extended_promotional: Boolean(row.preferred) && !Boolean(row.basic), })), } diff --git a/cf-proxy/src/render.ts b/cf-proxy/src/render.ts index 11ce224c..0674bfa5 100644 --- a/cf-proxy/src/render.ts +++ b/cf-proxy/src/render.ts @@ -147,6 +147,7 @@ const COLUMN_LABELS: Record = { in_stock: "In Stock", is_basic: "Basic", is_preferred: "Preferred", + is_extended_promotional: "Extended Promotional", capacitance_farads: "Capacitance", tolerance_fraction: "Tolerance", voltage_rating: "Voltage", @@ -540,6 +541,9 @@ const renderComponentsFilters = ( +
+ +
diff --git a/cf-proxy/src/search.ts b/cf-proxy/src/search.ts index f1b60d3c..706b383b 100644 --- a/cf-proxy/src/search.ts +++ b/cf-proxy/src/search.ts @@ -9,6 +9,7 @@ export interface SearchQueryParams { limit?: string is_basic?: string is_preferred?: string + is_extended_promotional?: string } interface SearchRow { @@ -110,6 +111,15 @@ export async function searchIndex( conditions.push(sql`search_index.preferred = 1`) } + if ( + params.is_extended_promotional === "true" || + params.is_extended_promotional === "1" + ) { + conditions.push( + sql`search_index.preferred = 1 AND COALESCE(search_index.basic, 0) = 0`, + ) + } + const raw = params.q?.trim() if (raw) { diff --git a/cf-proxy/test/render.test.ts b/cf-proxy/test/render.test.ts index 844b04a2..3d6ddaa0 100644 --- a/cf-proxy/test/render.test.ts +++ b/cf-proxy/test/render.test.ts @@ -59,4 +59,27 @@ describe("render helpers", () => { "Feature":"Overcurrent Protection(OCP)"", ) }) + + it("renders the extended promotional filter for the component catalog", () => { + const html = renderD1TablePage( + "/components/list", + { + components: [ + { + lcsc: 123, + mfr: "ABC", + package: "0603", + is_extended_promotional: true, + }, + ], + }, + { is_extended_promotional: "true" }, + "https://example.com/components/list?is_extended_promotional=true", + ) + + expect(html).toContain("Extended Promotional Part") + expect(html).toContain('name="is_extended_promotional"') + expect(html).toContain('is_extended_promotional" value="true" checked') + expect(html).toContain("Extended Promotional") + }) }) diff --git a/routes/api/search.tsx b/routes/api/search.tsx index a95d0da2..0c2e1467 100644 --- a/routes/api/search.tsx +++ b/routes/api/search.tsx @@ -50,6 +50,7 @@ export default withWinterSpec({ limit: z.string().optional(), is_basic: z.boolean().optional(), is_preferred: z.boolean().optional(), + is_extended_promotional: z.boolean().optional(), }), jsonResponse: z.any(), } as const)(async (req, ctx) => { @@ -72,6 +73,11 @@ export default withWinterSpec({ if (req.query.is_preferred) { query = query.where("preferred", "=", 1) } + if (req.query.is_extended_promotional) { + query = query + .where("preferred", "=", 1) + .where(sql`COALESCE(basic, 0) = 0`) + } const baseQuery = query let fallbackLikeTokens: string[] = [] @@ -193,6 +199,7 @@ export default withWinterSpec({ package: c.package, is_basic: Boolean(c.basic), is_preferred: Boolean(c.preferred), + is_extended_promotional: Boolean(c.preferred) && !Boolean(c.basic), description: c.description, stock: c.stock, price: extractSmallQuantityPrice(c.price), diff --git a/routes/components/list.tsx b/routes/components/list.tsx index 640785d1..ea97242a 100644 --- a/routes/components/list.tsx +++ b/routes/components/list.tsx @@ -35,6 +35,7 @@ export default withWinterSpec({ search: z.string().optional(), is_basic: z.boolean().optional(), is_preferred: z.boolean().optional(), + is_extended_promotional: z.boolean().optional(), }), jsonResponse: z.any(), } as const)(async (req, ctx) => { @@ -51,6 +52,7 @@ export default withWinterSpec({ "price", "extra", "basic", + "preferred", ]) .limit(limit) .orderBy("stock", "desc") @@ -70,6 +72,11 @@ export default withWinterSpec({ if (req.query.is_preferred) { query = query.where("preferred", "=", 1) } + if (req.query.is_extended_promotional) { + query = query + .where("preferred", "=", 1) + .where(sql`COALESCE(basic, 0) = 0`) + } if (req.query.search) { const search = req.query.search @@ -111,6 +118,7 @@ export default withWinterSpec({ package: c.package, is_basic: Boolean(c.basic), is_preferred: Boolean(c.preferred), + is_extended_promotional: Boolean(c.preferred) && !Boolean(c.basic), description: c.description, stock: c.stock, price: extractSmallQuantityPrice(c.price), @@ -133,6 +141,17 @@ export default withWinterSpec({ /> +
+ +