Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adds a raw data viewer for advanced users #2296

Merged
merged 29 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
270a017
feat(gendo): scaffolding
didimitrie May 22, 2024
687538a
feat(gendo): wip
didimitrie May 23, 2024
85e9277
feat(gendo): wip
didimitrie May 23, 2024
0df8fca
feat(gendo): wip
didimitrie May 24, 2024
f47d2b8
feat(gendo): wip
didimitrie May 24, 2024
244d5f8
feat(gendo): wip
didimitrie May 24, 2024
9d907ff
feat(gendo): it's alive
didimitrie May 25, 2024
ce888fd
feat(gendo): wip
didimitrie May 26, 2024
9bb615a
feat(gendo): blobifies responses to make gergo happy
didimitrie May 27, 2024
cc9b5d3
feat(gendo): ratelimiting + lints
didimitrie May 27, 2024
738ad0f
feat(gendo): prettier fix
didimitrie May 27, 2024
21c6824
feat(gendo): last fixes
didimitrie May 27, 2024
6b8740a
Merge branch 'main' into dim/gendo
didimitrie May 27, 2024
05e523f
feat(gendo): clarifications
didimitrie May 28, 2024
78a54b3
feat(gendo): helm base
didimitrie May 28, 2024
51ed487
feat(dataviewer): raw first pass
didimitrie May 29, 2024
9a20576
feat(dataviewer): some styling
didimitrie May 29, 2024
dbb1264
feat(dataviewer): objects in new + fixes
didimitrie May 29, 2024
4ca2ffe
feat(dataviewer): resources support for object cards
didimitrie May 29, 2024
ae8d871
feat(dataviewer): adds selected object support
didimitrie May 29, 2024
04cdc59
feat(dataviewer): removes button from main sidebar, integrates with e…
didimitrie May 29, 2024
329973b
feat(dataviewer): some value handling fixes
didimitrie May 29, 2024
ff13821
feat(dataviewer): linting fixes
didimitrie May 29, 2024
702b0bb
Merge branch 'main' into dim/prop-viewer
didimitrie May 29, 2024
ea1905a
feat(dataviewer): show raw viewer within Scene Explorer
andrewwallacespeckle May 30, 2024
231d1ad
feat(dataviewer): Update copy and labels
benjaminvo May 30, 2024
839d15d
feat(dataviewer): Improve row borders and divider
benjaminvo May 30, 2024
5db568d
Apply suggestions from code review
andrewwallacespeckle May 30, 2024
9dc4084
feat(dataviewer): Make sure arrow doesn't shrink
benjaminvo May 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions packages/frontend-2/components/viewer/Controls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,6 @@
<IconFileExplorer class="h-4 w-4 md:h-5 md:w-5" />
</ViewerControlsButtonToggle>

<!-- TODO -->
<!-- <ViewerControlsButtonToggle
:active="activeControl === 'filters'"
@click="toggleActiveControl('filters')"
>
<FunnelIcon class="w-5 h-5" />
</ViewerControlsButtonToggle> -->

<!-- Comment threads -->
<ViewerControlsButtonToggle
v-tippy="isSmallerOrEqualSm ? undefined : discussionsShortcut"
Expand Down Expand Up @@ -201,16 +193,19 @@
</div>
</KeepAlive>
</div>

<div v-show="resourceItems.length !== 0 && activeControl === 'explorer'">
<KeepAlive>
<ViewerExplorer class="pointer-events-auto" @close="activeControl = 'none'" />
</KeepAlive>
</div>

<ViewerComments
v-if="resourceItems.length !== 0 && activeControl === 'discussions'"
class="pointer-events-auto"
@close="activeControl = 'none'"
/>

<div v-show="resourceItems.length !== 0 && activeControl === 'automate'">
<AutomateViewerPanel
:automation-runs="allAutomationRuns"
Expand Down
61 changes: 61 additions & 0 deletions packages/frontend-2/components/viewer/dataviewer/Object.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<template>
<div>
<CommonLoadingBar v-show="loading" :loading="loading" />
<div class="space-y-1">
<div v-for="kvp in limitedKvps" :key="kvp.key">
<ViewerDataviewerRow :prop="kvp" />
</div>
<div v-if="limit < kvps.length">
<FormButton text full-width size="xs" @click="limit += 20">
show more
</FormButton>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { CommonLoadingBar } from '@speckle/ui-components'
import { useLazyQuery } from '@vue/apollo-composable'
import { useInjectedViewerState } from '~/lib/viewer/composables/setup'
import { viewerRawObjectQuery } from '~/lib/viewer/graphql/queries'

const { projectId } = useInjectedViewerState()

const props = defineProps<{
object: Record<string, unknown>
}>()

const { result, loading, load } = useLazyQuery(viewerRawObjectQuery, () => ({
streamId: projectId.value,
objectId: props.object['referencedId'] as string
}))

