Skip to content

Commit

Permalink
fix: Update npm package to speed up layout generation
Browse files Browse the repository at this point in the history
  • Loading branch information
aklinker1 committed Apr 4, 2024
1 parent 1e61e35 commit ebce717
Show file tree
Hide file tree
Showing 17 changed files with 124 additions and 91 deletions.
10 changes: 5 additions & 5 deletions web/components/BomTab.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script lang="ts" setup>
import type { BoardLayoutLeftover } from '@aklinker1/cutlist';
const { data: doc } = useDocumentQuery();
const { data, isLoading } = useBoardLayoutsQuery();
const distanceUnit = useDistanceUnit();
Expand All @@ -8,11 +10,9 @@ const rows = computed(() => {
if (data.value == null) return [];
const map = [
...data.value?.layouts.flatMap((layout) =>
layout.placements.map((p) => p.data),
),
...data.value?.layouts.flatMap((layout) => layout.placements),
...data.value?.leftovers,
].reduce<Map<number, PartToCut[]>>((acc, part) => {
].reduce<Map<number, BoardLayoutLeftover[]>>((acc, part) => {
const items = acc.get(part.partNumber) ?? [];
items.push(part);
acc.set(part.partNumber, items);
Expand All @@ -28,7 +28,7 @@ const rows = computed(() => {
'Part Name': part.name,
QTY: instanceList.length,
Material: part.material,
[`Size (${distanceUnit.value})`]: `${formatDistance(part.size.thickness)} × ${formatDistance(part.size.width)} × ${formatDistance(part.size.length)}`,
[`Size (${distanceUnit.value})`]: `${formatDistance(part.thicknessM)} × ${formatDistance(part.widthM)} × ${formatDistance(part.lengthM)}`,
};
});
});
Expand Down
16 changes: 7 additions & 9 deletions web/components/LayoutListItem.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
<script lang="ts" setup>
import { Distance } from '@aklinker1/cutlist';
import { type BoardLayout } from '@aklinker1/cutlist';
const props = defineProps<{
layout: BoardLayout;
}>();
const widthPx = usePx(() => props.layout.stock.width);
const heightPx = usePx(() => props.layout.stock.height);
const widthPx = usePx(() => props.layout.stock.widthM);
const heightPx = usePx(() => props.layout.stock.lengthM);
const thickness = useFormattedDistance(() => props.layout.stock.data.thickness);
const width = useFormattedDistance(() => props.layout.stock.data.width);
const length = useFormattedDistance(() => props.layout.stock.data.length);
const thickness = useFormattedDistance(() => props.layout.stock.thicknessM);
const width = useFormattedDistance(() => props.layout.stock.widthM);
const length = useFormattedDistance(() => props.layout.stock.lengthM);
</script>

<template>
<li class="flex flex-col items-center gap-4">
<p class="text-center">
<span class="font-bold text-nowrap">{{
layout.stock.data.material
}}</span>
<span class="font-bold text-nowrap">{{ layout.stock.material }}</span>
<br />
<span class="text-xs text-nowrap"
>{{ thickness }} &times; {{ width }} &times; {{ length }}</span
Expand Down
10 changes: 5 additions & 5 deletions web/components/LeftoverListItem.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<script lang="ts" setup>
import { useElementHover } from '@vueuse/core';
import type { BoardLayoutLeftover } from '@aklinker1/cutlist';
const props = defineProps<{
part: PartToCut;
part: BoardLayoutLeftover;
}>();
const width = useFormattedDistance(() => props.part.size.width);
const length = useFormattedDistance(() => props.part.size.length);
const thickness = useFormattedDistance(() => props.part.size.thickness);
const width = useFormattedDistance(() => props.part.widthM);
const length = useFormattedDistance(() => props.part.lengthM);
const thickness = useFormattedDistance(() => props.part.thicknessM);
</script>

<template>
Expand Down
40 changes: 26 additions & 14 deletions web/components/MainSidebar.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<script lang="ts" setup>
import type { Config, Project } from '@aklinker1/cutlist';
import { Distance } from '@aklinker1/cutlist';
import type { HorizontalNavigationLink } from '#ui/types';
const url = useAssemblyUrl();
const { data: doc, isLoading: isLoadingDoc } = useDocumentQuery();
const { data: doc, isFetching: isFetchingDoc } = useDocumentQuery();
const { isFetching: isFetchingLayouts } = useBoardLayoutsQuery();
const refresh = useRefreshOnshapeQueries();
const { data: boardLayouts } = useBoardLayoutsQuery();
Expand All @@ -14,7 +16,7 @@ const warningsBadge = computed(() => {
return leftovers.length;
});
const links = computed(() => [
const links = computed<HorizontalNavigationLink[]>(() => [
{
label: 'BOM',
icon: 'i-heroicons-table-cells',
Expand Down Expand Up @@ -91,24 +93,34 @@ const tab = ref<'bom' | 'stock' | 'settings' | 'warnings'>('bom');
color="white"
:trailing="false"
placeholder="Enter URL..."
:loading="isLoadingDoc"
:loading="isFetchingDoc"
/>
<div
v-if="doc"
class="py-2 px-3 bg-gray-900 rounded-lg border border-gray-700 mt-2 flex justify-between items-center"
class="p-2 pl-3 bg-gray-900 rounded-lg border border-gray-700 mt-2 flex justify-between items-center"
>
<p>
{{ doc.name }}
<span class="text-sm opacity-50">by {{ doc.owner.name }}</span>
</p>
<ULink
:to="url"
target="_blank"
class="text-sm text-primary hover:underline flex items-center gap-1"
>
<span>Open</span>
<UIcon name="i-heroicons-arrow-top-right-on-square" />
</ULink>
<div class="flex items-center gap-2">
<UButton
title="Get latest parts from Onshape"
:icon="isFetchingLayouts ? undefined : 'i-heroicons-arrow-path'"
color="gray"
size="sm"
:loading="isFetchingLayouts"
@click="refresh"
/>
<UButton
title="Open in Onshape"
:to="url"
target="_blank"
icon="i-heroicons-arrow-top-right-on-square"
color="gray"
size="sm"
/>
</div>
</div>
</UFormGroup>

Expand Down
23 changes: 14 additions & 9 deletions web/components/PartDetails.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
<script lang="ts" setup>
import type {
BoardLayoutLeftover,
BoardLayoutPlacement,
} from '@aklinker1/cutlist';
const props = defineProps<{
part: PartToCut;
placement?: Rectanble<any>;
part: BoardLayoutLeftover;
placement?: BoardLayoutPlacement;
}>();
const width = useFormattedDistance(() => props.part.size.width);
const length = useFormattedDistance(() => props.part.size.length);
const thickness = useFormattedDistance(() => props.part.size.thickness);
const width = useFormattedDistance(() => props.part.widthM);
const length = useFormattedDistance(() => props.part.lengthM);
const thickness = useFormattedDistance(() => props.part.thicknessM);
const top = useFormattedDistance(() => props.placement?.top);
const left = useFormattedDistance(() => props.placement?.left);
const right = useFormattedDistance(() => props.placement?.right);
const bottom = useFormattedDistance(() => props.placement?.bottom);
const top = useFormattedDistance(() => props.placement?.topM);
const left = useFormattedDistance(() => props.placement?.leftM);
const right = useFormattedDistance(() => props.placement?.rightM);
const bottom = useFormattedDistance(() => props.placement?.bottomM);
</script>

<template>
Expand Down
6 changes: 4 additions & 2 deletions web/components/PartDetailsTooltip.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script lang="ts" setup>
import type { BoardLayoutPlacement } from '@aklinker1/cutlist';
const props = defineProps<{
part: Rectangle<PartToCut>;
part: BoardLayoutPlacement;
}>();
const { x, y } = useGlobalMouse();
Expand All @@ -14,7 +16,7 @@ const { x, y } = useGlobalMouse();
>
<PartDetails
class="translate-x-[-50%] translate-y-8 p-2 bg-gray-600 rounded shadow-xl min-w-[256px]"
:part="part.data"
:part="part"
:placement="part"
/>
</div>
Expand Down
15 changes: 8 additions & 7 deletions web/components/PartListItem.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
<script lang="ts" setup>
import type { BoardLayoutPlacement } from '@aklinker1/cutlist';
import { useElementHover } from '@vueuse/core';
const props = defineProps<{
placement: Rectangle<PartToCut>;
placement: BoardLayoutPlacement;
}>();
const container = ref<HTMLDivElement>();
const isHovered = useElementHover(container);
const width = usePx(() => props.placement.width);
const height = usePx(() => props.placement.height);
const left = usePx(() => props.placement.left);
const bottom = usePx(() => props.placement.bottom);
const width = usePx(() => props.placement.widthM);
const height = usePx(() => props.placement.lengthM);
const left = usePx(() => props.placement.leftM);
const bottom = usePx(() => props.placement.bottomM);
const getPx = useGetPx();
const fontSize = usePx(() =>
Math.min(
props.placement.width / 2,
props.placement.widthM / 2,
0.0254, // 1 in to m
),
);
Expand All @@ -40,7 +41,7 @@ const showPartNumbers = useShowPartNumbers();
class="w-full text-clip text-gray-400 group-hover:text-primary text-right p-px"
:style="`font-size:${fontSize};line-height:${fontSize}`"
>
{{ placement.data.partNumber }}
{{ placement.partNumber }}
</p>
</UPlaceholder>
<PartDetailsTooltip v-if="isHovered" :part="placement" />
Expand Down
2 changes: 1 addition & 1 deletion web/components/ScaleController.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const percent = computed(() => `${Math.round(scale.value * 100)}%`);
/>
<UButton
:title="`${percent} - Click to reset to 100%`"
class="w-20 text-center"
class="w-20 justify-center"
size="lg"
color="black"
@click="resetZoom"
Expand Down
2 changes: 1 addition & 1 deletion web/components/StockMatrixInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { StockMatrix } from '@aklinker1/cutlist';
import { z } from 'zod';
import YAML from 'js-yaml';
const model = defineModel<StockMatrix>();
const model = defineModel<StockMatrix[]>();
const getModelString = () =>
YAML.dump(model.value, { indent: 2, flowLevel: 2 });
Expand Down
40 changes: 16 additions & 24 deletions web/composables/useBoardLayoutsQuery.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,25 @@
import { useQuery } from '@tanstack/vue-query';
import { useOnshapeUrl } from './useOnshapeUrl';
import { type Project, getBoardLayouts, type Config } from '@aklinker1/cutlist';
import { generateBoardLayouts } from '@aklinker1/cutlist';

export default function () {
const onshape = useOnshapeApi();
const loader = useOnshapeLoader();
const url = useAssemblyUrl();
const onshapeUrl = useOnshapeUrl(url);
const bladeWidth = useBladeWidth();
const optimize = useOptimizeFor();
const config = useCutlistConfig();
const stock = useStock();

return useQuery({
queryKey: ['board-layouts', url, bladeWidth, optimize, stock],
queryFn: async () => {
if (onshapeUrl.value == null) return undefined;
const partsQuery = useQuery({
queryKey: ['onshape', 'board-layouts', url],
queryFn: () => loader.getParts(url.value),
});

const project: Project = {
source: {
type: 'onshape',
id: onshapeUrl.value.did,
assemblyId: onshapeUrl.value.eid,
},
};
const config: Config = {
bladeWidth: bladeWidth.value,
optimize: optimize.value,
};
return await getBoardLayouts(onshape, project, stock.value, config);
},
staleTime: 5 * 60e3, // 5 minutes, will refrech latest document
const layouts = computed(() => {
const parts = partsQuery.data.value;
if (parts == null) return undefined;
return generateBoardLayouts(parts, stock.value, config.value);
});

return {
...partsQuery,
data: layouts,
};
}
11 changes: 11 additions & 0 deletions web/composables/useCutlistConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { Config } from '@aklinker1/cutlist';

export default createSharedComposable(() => {
const bladeWidth = useBladeWidth();
const optimize = useOptimizeFor();

return computed<Config>(() => ({
bladeWidth: bladeWidth.value,
optimize: optimize.value,
}));
});
4 changes: 2 additions & 2 deletions web/composables/useDocumentQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { useQuery } from '@tanstack/vue-query';
import { useOnshapeUrl } from './useOnshapeUrl';

export default function () {
const onshape = useOnshapeApi();
const onshape = useOnshapeLoader();

const url = useAssemblyUrl();
const onshapeUrl = useOnshapeUrl(url);

return useQuery({
queryKey: ['document', computed(() => toValue(url))],
queryKey: ['onshape', 'document', computed(() => toValue(url))],
queryFn: async () => {
if (onshapeUrl.value == null) return undefined;
return await onshape.getDocument(onshapeUrl.value.did);
Expand Down
8 changes: 0 additions & 8 deletions web/composables/useOnshapeApi.ts

This file was deleted.

10 changes: 10 additions & 0 deletions web/composables/useOnshapeLoader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { defineOnshapeLoader } from '@aklinker1/cutlist/onshape';

export default createGlobalState(() =>
defineOnshapeLoader({
// Forward requests through server
baseUrl: '/api/onshape',
// Server adds auth, no need to pass anything here
// auth: { ... },
}),
);
10 changes: 10 additions & 0 deletions web/composables/useRefreshOnshapeQueries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useQueryClient } from '@tanstack/vue-query';

export default function () {
const queries = useQueryClient();
return async () => {
await queries.refetchQueries({
queryKey: ['onshape'],
});
};
}
4 changes: 2 additions & 2 deletions web/server/composables/useExtendedNitroApp.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { NitroApp } from 'nitropack';
import type { OnshapeApiClient } from '@aklinker1/cutlist/onshape';
import type { OnshapeLoader } from '@aklinker1/cutlist/onshape';

export default function () {
return useNitroApp() as ExtendedNitroApp;
}

export interface ExtendedNitroApp extends NitroApp {
onshape: OnshapeApiClient;
onshape: OnshapeLoader;
}
4 changes: 2 additions & 2 deletions web/server/plugins/onshape.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { defineOnshapeApi } from '@aklinker1/cutlist/onshape';
import { defineOnshapeLoader } from '@aklinker1/cutlist/onshape';
import { type ExtendedNitroApp } from '../composables/useExtendedNitroApp';

export default defineNitroPlugin((nitro) => {
const config = useRuntimeConfig();
(nitro as ExtendedNitroApp).onshape = defineOnshapeApi({
(nitro as ExtendedNitroApp).onshape = defineOnshapeLoader({
auth: config.onshape,
});
});

0 comments on commit ebce717

Please sign in to comment.