Merge branch 'main' of github.com:specklesystems/speckle-server into alessandro/web-2362-list-workspace-pending-requests
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div v-if="detailedRender">
|
||||
<div v-if="detailedRender" class="mb-2">
|
||||
<div class="relative">
|
||||
<div v-if="detailedRender.status === 'COMPLETED' && renderUrl" class="group">
|
||||
<button class="relative flex cursor-zoom-in" @click="openPreview">
|
||||
@@ -55,7 +55,7 @@
|
||||
</div>
|
||||
<div
|
||||
v-if="detailedRender.status !== 'COMPLETED'"
|
||||
class="relative w-full h-32 rounded-lg flex items-center justify-center"
|
||||
class="relative w-full h-40 rounded-lg flex items-center justify-center"
|
||||
>
|
||||
<div
|
||||
:class="`absolute rounded-lg w-full h-full top-0 ${
|
||||
@@ -66,7 +66,7 @@
|
||||
<ExclamationCircleIcon v-else class="w-6 text-danger" />
|
||||
</div>
|
||||
<div
|
||||
class="absolute bottom-2 left-2 right-2 space-x-2 flex items-center min-w-0 max-w-full overflow-hidden z-10"
|
||||
class="absolute bottom-2 left-0 gap-x-2 px-2 flex items-center min-w-0 max-w-full overflow-hidden z-10"
|
||||
>
|
||||
<div
|
||||
class="bg-foundation p-0.5 flex items-center gap-x-1 min-w-0 max-w-full rounded-md"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex flex-col gap-y-2 max-h-64 2xl:max-h-96 overflow-y-scroll overflow-x-hidden simple-scroll pb-4"
|
||||
class="flex flex-col gap-y-2 max-h-64 2xl:max-h-96 overflow-y-auto overflow-x-hidden simple-scrollbar"
|
||||
>
|
||||
<ViewerGendoItem
|
||||
v-for="render in renders"
|
||||
|
||||
@@ -15,14 +15,12 @@
|
||||
</CommonBadge>
|
||||
</div>
|
||||
</template>
|
||||
<div class="pt-2">
|
||||
<div class="px-4 flex flex-col gap-y-2">
|
||||
<CommonAlert v-if="showAlert" :color="alertColor" size="xs">
|
||||
<template #title>
|
||||
{{ alertMessage }}
|
||||
</template>
|
||||
<div class="pt-3">
|
||||
<div class="px-3 flex flex-col gap-y-3">
|
||||
<CommonAlert v-if="!limits" color="danger" size="xs">
|
||||
<template #title>No credits available</template>
|
||||
</CommonAlert>
|
||||
<div class="flex flex-col gap-y-2">
|
||||
<div class="flex flex-col gap-y-3">
|
||||
<FormTextArea
|
||||
v-model="prompt"
|
||||
name="prompt"
|
||||
@@ -31,6 +29,9 @@
|
||||
color="foundation"
|
||||
:disabled="isLoading || timeOutWait || isOutOfCredits"
|
||||
textarea-classes="sm:!min-h-24"
|
||||
@keypress.enter.prevent="
|
||||
!isLoading && !timeOutWait && !isOutOfCredits && prompt && enqueMagic()
|
||||
"
|
||||
/>
|
||||
<div class="flex justify-between gap-2 items-center text-foreground-2">
|
||||
<FormButton
|
||||
@@ -41,28 +42,32 @@
|
||||
target="_blank"
|
||||
>
|
||||
<div class="flex items-center gap-1 text-foreground-2 font-normal">
|
||||
<span>Writing prompts</span>
|
||||
<span>Learn to prompt</span>
|
||||
<ArrowTopRightOnSquareIcon class="h-3 w-3" />
|
||||
</div>
|
||||
</FormButton>
|
||||
|
||||
<FormButton
|
||||
:disabled="!prompt || isLoading || timeOutWait || isOutOfCredits"
|
||||
@click="enqueMagic()"
|
||||
<View
|
||||
:key="`gendo-credits-${isOutOfCredits}`"
|
||||
v-tippy="isOutOfCredits ? 'No credits remaining' : undefined"
|
||||
>
|
||||
Generate
|
||||
</FormButton>
|
||||
<FormButton
|
||||
:disabled="!prompt || isLoading || timeOutWait || isOutOfCredits"
|
||||
@click="enqueMagic()"
|
||||
>
|
||||
Generate
|
||||
</FormButton>
|
||||
</View>
|
||||
</div>
|
||||
</div>
|
||||
<ViewerGendoList @reuse-prompt="prompt = $event" />
|
||||
</div>
|
||||
<div
|
||||
class="flex w-full items-center justify-between gap-2 border-t border-outline-2 py-1 px-2"
|
||||
class="flex w-full items-center justify-between gap-2 border-t border-outline-2 py-1 px-1"
|
||||
>
|
||||
<FormButton color="subtle" size="sm" @click="isFeedbackOpen = true">
|
||||
<div class="flex items-center gap-1 text-foreground-2 font-normal">
|
||||
<IconFeedback class="h-3 w-3" />
|
||||
<span>Feedback</span>
|
||||
<span>Give us feedback</span>
|
||||
</div>
|
||||
</FormButton>
|
||||
<FormButton
|
||||
@@ -74,12 +79,11 @@
|
||||
>
|
||||
<div class="flex items-center gap-1 text-foreground-2 font-normal">
|
||||
<span>Terms</span>
|
||||
<ArrowTopRightOnSquareIcon class="h-3 w-3" />
|
||||
</div>
|
||||
</FormButton>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="!showAlert && limits" #actions>
|
||||
<template v-if="limits" #actions>
|
||||
<div class="text-body-2xs p-1">
|
||||
{{ limits.used }}/{{ limits.limit }} free renders used
|
||||
<span class="hidden-under-250">this month</span>
|
||||
@@ -121,11 +125,11 @@ const timeOutWait = ref(false)
|
||||
const isFeedbackOpen = ref(false)
|
||||
|
||||
const suggestedPrompts = ref<string[]>([
|
||||
'Example: Minimalist Scandinavian interior with warm natural lighting',
|
||||
'Example: Luxury penthouse with floor-to-ceiling windows and city views',
|
||||
'Example: Cozy industrial loft with exposed brick and steel elements',
|
||||
'Example: Modern office space with biophilic design elements',
|
||||
'Example: High-end retail space with dramatic lighting'
|
||||
'Example: Minimalist Scandinavian interior with warm natural lighting...',
|
||||
'Example: Luxury penthouse with floor-to-ceiling windows and city views...',
|
||||
'Example: Cozy industrial loft with exposed brick and steel elements...',
|
||||
'Example: Modern office space with biophilic design elements...',
|
||||
'Example: High-end retail space with dramatic lighting...'
|
||||
])
|
||||
|
||||
const { result, refetch } = useQuery(activeUserGendoLimits)
|
||||
@@ -143,27 +147,6 @@ const isOutOfCredits = computed(() => {
|
||||
return (limits.value?.used || 0) >= (limits.value?.limit || 0)
|
||||
})
|
||||
|
||||
const isNearingLimit = computed(() => {
|
||||
if (!limits.value) return
|
||||
const usagePercent = (limits.value?.used / limits.value?.limit) * 100
|
||||
return usagePercent >= 80
|
||||
})
|
||||
|
||||
const alertColor = computed(() => {
|
||||
if (isOutOfCredits.value) return 'danger'
|
||||
if (isNearingLimit.value) return 'warning'
|
||||
return 'neutral'
|
||||
})
|
||||
|
||||
const alertMessage = computed(() => {
|
||||
if (!limits.value) return 'No credits available'
|
||||
return `${limits.value.used}/${limits.value.limit} free renders used this month`
|
||||
})
|
||||
|
||||
const showAlert = computed(
|
||||
() => !limits.value || isNearingLimit.value || isOutOfCredits.value
|
||||
)
|
||||
|
||||
const enqueMagic = async () => {
|
||||
isLoading.value = true
|
||||
const [depthData, width, height] = await viewerInstance
|
||||
|
||||
@@ -4285,6 +4285,10 @@ export type WorkspaceCreationStateInput = {
|
||||
workspaceId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
export type WorkspaceDismissInput = {
|
||||
workspaceId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
export type WorkspaceDomain = {
|
||||
__typename?: 'WorkspaceDomain';
|
||||
domain: Scalars['String']['output'];
|
||||
@@ -4378,6 +4382,8 @@ export type WorkspaceMutations = {
|
||||
delete: Scalars['Boolean']['output'];
|
||||
deleteDomain: Workspace;
|
||||
deleteSsoProvider: Scalars['Boolean']['output'];
|
||||
/** Dismiss a workspace from the discoverable list, behind the scene a join request is created with the status "dismissed" */
|
||||
dismiss: Scalars['Boolean']['output'];
|
||||
invites: WorkspaceInviteMutations;
|
||||
join: Workspace;
|
||||
leave: Scalars['Boolean']['output'];
|
||||
@@ -4415,6 +4421,11 @@ export type WorkspaceMutationsDeleteSsoProviderArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type WorkspaceMutationsDismissArgs = {
|
||||
input: WorkspaceDismissInput;
|
||||
};
|
||||
|
||||
|
||||
export type WorkspaceMutationsJoinArgs = {
|
||||
input: JoinWorkspaceInput;
|
||||
};
|
||||
@@ -8117,6 +8128,7 @@ export type WorkspaceMutationsFieldArgs = {
|
||||
delete: WorkspaceMutationsDeleteArgs,
|
||||
deleteDomain: WorkspaceMutationsDeleteDomainArgs,
|
||||
deleteSsoProvider: WorkspaceMutationsDeleteSsoProviderArgs,
|
||||
dismiss: WorkspaceMutationsDismissArgs,
|
||||
invites: {},
|
||||
join: WorkspaceMutationsJoinArgs,
|
||||
leave: WorkspaceMutationsLeaveArgs,
|
||||
|
||||
@@ -9,11 +9,18 @@ import {
|
||||
getServerInfoFactory,
|
||||
updateServerInfoFactory,
|
||||
getPublicRolesFactory,
|
||||
getPublicScopesFactory
|
||||
getPublicScopesFactory,
|
||||
getServerInfoFromCacheFactory,
|
||||
storeServerInfoInCacheFactory
|
||||
} from '@/modules/core/repositories/server'
|
||||
import { db } from '@/db/knex'
|
||||
import { Resolvers } from '@/modules/core/graph/generated/graphql'
|
||||
import { LRUCache } from 'lru-cache'
|
||||
import { ServerInfo } from '@/modules/core/helpers/types'
|
||||
|
||||
const cache = new LRUCache<string, ServerInfo>({ max: 1, ttl: 60 * 1000 })
|
||||
const getServerInfoFromCache = getServerInfoFromCacheFactory({ cache })
|
||||
const storeServerInfoInCache = storeServerInfoInCacheFactory({ cache })
|
||||
const getServerInfo = getServerInfoFactory({ db })
|
||||
const updateServerInfo = updateServerInfoFactory({ db })
|
||||
const getPublicRoles = getPublicRolesFactory({ db })
|
||||
@@ -22,7 +29,11 @@ const getPublicScopes = getPublicScopesFactory({ db })
|
||||
export = {
|
||||
Query: {
|
||||
async serverInfo() {
|
||||
return await getServerInfo()
|
||||
const cachedServerInfo = getServerInfoFromCache()
|
||||
if (cachedServerInfo) return cachedServerInfo
|
||||
const serverInfo = await getServerInfo()
|
||||
storeServerInfoInCache({ serverInfo })
|
||||
return serverInfo
|
||||
}
|
||||
},
|
||||
ServerInfo: {
|
||||
@@ -58,6 +69,9 @@ export = {
|
||||
|
||||
const update = removeNullOrUndefinedKeys(args.info)
|
||||
await updateServerInfo(update)
|
||||
// we're currently going to ignore, that this should be propagated to all
|
||||
// backend instances, and going to rely on the TTL in the cache to propagate the changes
|
||||
cache.clear()
|
||||
return true
|
||||
},
|
||||
serverInfoMutations: () => ({})
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
getServerVersion
|
||||
} from '@/modules/shared/helpers/envHelper'
|
||||
import { Knex } from 'knex'
|
||||
import { LRUCache } from 'lru-cache'
|
||||
|
||||
const ServerConfig = buildTableHelper('server_config', [
|
||||
'id',
|
||||
@@ -38,6 +39,21 @@ const tables = {
|
||||
scopes: (db: Knex) => db<ScopeRecord>(Scopes.name)
|
||||
}
|
||||
|
||||
const SERVER_CONFIG_CACHE_KEY = 'server_config'
|
||||
|
||||
export const getServerInfoFromCacheFactory =
|
||||
({ cache }: { cache: LRUCache<string, ServerInfo> }) =>
|
||||
() => {
|
||||
const serverInfo = cache.get(SERVER_CONFIG_CACHE_KEY)
|
||||
return serverInfo ?? null
|
||||
}
|
||||
|
||||
export const storeServerInfoInCacheFactory =
|
||||
({ cache }: { cache: LRUCache<string, ServerInfo> }) =>
|
||||
({ serverInfo }: { serverInfo: ServerInfo }) => {
|
||||
cache.set(SERVER_CONFIG_CACHE_KEY, serverInfo)
|
||||
}
|
||||
|
||||
export const getServerInfoFactory =
|
||||
(deps: { db: Knex }): GetServerInfo =>
|
||||
async () => {
|
||||
|
||||
@@ -459,12 +459,14 @@ const getStream = () => {
|
||||
// 'https://speckle.xyz/streams/27e89d0ad6/commits/5ed4b74252'
|
||||
|
||||
//Gingerbread
|
||||
'https://latest.speckle.systems/projects/387050bffe/models/48f7eb26fb'
|
||||
// 'https://latest.speckle.systems/projects/387050bffe/models/48f7eb26fb'
|
||||
// DUI3 Mesh Colors
|
||||
// 'https://app.speckle.systems/projects/93200a735d/models/cbacd3eaeb@344a397239'
|
||||
|
||||
// Instance toilets
|
||||
// 'https://app.speckle.systems/projects/e89b61b65c/models/2a0995f124'
|
||||
|
||||
'https://latest.speckle.systems/projects/3fe1880c36/models/65bb4287a8'
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -286,9 +286,9 @@ export class SpeckleGeometryConverter extends GeometryConverter {
|
||||
Logger.warn(
|
||||
`Mesh (id ${node.raw.id}) colours are mismatched with vertice counts. The number of colours must equal the number of vertices.`
|
||||
)
|
||||
}
|
||||
} else
|
||||
/** We want the colors in linear space */
|
||||
colors = this.unpackColors(colorsRaw, true)
|
||||
colors = this.unpackColors(colorsRaw, true)
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user