if (props.object['referencedId']) {
load()
}

const kvps = computed(() => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const obj = (result.value?.stream?.object?.data || props.object) as Record<
string,
unknown
>
const keys = Object.keys(obj)
const localKvps = []
for (const key of keys) {
// if (!obj[key]) continue // TODO: deal with null/undef
const value = obj[key] || obj[key] === 0 ? obj[key] : 'null'
localKvps.push({
key,
value,
type: Array.isArray(value) ? 'array' : typeof value
})
}
return localKvps
})

const limit = ref(20)
const limitedKvps = computed(() => {
return kvps.value.slice(0, limit.value)
})
</script>
43 changes: 43 additions & 0 deletions packages/frontend-2/components/viewer/dataviewer/Panel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<template>
<div class="px-2 divide-y divide-dashed divide-outline-3">
<div v-for="obj in rootObjs" :key="obj.referencedId" class="py-3">
<div class="font-bold text-xs pl-1 mb-2 text-foreground-1">
{{ obj.name }}
</div>
<ViewerDataviewerObject :object="obj" />
</div>
</div>
</template>
<script setup lang="ts">
import { useSelectionUtilities } from '~/lib/viewer/composables/ui'
import { useInjectedViewerLoadedResources } from '~~/lib/viewer/composables/setup'

const { modelsAndVersionIds, objects } = useInjectedViewerLoadedResources()

const { objects: selectedObjects } = useSelectionUtilities()

