Files
speckle-server/packages/frontend-2/components/project/page/models/Card.vue
T
2024-08-29 11:00:09 +02:00

231 lines
7.1 KiB
Vue

<!-- eslint-disable vuejs-accessibility/click-events-have-key-events -->
<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->
<template>
<div v-keyboard-clickable :class="containerClasses" @click="onCardClick">
<div class="relative p-2 h-full flex flex-col">
<NuxtLink
v-if="!defaultLinkDisabled"
:to="modelRoute(projectId, model.id)"
class="absolute z-10 inset-0"
/>
<div class="relative z-40 flex justify-between items-center h-10">
<NuxtLink
:to="!defaultLinkDisabled ? modelRoute(projectId, model.id) : undefined"
class="w-full"
>
<div class="px-2 select-none w-full max-w-[80%]">
<div
v-if="nameParts[0]"
class="text-body-2xs text-foreground-2 relative truncate"
>
{{ nameParts[0] }}
</div>
<div
class="text-body-xs font-medium truncate text-foreground flex-shrink min-w-0"
>
{{ nameParts[1] }}
</div>
</div>
</NuxtLink>
<ProjectPageModelsActions
v-if="project && showActions && !isPendingModelFragment(model)"
v-model:open="showActionsMenu"
:model="model"
:project="project"
:can-edit="canEdit"
@click.stop.prevent
@upload-version="triggerVersionUpload"
/>
</div>
<div class="relative flex items-center justify-center my-1 flex-1">
<div
v-if="
isAutomateModuleEnabled &&
!isPendingModelFragment(model) &&
model.automationsStatus
"
class="z-30 absolute top-0 left-0"
>
<AutomateRunsTriggerStatus
:project-id="projectId"
:status="model.automationsStatus"
:model-id="model.id"
/>
</div>
<ProjectPendingFileImportStatus
v-if="isPendingModelFragment(model)"
:upload="model"
class="px-4 w-full h-full"
/>
<ProjectPendingFileImportStatus
v-else-if="pendingVersion"
:upload="pendingVersion"
type="subversion"
class="px-4 w-full text-foreground-2 text-sm flex flex-col items-center space-y-1"
/>
<template v-else-if="previewUrl">
<NuxtLink
:to="!defaultLinkDisabled ? modelRoute(projectId, model.id) : undefined"
class="relative z-20 bg-foundation-page w-full h-48 rounded-xl border border-outline-2"
>
<PreviewImage :preview-url="previewUrl" />
</NuxtLink>
</template>
<div
v-if="!isPendingModelFragment(model)"
v-show="!previewUrl && !pendingVersion"
class="h-48 w-full relative z-30"
>
<ProjectCardImportFileArea
ref="importArea"
:project-id="projectId"
:model-name="model.name"
class="w-full h-full"
/>
</div>
</div>
<div class="relative z-20 flex justify-between items-center w-full h-8 pl-2">
<ProjectPageModelsCardUpdatedTime
class="text-body-3xs text-foreground-2"
:updated-at="updatedAtFullDate"
/>
<div class="flex items-center gap-1">
<div
v-if="!isPendingModelFragment(model)"
class="flex items-center gap-1 !text-foreground-2"
:to="modelVersionsRoute(projectId, model.id)"
>
<IconDiscussions class="h-4 w-4" />
<span class="text-body-2xs font-medium">
{{ model.commentThreadCount.totalCount }}
</span>
</div>
<FormButton
v-tippy="'View Versions'"
color="subtle"
size="sm"
class="flex items-center gap-1 !text-foreground-2"
@click.stop="router.push(modelVersionsRoute(projectId, model.id))"
>
<IconVersions class="h-4 w-4" />
{{ versionCount }}
</FormButton>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import type {
PendingFileUploadFragment,
ProjectPageLatestItemsModelItemFragment,
ProjectPageModelsCardProjectFragment
} from '~~/lib/common/generated/gql/graphql'
import { modelVersionsRoute, modelRoute } from '~~/lib/common/helpers/route'
import { graphql } from '~~/lib/common/generated/gql'
import { canModifyModels } from '~~/lib/projects/helpers/permissions'
import { isPendingModelFragment } from '~~/lib/projects/helpers/models'
import type { Nullable, Optional } from '@speckle/shared'
graphql(`
fragment ProjectPageModelsCardProject on Project {
id
role
visibility
...ProjectPageModelsActions_Project
}
`)
const emit = defineEmits<{
(e: 'click', event: MouseEvent | KeyboardEvent): void
}>()
const props = withDefaults(
defineProps<{
projectId: string
model: ProjectPageLatestItemsModelItemFragment | PendingFileUploadFragment
project: Optional<ProjectPageModelsCardProjectFragment>
showVersions?: boolean
showActions?: boolean
disableDefaultLink?: boolean
}>(),
{
showVersions: true,
showActions: true
}
)
// TODO: Get rid of this, its not reactive. Is it even necessary?
provide('projectId', props.projectId)
const router = useRouter()
const isAutomateModuleEnabled = useIsAutomateModuleEnabled()
const importArea = ref(
null as Nullable<{
triggerPicker: () => void
}>
)
const showActionsMenu = ref(false)
const containerClasses = computed(() => {
const classParts = [
'group rounded-xl bg-foundation border border-outline-3 hover:border-outline-5 w-full z-[0]'
]
if (versionCount.value > 0) {
classParts.push('cursor-pointer')
}
return classParts.join(' ')
})
const nameParts = computed(() => {
const model = props.model
const modelName = isPendingModelFragment(model) ? model.modelName : model.name
const splitName = modelName.split('/')
if (splitName.length === 1) return [null, modelName]
const displayName = splitName.pop()
return [splitName.join('/') + '/', displayName]
})
const previewUrl = computed(() =>
isPendingModelFragment(props.model) ? null : props.model.previewUrl
)
const defaultLinkDisabled = computed(
() => props.disableDefaultLink || versionCount.value < 1
)
const updatedAtFullDate = computed(() => {
return isPendingModelFragment(props.model)
? props.model.convertedLastUpdate || props.model.uploadDate
: props.model.updatedAt
})
const canEdit = computed(() => (props.project ? canModifyModels(props.project) : false))
const versionCount = computed(() => {
return isPendingModelFragment(props.model) ? 0 : props.model.versionCount.totalCount
})
const pendingVersion = computed(() => {
return isPendingModelFragment(props.model)
? null
: props.model.pendingImportedVersions[0]
})
const onCardClick = (event: KeyboardEvent | MouseEvent) => {
if (
!previewUrl.value &&
!pendingVersion.value &&
!isPendingModelFragment(props.model)
) {
return
}
emit('click', event)
}
const triggerVersionUpload = () => {
importArea.value?.triggerPicker()
}
</script>