const rootObjs = computed(() => {
const selection = selectedObjects.value.map((o) => ({
referencedId: o.id,
name: 'Selection',
// eslint-disable-next-line camelcase
speckle_type: 'reference'
}))

const models = modelsAndVersionIds.value.map((m) => ({
referencedId: m.model.loadedVersion.items[0].referencedObject,
name: m.model.name,
// eslint-disable-next-line camelcase
speckle_type: 'reference'
}))

const objs = objects.value.map((m) => ({
referencedId: m.objectId,
name: 'Object ' + m.objectId,
// eslint-disable-next-line camelcase
speckle_type: 'reference'
}))

return [...selection, ...models, ...objs]
})
</script>
64 changes: 64 additions & 0 deletions packages/frontend-2/components/viewer/dataviewer/Row.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<template>
<div
:class="`w-full bg-foundation-2 hover:bg-blue-500/5 rounded px-1 py-1 border-l-2 text-xs ${
expandable ? 'border-blue-500' : 'border-transparent'
} ${expanded ? 'border-neutral-500 border-opacity-30' : ''}`"
>
<!-- eslint-disable-next-line vuejs-accessibility/click-events-have-key-events -->
<div
:class="`grid grid-cols-3 ${expandable ? 'cursor-pointer' : ''}`"
@click="handleExpand"
>
<div class="col-span-1 mr-1 flex items-center text-foreground-2 font-semibold">
<ChevronRightIcon
v-if="expandable"
:class="`w-3 ${expanded ? 'rotate-90' : ''} transition shrink-0 `"
/>
<span class="select-all truncate">{{ prop.key }}</span>
</div>
<div v-if="!expandable" class="col-span-2 truncate select-all">
{{ prop.value }}
</div>
<div v-if="expandable" class="col-span-2 truncate">
{{ prop.type }}
<span v-if="prop.type === 'array'" class="text-foreground-2 text-xs">
({{ arrayLen }})
</span>
</div>
</div>
<div v-if="expandable && expanded" class="w-full pl-1 pt-2">
<ViewerDataviewerObject :object="castProp" />
</div>
</div>
</template>
<script setup lang="ts">
import { ChevronRightIcon } from '@heroicons/vue/20/solid'
const props = defineProps<{
prop: {
key: string
value: unknown
type: string
}
}>()

const expanded = ref(false)

const expandable = computed(() => {
return props.prop.type === 'array' || props.prop.type === 'object'
})

const arrayLen = computed(() => {
if (props.prop.type !== 'array') return
const arr = props.prop.value as unknown[]
return arr.length
})

const castProp = computed(() => {
return props.prop.value as Record<string, unknown>
})

const handleExpand = () => {
if (!expandable.value) return
expanded.value = !expanded.value
}
</script>
69 changes: 50 additions & 19 deletions packages/frontend-2/components/viewer/explorer/Explorer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,49 @@
<template #title>Scene Explorer</template>

<template #actions>
<FormButton
size="xs"
text
:icon-left="BarsArrowDownIcon"
@click="expandLevel++"
>
Unfold
</FormButton>
<FormButton
size="xs"
text
:icon-left="BarsArrowUpIcon"
:disabled="expandLevel <= -1 && manualExpandLevel <= -1"
@click="collapse()"
>
Collapse
</FormButton>
<div class="flex items-center justify-between w-full">
<div v-if="!showRaw" class="flex items-center">
<FormButton
size="xs"
text
:icon-left="BarsArrowDownIcon"
@click="expandLevel++"
>
Unfold
</FormButton>
<FormButton
size="xs"
text
:icon-left="BarsArrowUpIcon"
:disabled="expandLevel <= -1 && manualExpandLevel <= -1"
@click="collapse()"
>
Collapse
</FormButton>
</div>
<div v-else>
<h4 class="font-bold whitespace-normal text-xs ml-1">Dev Mode</h4>
</div>

<FormButton
v-tippy="showRaw ? 'Switch back' : 'Switch to Dev Mode'"
size="xs"
text
class="-mr-0.5 sm:-mr-1"
color="secondary"
@click="showRaw = !showRaw"
>
<CodeBracketIcon
class="size-4 sm:size-3"
:class="showRaw ? 'text-primary' : 'text-foreground'"
/>
</FormButton>
</div>
</template>
<div v-if="rootNodes.length !== 0" class="relative flex flex-col space-y-2 py-2">
<div
v-if="!showRaw && rootNodes.length !== 0"
class="relative flex flex-col gap-y-2 py-2"
>
<div
v-for="(rootNode, idx) in rootNodes"
:key="idx"
Expand All @@ -39,12 +63,17 @@
/>
</div>
</div>
<ViewerDataviewerPanel v-if="showRaw" class="pointer-events-auto" />
</ViewerLayoutPanel>
<ViewerExplorerFilters :filters="allFilters || []" />
</div>
</template>
<script setup lang="ts">
import { BarsArrowUpIcon, BarsArrowDownIcon } from '@heroicons/vue/24/solid'
import {
BarsArrowUpIcon,
BarsArrowDownIcon,
CodeBracketIcon
} from '@heroicons/vue/24/solid'
import { ViewerEvent } from '@speckle/viewer'
import type { ExplorerNode } from '~~/lib/common/helpers/sceneExplorer'
import {
Expand Down Expand Up @@ -75,6 +104,8 @@ const collapse = () => {
if (manualExpandLevel.value > -1) manualExpandLevel.value--
}

const showRaw = ref(false)

// TODO: worldTree being set in postSetup.ts (viewer) does not seem to create a reactive effect
// in here (as i was expecting it to?). Therefore, refHack++ to trigger the computed prop rootNodes.
// Possibly Fabs will know more :)
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend-2/components/viewer/layout/Panel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
class="absolute top-1.5 sm:top-2 right-0.5 sm:right-0 z-10"
>
<FormButton size="sm" color="secondary" text @click="$emit('close')">
<XMarkIcon class="h-4 w-4 sm:h-3 sm:w-3 text-primary sm:text-foreground" />
<XMarkIcon class="size-4 sm:size-3 text-primary sm:text-foreground" />
</FormButton>
</div>
<div
Expand Down
19 changes: 16 additions & 3 deletions packages/frontend-2/components/viewer/resources/List.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
size="xs"
text
:icon-left="showRemove ? CheckIcon : MinusIcon"
:disabled="modelsAndVersionIds.length <= 1"
:disabled="!removeEnabled"
@click="showRemove = !showRemove"
>
{{ showRemove ? 'Done' : 'Remove' }}
Expand All @@ -35,6 +35,15 @@
@remove="(id:string) => removeModel(id)"
/>
</div>
<template v-if="objects.length !== 0">
<ViewerResourcesObjectCard
v-for="object in objects"
:key="object.objectId"
:object="object"
:show-remove="showRemove"
@remove="(id:string) => removeModel(id)"
/>
</template>
</template>
</div>
<ViewerResourcesAddModelDialog v-model:open="open" />
Expand All @@ -52,7 +61,8 @@ import { useMixpanel } from '~~/lib/core/composables/mp'
defineEmits(['close'])

const showRemove = ref(false)
const { resourceItems, modelsAndVersionIds } = useInjectedViewerLoadedResources()
const { resourceItems, modelsAndVersionIds, objects } =
useInjectedViewerLoadedResources()
const { items } = useInjectedViewerRequestedResources()

const open = ref(false)
Expand All @@ -68,7 +78,8 @@ const removeModel = async (modelId: string) => {
builder.addModel(loadedResource.modelId, loadedResource.versionId || undefined)
}
} else {
builder.addObject(loadedResource.objectId)
if (loadedResource.objectId !== modelId)
builder.addObject(loadedResource.objectId)
}
}
mp.track('Viewer Action', { type: 'action', name: 'federation', action: 'remove' })
Expand All @@ -78,4 +89,6 @@ const removeModel = async (modelId: string) => {
watch(modelsAndVersionIds, (newVal) => {
if (newVal.length <= 1) showRemove.value = false
})

const removeEnabled = computed(() => items.value.length > 1)
</script>
Loading