Merge branch 'main' of github.com:specklesystems/speckle-server into alessandro/web-943-add-stream-permissions-revoked-activity
This commit is contained in:
@@ -26,7 +26,9 @@
|
||||
class="absolute z-40 lg:static h-full flex w-[17rem] shrink-0 transition-all"
|
||||
:class="isOpenMobile ? '' : '-translate-x-[17rem] lg:translate-x-0'"
|
||||
>
|
||||
<LayoutSidebar class="border-r border-outline-3 px-2 py-3 bg-foundation-page">
|
||||
<LayoutSidebar
|
||||
class="border-r border-outline-3 px-2 pt-3 pb-2 bg-foundation-page"
|
||||
>
|
||||
<LayoutSidebarMenu>
|
||||
<LayoutSidebarMenuGroup>
|
||||
<NuxtLink :to="homeRoute" @click="isOpenMobile = false">
|
||||
@@ -123,17 +125,13 @@
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink
|
||||
to="https://docs.google.com/forms/d/e/1FAIpQLSeTOU8i0KwpgBG7ONimsh4YMqvLKZfSRhWEOz4W0MyjQ1lfAQ/viewform"
|
||||
target="_blank"
|
||||
@click="isOpenMobile = false"
|
||||
>
|
||||
<LayoutSidebarMenuGroupItem label="Give us feedback" external>
|
||||
<div @click="openFeedbackDialog">
|
||||
<LayoutSidebarMenuGroupItem label="Give us feedback">
|
||||
<template #icon>
|
||||
<IconFeedback class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<NuxtLink
|
||||
to="https://speckle.guide/"
|
||||
@@ -160,10 +158,20 @@
|
||||
</NuxtLink>
|
||||
</LayoutSidebarMenuGroup>
|
||||
</LayoutSidebarMenu>
|
||||
<template #promo>
|
||||
<LayoutSidebarPromo
|
||||
title="SpeckleCon 2024"
|
||||
text="Join us in London on Nov 13-14 for the ultimate community event."
|
||||
button-text="Get tickets"
|
||||
@on-click="onPromoClick"
|
||||
/>
|
||||
</template>
|
||||
</LayoutSidebar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<FeedbackDialog v-model:open="showFeedbackDialog" />
|
||||
|
||||
<WorkspaceCreateDialog
|
||||
v-model:open="showWorkspaceCreateDialog"
|
||||
navigate-on-success
|
||||
@@ -175,6 +183,7 @@
|
||||
import {
|
||||
FormButton,
|
||||
LayoutSidebar,
|
||||
LayoutSidebarPromo,
|
||||
LayoutSidebarMenu,
|
||||
LayoutSidebarMenuGroup,
|
||||
LayoutSidebarMenuGroupItem
|
||||
@@ -202,6 +211,7 @@ const mixpanel = useMixpanel()
|
||||
|
||||
const isOpenMobile = ref(false)
|
||||
const showWorkspaceCreateDialog = ref(false)
|
||||
const showFeedbackDialog = ref(false)
|
||||
|
||||
const { result: workspaceResult, onResult: onWorkspaceResult } = useQuery(
|
||||
settingsSidebarQuery,
|
||||
@@ -249,4 +259,18 @@ onWorkspaceResult((result) => {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const onPromoClick = () => {
|
||||
mixpanel.track('Promo Banner Clicked', {
|
||||
source: 'sidebar',
|
||||
campaign: 'specklecon2024'
|
||||
})
|
||||
|
||||
window.open('https://conf.speckle.systems/', '_blank')
|
||||
}
|
||||
|
||||
const openFeedbackDialog = () => {
|
||||
showFeedbackDialog.value = true
|
||||
isOpenMobile.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<LayoutDialog
|
||||
v-model:open="isOpen"
|
||||
title="Give us feedback"
|
||||
:buttons="dialogButtons"
|
||||
:on-submit="onSubmit"
|
||||
max-width="md"
|
||||
>
|
||||
<div class="flex flex-col gap-4">
|
||||
<p class="text-body-xs text-foreground font-medium">
|
||||
How can we improve Speckle? If you have a feature request, please also share how
|
||||
you would use it and why it's important to you
|
||||
</p>
|
||||
<FormTextArea
|
||||
v-model="feedback"
|
||||
:rules="[isRequired]"
|
||||
name="feedback"
|
||||
label="Feedback"
|
||||
color="foundation"
|
||||
/>
|
||||
</div>
|
||||
</LayoutDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { LayoutDialogButton } from '@speckle/ui-components'
|
||||
import { useForm } from 'vee-validate'
|
||||
import { useMixpanel } from '~/lib/core/composables/mp'
|
||||
import { useZapier } from '~/lib/core/composables/zapier'
|
||||
import { useGlobalToast, ToastNotificationType } from '~~/lib/common/composables/toast'
|
||||
import { isRequired } from '~/lib/common/helpers/validation'
|
||||
import { useActiveUser } from '~~/lib/auth/composables/activeUser'
|
||||
|
||||
type FormValues = { feedback: string }
|
||||
|
||||
const isOpen = defineModel<boolean>('open', { required: true })
|
||||
|
||||
const { activeUser: user } = useActiveUser()
|
||||
const mixpanel = useMixpanel()
|
||||
const { sendWebhook } = useZapier()
|
||||
const { triggerNotification } = useGlobalToast()
|
||||
const { handleSubmit } = useForm<FormValues>()
|
||||
|
||||
const feedback = ref('')
|
||||
|
||||
const dialogButtons = computed((): LayoutDialogButton[] => [
|
||||
{
|
||||
text: 'Send',
|
||||
props: { color: 'primary' },
|
||||
submit: true,
|
||||
id: 'sendFeedback'
|
||||
}
|
||||
])
|
||||
|
||||
const onSubmit = handleSubmit(async () => {
|
||||
if (!feedback.value) return
|
||||
|
||||
isOpen.value = false
|
||||
|
||||
triggerNotification({
|
||||
type: ToastNotificationType.Success,
|
||||
title: 'Thank you for your feedback!'
|
||||
})
|
||||
|
||||
mixpanel.track('Feedback Sent', {
|
||||
message: feedback.value
|
||||
})
|
||||
|
||||
await sendWebhook('https://hooks.zapier.com/hooks/catch/12120532/2m4okri/', {
|
||||
userId: user.value?.id ?? '',
|
||||
feedback: feedback.value
|
||||
})
|
||||
})
|
||||
|
||||
watch(isOpen, (newVal) => {
|
||||
if (newVal) {
|
||||
feedback.value = ''
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -84,9 +84,8 @@
|
||||
active ? 'bg-highlight-1' : '',
|
||||
'text-body-xs flex px-2 py-1 text-foreground cursor-pointer transition mx-1 rounded'
|
||||
]"
|
||||
target="_blank"
|
||||
to="https://docs.google.com/forms/d/e/1FAIpQLSeTOU8i0KwpgBG7ONimsh4YMqvLKZfSRhWEOz4W0MyjQ1lfAQ/viewform"
|
||||
external
|
||||
class="text-body-xs flex px-2 py-1 text-foreground cursor-pointer transition mx-1 rounded"
|
||||
@click="openFeedbackDialog"
|
||||
>
|
||||
Feedback
|
||||
</NuxtLink>
|
||||
@@ -130,6 +129,7 @@
|
||||
v-model:open="showSettingsDialog"
|
||||
v-model:target-menu-item="settingsDialogTarget"
|
||||
/>
|
||||
<FeedbackDialog v-model:open="showFeedbackDialog" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
@@ -169,6 +169,7 @@ const settingsDialogTarget = ref<string | null>(null)
|
||||
const menuButtonId = useId()
|
||||
const breakpoints = useBreakpoints(TailwindBreakpoints)
|
||||
const isMobile = breakpoints.smaller('md')
|
||||
const showFeedbackDialog = ref(false)
|
||||
|
||||
const version = computed(() => serverInfo.value?.version)
|
||||
const isAdmin = computed(() => activeUser.value?.role === Roles.Server.Admin)
|
||||
@@ -190,6 +191,10 @@ const deleteSettingsQuery = (): void => {
|
||||
router.push({ query: currentQueryParams })
|
||||
}
|
||||
|
||||
const openFeedbackDialog = () => {
|
||||
showFeedbackDialog.value = true
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const settingsQuery = route.query?.settings
|
||||
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<div class="position left-2 sm:left-auto right-2 bottom-2 fixed z-[45]">
|
||||
<div
|
||||
v-if="showBanner"
|
||||
class="rounded-lg flex flex-col w-full sm:max-w-96 border border-outline-2 shadow-md bg-foundation-3 dark:bg-foundation"
|
||||
>
|
||||
<img :src="bannerImage" class="w-full" alt="Try workspaces" />
|
||||
<div class="px-5 py-6 flex flex-col gap-y-2">
|
||||
<h5 class="text-body-xs md:text-heading-sm text-foreground font-medium">
|
||||
Still not using workspaces?
|
||||
</h5>
|
||||
<p class="text-body-2xs leading-5 md:text-body-xs text-foreground-2">
|
||||
Be the first to reach more security options, data control, and better
|
||||
project management with your team.
|
||||
</p>
|
||||
<div class="flex items-center gap-x-2 mt-2">
|
||||
<FormButton color="primary" size="sm" @click="openWorkspaceCreateDialog">
|
||||
Start for free
|
||||
</FormButton>
|
||||
<FormButton color="subtle" size="sm" @click="dismissedCookie = true">
|
||||
Dismiss
|
||||
</FormButton>
|
||||
</div>
|
||||
</div>
|
||||
<WorkspaceCreateDialog
|
||||
v-model:open="showWorkspaceCreateDialog"
|
||||
navigate-on-success
|
||||
event-source="promo-banner"
|
||||
@created="dismissedCookie = true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
// This is a temporary component, to meassure if in app-notifications can be succesful
|
||||
// It will be remove after a certain period, if we continue with in-app notification we should further develop this
|
||||
|
||||
import { useMixpanel } from '~~/lib/core/composables/mp'
|
||||
import { useSynchronizedCookie } from '~~/lib/common/composables/reactiveCookie'
|
||||
import { CookieKeys } from '~/lib/common/helpers/constants'
|
||||
import { useIsWorkspacesEnabled } from '~/composables/globals'
|
||||
import { settingsSidebarQuery } from '~/lib/settings/graphql/queries'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { useTheme } from '~~/lib/core/composables/theme'
|
||||
import { useBreakpoints } from '@vueuse/core'
|
||||
import { TailwindBreakpoints } from '~~/lib/common/helpers/tailwind'
|
||||
import imageLight from '~/assets/images/banners/workspace-promo-light.png'
|
||||
import imageDark from '~/assets/images/banners/workspace-promo-dark.png'
|
||||
import imageMobileLight from '~/assets/images/banners/workspace-promo-mobile-light.png'
|
||||
import imageMobileDark from '~/assets/images/banners/workspace-promo-mobile-dark.png'
|
||||
|
||||
const { isLoggedIn } = useActiveUser()
|
||||
const breakpoints = useBreakpoints(TailwindBreakpoints)
|
||||
const { isDarkTheme } = useTheme()
|
||||
const isWorkspacesEnabled = useIsWorkspacesEnabled()
|
||||
const mixpanel = useMixpanel()
|
||||
const dismissedCookie = useSynchronizedCookie<boolean>(
|
||||
CookieKeys.DismissedWorkspaceBanner,
|
||||
{
|
||||
default: () => false
|
||||
}
|
||||
)
|
||||
const { result } = useQuery(settingsSidebarQuery, null, {
|
||||
enabled: isWorkspacesEnabled.value
|
||||
})
|
||||
|
||||
const showWorkspaceCreateDialog = ref(false)
|
||||
const isMobile = breakpoints.smaller('md')
|
||||
|
||||
const bannerImage = computed(() => {
|
||||
if (isMobile.value) {
|
||||
return isDarkTheme.value ? imageMobileDark : imageMobileLight
|
||||
}
|
||||
return isDarkTheme.value ? imageDark : imageLight
|
||||
})
|
||||
const hasWorkspaces = computed(() =>
|
||||
result.value?.activeUser?.workspaces.items
|
||||
? result.value.activeUser.workspaces.items.length > 0
|
||||
: false
|
||||
)
|
||||
const showBanner = computed(
|
||||
() =>
|
||||
isWorkspacesEnabled.value &&
|
||||
isLoggedIn.value &&
|
||||
!hasWorkspaces.value &&
|
||||
(import.meta.client ? !dismissedCookie.value : false)
|
||||
)
|
||||
|
||||
const openWorkspaceCreateDialog = () => {
|
||||
showWorkspaceCreateDialog.value = true
|
||||
mixpanel.track('Create Workspace Button Clicked', {
|
||||
source: 'promo-banner'
|
||||
})
|
||||
}
|
||||
|
||||
watch(
|
||||
showBanner,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
mixpanel.track('Workspace Promo Banner Viewed', {
|
||||
source: 'promo-banner'
|
||||
})
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
</script>
|
||||
@@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<HeaderNavBar />
|
||||
<PromoBannersWorkspace />
|
||||
<div class="h-dvh w-dvh overflow-hidden flex flex-col">
|
||||
<!-- Static Spacer to allow for absolutely positioned HeaderNavBar -->
|
||||
<div class="h-12 w-full shrink-0"></div>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
export function useZapier() {
|
||||
const sendWebhook = async (webhookUrl: string, data: Record<string, string>) => {
|
||||
const response = await fetch(webhookUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
mode: 'no-cors',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
return {
|
||||
sendWebhook
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,10 @@
|
||||
<Portal to="navigation">
|
||||
<HeaderNavLink :to="homeRoute" name="Dashboard" hide-chevron :separator="false" />
|
||||
</Portal>
|
||||
<PromoBannersWrapper v-if="promoBanners.length" :banners="promoBanners" />
|
||||
<PromoBannersWrapper
|
||||
v-if="promoBanners && promoBanners.length"
|
||||
:banners="promoBanners"
|
||||
/>
|
||||
<ProjectsDashboardHeader
|
||||
:projects-invites="projectsResult?.activeUser || undefined"
|
||||
:workspaces-invites="workspacesResult?.activeUser || undefined"
|
||||
@@ -72,7 +75,6 @@ import { downloadManager } from '~~/lib/common/utils/downloadManager'
|
||||
import { ToastNotificationType, useGlobalToast } from '~~/lib/common/composables/toast'
|
||||
import type { LayoutDialogButton } from '@speckle/ui-components'
|
||||
import type { PromoBanner } from '~/lib/promo-banners/types'
|
||||
import speckleconTicketsImage from '~/assets/images/banners/grab-your-tickets.gif'
|
||||
|
||||
useHead({ title: 'Dashboard' })
|
||||
|
||||
@@ -187,14 +189,5 @@ const onDownloadManager = (extension: ManagerExtension) => {
|
||||
}
|
||||
}
|
||||
|
||||
const promoBanners = ref<PromoBanner[]>([
|
||||
{
|
||||
primaryText: 'Specklecon - Grab your tickets',
|
||||
url: 'https://conf.speckle.systems/',
|
||||
priority: 1,
|
||||
expiryDate: '2024-11-14',
|
||||
image: speckleconTicketsImage,
|
||||
isBackgroundImage: true
|
||||
}
|
||||
])
|
||||
const promoBanners = ref<PromoBanner[]>()
|
||||
</script>
|
||||
|
||||
@@ -16,8 +16,8 @@ import {
|
||||
getStreamBranchesByNameFactory
|
||||
} from '@/modules/core/repositories/branches'
|
||||
import {
|
||||
getAllBranchCommits,
|
||||
getCommitsAndTheirBranchIds,
|
||||
getAllBranchCommitsFactory,
|
||||
getCommitsAndTheirBranchIdsFactory,
|
||||
getSpecificBranchCommitsFactory
|
||||
} from '@/modules/core/repositories/commits'
|
||||
import { getStreamObjects } from '@/modules/core/repositories/objects'
|
||||
@@ -60,7 +60,7 @@ export async function addCommentCreatedActivity(params: {
|
||||
getViewerResourcesFromLegacyIdentifiers: (...args) =>
|
||||
getViewerResourcesFromLegacyIdentifiers(...args) // recursive dep
|
||||
}),
|
||||
getCommitsAndTheirBranchIds,
|
||||
getCommitsAndTheirBranchIds: getCommitsAndTheirBranchIdsFactory({ db }),
|
||||
getStreamObjects
|
||||
})
|
||||
const getViewerResourceItemsUngrouped = getViewerResourceItemsUngroupedFactory({
|
||||
@@ -69,7 +69,7 @@ export async function addCommentCreatedActivity(params: {
|
||||
getBranchLatestCommits: getBranchLatestCommitsFactory({ db }),
|
||||
getStreamBranchesByName: getStreamBranchesByNameFactory({ db }),
|
||||
getSpecificBranchCommits: getSpecificBranchCommitsFactory({ db }),
|
||||
getAllBranchCommits
|
||||
getAllBranchCommits: getAllBranchCommitsFactory({ db })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -146,7 +146,7 @@ export async function addCommentArchivedActivity(params: {
|
||||
getViewerResourcesFromLegacyIdentifiers: (...args) =>
|
||||
getViewerResourcesFromLegacyIdentifiers(...args) // recursive dep
|
||||
}),
|
||||
getCommitsAndTheirBranchIds,
|
||||
getCommitsAndTheirBranchIds: getCommitsAndTheirBranchIdsFactory({ db }),
|
||||
getStreamObjects
|
||||
})
|
||||
|
||||
@@ -208,7 +208,7 @@ export async function addReplyAddedActivity(params: {
|
||||
getViewerResourcesFromLegacyIdentifiers: (...args) =>
|
||||
getViewerResourcesFromLegacyIdentifiers(...args) // recursive dep
|
||||
}),
|
||||
getCommitsAndTheirBranchIds,
|
||||
getCommitsAndTheirBranchIds: getCommitsAndTheirBranchIdsFactory({ db }),
|
||||
getStreamObjects
|
||||
})
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
} from '@/modules/core/services/commit/viewerResources'
|
||||
import {
|
||||
createCommitFactory,
|
||||
getAllBranchCommits,
|
||||
getAllBranchCommitsFactory,
|
||||
getSpecificBranchCommitsFactory,
|
||||
insertBranchCommitsFactory,
|
||||
insertStreamCommitsFactory
|
||||
@@ -102,7 +102,7 @@ const command: CommandModule<
|
||||
getBranchLatestCommits,
|
||||
getStreamBranchesByName: getStreamBranchesByNameFactory({ db }),
|
||||
getSpecificBranchCommits: getSpecificBranchCommitsFactory({ db }),
|
||||
getAllBranchCommits
|
||||
getAllBranchCommits: getAllBranchCommitsFactory({ db })
|
||||
})
|
||||
})
|
||||
const createCommentThreadAndNotify = createCommentThreadAndNotifyFactory({
|
||||
|
||||
@@ -32,7 +32,7 @@ import {
|
||||
} from '@/modules/activitystream/services/commentActivity'
|
||||
import {
|
||||
createCommitFactory,
|
||||
getAllBranchCommits,
|
||||
getAllBranchCommitsFactory,
|
||||
getSpecificBranchCommitsFactory,
|
||||
insertBranchCommitsFactory,
|
||||
insertStreamCommitsFactory
|
||||
@@ -99,7 +99,7 @@ const command: CommandModule<
|
||||
getBranchLatestCommits: getBranchLatestCommitsFactory({ db }),
|
||||
getStreamBranchesByName: getStreamBranchesByNameFactory({ db }),
|
||||
getSpecificBranchCommits: getSpecificBranchCommitsFactory({ db }),
|
||||
getAllBranchCommits
|
||||
getAllBranchCommits: getAllBranchCommitsFactory({ db })
|
||||
})
|
||||
})
|
||||
const createCommentThreadAndNotify = createCommentThreadAndNotifyFactory({
|
||||
|
||||
@@ -86,8 +86,8 @@ import { CommentsEmitter } from '@/modules/comments/events/emitter'
|
||||
import { getBlobsFactory } from '@/modules/blobstorage/repositories'
|
||||
import { ResourceIdentifier } from '@/modules/comments/domain/types'
|
||||
import {
|
||||
getAllBranchCommits,
|
||||
getCommitsAndTheirBranchIds,
|
||||
getAllBranchCommitsFactory,
|
||||
getCommitsAndTheirBranchIdsFactory,
|
||||
getSpecificBranchCommitsFactory
|
||||
} from '@/modules/core/repositories/commits'
|
||||
import { getStreamObjects } from '@/modules/core/repositories/objects'
|
||||
@@ -148,7 +148,7 @@ const getViewerResourcesFromLegacyIdentifiers =
|
||||
getViewerResourcesFromLegacyIdentifiers: (...args) =>
|
||||
getViewerResourcesFromLegacyIdentifiers(...args) // recursive dep
|
||||
}),
|
||||
getCommitsAndTheirBranchIds,
|
||||
getCommitsAndTheirBranchIds: getCommitsAndTheirBranchIdsFactory({ db }),
|
||||
getStreamObjects
|
||||
})
|
||||
|
||||
@@ -179,7 +179,7 @@ const getViewerResourceItemsUngrouped = getViewerResourceItemsUngroupedFactory({
|
||||
getBranchLatestCommits: getBranchLatestCommitsFactory({ db }),
|
||||
getStreamBranchesByName: getStreamBranchesByNameFactory({ db }),
|
||||
getSpecificBranchCommits: getSpecificBranchCommitsFactory({ db }),
|
||||
getAllBranchCommits
|
||||
getAllBranchCommits: getAllBranchCommitsFactory({ db })
|
||||
})
|
||||
})
|
||||
const createCommentThreadAndNotify = createCommentThreadAndNotifyFactory({
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import {
|
||||
BranchCommit,
|
||||
CommitWithStreamBranchMetadata,
|
||||
Commit
|
||||
Commit,
|
||||
CommitBranch
|
||||
} from '@/modules/core/domain/commits/types'
|
||||
import {
|
||||
CommitUpdateInput,
|
||||
UpdateVersionInput
|
||||
} from '@/modules/core/graph/generated/graphql'
|
||||
import { BranchCommitRecord, StreamCommitRecord } from '@/modules/core/helpers/types'
|
||||
import { BatchedSelectOptions } from '@/modules/shared/helpers/dbHelper'
|
||||
import { MaybeNullOrUndefined, Nullable, Optional } from '@speckle/shared'
|
||||
import { Knex } from 'knex'
|
||||
|
||||
@@ -86,3 +92,82 @@ export type InsertStreamCommits = (
|
||||
trx: Knex.Transaction
|
||||
}>
|
||||
) => Promise<number[]>
|
||||
|
||||
export type UpdateCommitAndNotify = (
|
||||
params: CommitUpdateInput | UpdateVersionInput,
|
||||
userId: string
|
||||
) => Promise<Commit>
|
||||
|
||||
export type GetCommitBranches = (commitIds: string[]) => Promise<CommitBranch[]>
|
||||
|
||||
export type GetCommitBranch = (commitId: string) => Promise<Optional<CommitBranch>>
|
||||
|
||||
export type SwitchCommitBranch = (
|
||||
commitId: string,
|
||||
newBranchId: string,
|
||||
oldBranchId?: string
|
||||
) => Promise<void>
|
||||
|
||||
export type UpdateCommit = (
|
||||
commitId: string,
|
||||
commit: Partial<Commit>
|
||||
) => Promise<Commit>
|
||||
|
||||
export type GetAllBranchCommits = (params: {
|
||||
branchIds?: string[]
|
||||
projectId?: string
|
||||
}) => Promise<{ [branchId: string]: Commit[] }>
|
||||
|
||||
export type GetStreamCommitCounts = (
|
||||
streamIds: string[],
|
||||
options?: Partial<{
|
||||
ignoreGlobalsBranch: boolean
|
||||
}>
|
||||
) => Promise<
|
||||
{
|
||||
count: number
|
||||
streamId: string
|
||||
}[]
|
||||
>
|
||||
|
||||
export type GetStreamCommitCount = (
|
||||
streamId: string,
|
||||
options?: Partial<{
|
||||
ignoreGlobalsBranch: boolean
|
||||
}>
|
||||
) => Promise<number>
|
||||
|
||||
export type GetUserStreamCommitCounts = (params: {
|
||||
userIds: string[]
|
||||
publicOnly?: boolean
|
||||
}) => Promise<{
|
||||
[userId: string]: number
|
||||
}>
|
||||
|
||||
export type GetUserAuthoredCommitCounts = (params: {
|
||||
userIds: string[]
|
||||
publicOnly?: boolean
|
||||
}) => Promise<{
|
||||
[userId: string]: number
|
||||
}>
|
||||
|
||||
export type GetCommitsAndTheirBranchIds = (
|
||||
commitIds: string[]
|
||||
) => Promise<BranchCommit[]>
|
||||
|
||||
export type GetBatchedStreamCommits = (
|
||||
streamId: string,
|
||||
options?: Partial<BatchedSelectOptions>
|
||||
) => AsyncGenerator<Commit[], void, unknown>
|
||||
|
||||
export type GetBatchedBranchCommits = (
|
||||
branchIds: string[],
|
||||
options?: Partial<BatchedSelectOptions>
|
||||
) => AsyncGenerator<BranchCommitRecord[], void, unknown>
|
||||
|
||||
export type InsertCommits = (
|
||||
commits: Commit[],
|
||||
options?: Partial<{
|
||||
trx: Knex.Transaction
|
||||
}>
|
||||
) => Promise<number[]>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Branch } from '@/modules/core/domain/branches/types'
|
||||
import { CommitRecord } from '@/modules/core/helpers/types'
|
||||
|
||||
export type Commit = CommitRecord
|
||||
@@ -11,3 +12,5 @@ export type CommitWithStreamBranchMetadata = Commit & {
|
||||
branchId: string
|
||||
branchName: string
|
||||
}
|
||||
|
||||
export type CommitBranch = Branch & { commitId: string }
|
||||
|
||||
@@ -16,11 +16,11 @@ const {
|
||||
getPaginatedBranchCommits
|
||||
} = require('@/modules/core/services/commit/retrieval')
|
||||
const {
|
||||
updateCommitAndNotify,
|
||||
markCommitReceivedAndNotify,
|
||||
deleteCommitAndNotifyFactory,
|
||||
createCommitByBranchIdFactory,
|
||||
createCommitByBranchNameFactory
|
||||
createCommitByBranchNameFactory,
|
||||
updateCommitAndNotifyFactory
|
||||
} = require('@/modules/core/services/commit/management')
|
||||
|
||||
const { RateLimitError } = require('@/modules/core/errors/ratelimit')
|
||||
@@ -44,10 +44,17 @@ const {
|
||||
deleteCommitFactory,
|
||||
createCommitFactory,
|
||||
insertStreamCommitsFactory,
|
||||
insertBranchCommitsFactory
|
||||
insertBranchCommitsFactory,
|
||||
getCommitBranchFactory,
|
||||
switchCommitBranchFactory,
|
||||
updateCommitFactory
|
||||
} = require('@/modules/core/repositories/commits')
|
||||
const { db } = require('@/db/knex')
|
||||
const { markCommitStreamUpdated } = require('@/modules/core/repositories/streams')
|
||||
const {
|
||||
markCommitStreamUpdated,
|
||||
getStream,
|
||||
getCommitStream
|
||||
} = require('@/modules/core/repositories/streams')
|
||||
const {
|
||||
markCommitBranchUpdatedFactory,
|
||||
getBranchByIdFactory,
|
||||
@@ -55,7 +62,8 @@ const {
|
||||
} = require('@/modules/core/repositories/branches')
|
||||
const {
|
||||
addCommitDeletedActivity,
|
||||
addCommitCreatedActivity
|
||||
addCommitCreatedActivity,
|
||||
addCommitUpdatedActivity
|
||||
} = require('@/modules/activitystream/services/commitActivity')
|
||||
const { getObject } = require('@/modules/core/repositories/objects')
|
||||
const { VersionsEmitter } = require('@/modules/core/events/versionsEmitter')
|
||||
@@ -91,6 +99,19 @@ const createCommitByBranchName = createCommitByBranchNameFactory({
|
||||
getBranchById: getBranchByIdFactory({ db })
|
||||
})
|
||||
|
||||
const updateCommitAndNotify = updateCommitAndNotifyFactory({
|
||||
getCommit: getCommitFactory({ db }),
|
||||
getStream,
|
||||
getCommitStream,
|
||||
getStreamBranchByName: getStreamBranchByNameFactory({ db }),
|
||||
getCommitBranch: getCommitBranchFactory({ db }),
|
||||
switchCommitBranch: switchCommitBranchFactory({ db }),
|
||||
updateCommit: updateCommitFactory({ db }),
|
||||
addCommitUpdatedActivity,
|
||||
markCommitStreamUpdated,
|
||||
markCommitBranchUpdated: markCommitBranchUpdatedFactory({ db })
|
||||
})
|
||||
|
||||
/**
|
||||
* @param {boolean} publicOnly
|
||||
* @param {string} userId
|
||||
|
||||
@@ -41,7 +41,7 @@ import { BranchNotFoundError } from '@/modules/core/errors/branch'
|
||||
import { CommitNotFoundError } from '@/modules/core/errors/commit'
|
||||
import { getStreamObjects } from '@/modules/core/repositories/objects'
|
||||
import {
|
||||
getAllBranchCommits,
|
||||
getAllBranchCommitsFactory,
|
||||
getSpecificBranchCommitsFactory
|
||||
} from '@/modules/core/repositories/commits'
|
||||
import { db } from '@/db/knex'
|
||||
@@ -58,7 +58,7 @@ const getViewerResourceGroups = getViewerResourceGroupsFactory({
|
||||
getBranchLatestCommits: getBranchLatestCommitsFactory({ db }),
|
||||
getStreamBranchesByName: getStreamBranchesByNameFactory({ db }),
|
||||
getSpecificBranchCommits: getSpecificBranchCommitsFactory({ db }),
|
||||
getAllBranchCommits
|
||||
getAllBranchCommits: getAllBranchCommitsFactory({ db })
|
||||
})
|
||||
|
||||
const getPaginatedProjectModels = getPaginatedProjectModelsFactory({
|
||||
|
||||
@@ -14,7 +14,7 @@ import { CommitUpdateError } from '@/modules/core/errors/commit'
|
||||
import {
|
||||
createCommitByBranchIdFactory,
|
||||
markCommitReceivedAndNotify,
|
||||
updateCommitAndNotify
|
||||
updateCommitAndNotifyFactory
|
||||
} from '@/modules/core/services/commit/management'
|
||||
import {
|
||||
getRateLimitResult,
|
||||
@@ -23,18 +23,30 @@ import {
|
||||
import { RateLimitError } from '@/modules/core/errors/ratelimit'
|
||||
import {
|
||||
createCommitFactory,
|
||||
getCommitBranchFactory,
|
||||
getCommitFactory,
|
||||
insertBranchCommitsFactory,
|
||||
insertStreamCommitsFactory
|
||||
insertStreamCommitsFactory,
|
||||
switchCommitBranchFactory,
|
||||
updateCommitFactory
|
||||
} from '@/modules/core/repositories/commits'
|
||||
import { db } from '@/db/knex'
|
||||
import { getObject } from '@/modules/core/repositories/objects'
|
||||
import {
|
||||
getBranchByIdFactory,
|
||||
getStreamBranchByNameFactory,
|
||||
markCommitBranchUpdatedFactory
|
||||
} from '@/modules/core/repositories/branches'
|
||||
import { markCommitStreamUpdated } from '@/modules/core/repositories/streams'
|
||||
import {
|
||||
getCommitStream,
|
||||
getStream,
|
||||
markCommitStreamUpdated
|
||||
} from '@/modules/core/repositories/streams'
|
||||
import { VersionsEmitter } from '@/modules/core/events/versionsEmitter'
|
||||
import { addCommitCreatedActivity } from '@/modules/activitystream/services/commitActivity'
|
||||
import {
|
||||
addCommitCreatedActivity,
|
||||
addCommitUpdatedActivity
|
||||
} from '@/modules/activitystream/services/commitActivity'
|
||||
|
||||
const createCommitByBranchId = createCommitByBranchIdFactory({
|
||||
createCommit: createCommitFactory({ db }),
|
||||
@@ -48,6 +60,19 @@ const createCommitByBranchId = createCommitByBranchIdFactory({
|
||||
addCommitCreatedActivity
|
||||
})
|
||||
|
||||
const updateCommitAndNotify = updateCommitAndNotifyFactory({
|
||||
getCommit: getCommitFactory({ db }),
|
||||
getStream,
|
||||
getCommitStream,
|
||||
getStreamBranchByName: getStreamBranchByNameFactory({ db }),
|
||||
getCommitBranch: getCommitBranchFactory({ db }),
|
||||
switchCommitBranch: switchCommitBranchFactory({ db }),
|
||||
updateCommit: updateCommitFactory({ db }),
|
||||
addCommitUpdatedActivity,
|
||||
markCommitStreamUpdated,
|
||||
markCommitBranchUpdated: markCommitBranchUpdatedFactory({ db })
|
||||
})
|
||||
|
||||
export = {
|
||||
Project: {
|
||||
async version(parent, args, ctx) {
|
||||
|
||||
@@ -23,12 +23,12 @@ import {
|
||||
import { Nullable } from '@/modules/shared/helpers/typeHelper'
|
||||
import { ServerInviteRecord } from '@/modules/serverinvites/domain/types'
|
||||
import {
|
||||
getCommitBranches,
|
||||
getCommitBranchesFactory,
|
||||
getCommitsFactory,
|
||||
getSpecificBranchCommitsFactory,
|
||||
getStreamCommitCounts,
|
||||
getUserAuthoredCommitCounts,
|
||||
getUserStreamCommitCounts
|
||||
getStreamCommitCountsFactory,
|
||||
getUserAuthoredCommitCountsFactory,
|
||||
getUserStreamCommitCountsFactory
|
||||
} from '@/modules/core/repositories/commits'
|
||||
import { ResourceIdentifier, Scope } from '@/modules/core/graph/generated/graphql'
|
||||
import {
|
||||
@@ -112,6 +112,10 @@ const getStreamBranchCounts = getStreamBranchCountsFactory({ db })
|
||||
const getBranchCommitCounts = getBranchCommitCountsFactory({ db })
|
||||
const getCommits = getCommitsFactory({ db })
|
||||
const getSpecificBranchCommits = getSpecificBranchCommitsFactory({ db })
|
||||
const getCommitBranches = getCommitBranchesFactory({ db })
|
||||
const getStreamCommitCounts = getStreamCommitCountsFactory({ db })
|
||||
const getUserStreamCommitCounts = getUserStreamCommitCountsFactory({ db })
|
||||
const getUserAuthoredCommitCounts = getUserAuthoredCommitCountsFactory({ db })
|
||||
|
||||
/**
|
||||
* TODO: Lazy load DataLoaders to reduce memory usage
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
BranchCommitRecord,
|
||||
BranchRecord,
|
||||
CommitRecord,
|
||||
StreamAclRecord,
|
||||
StreamCommitRecord
|
||||
} from '@/modules/core/helpers/types'
|
||||
import { clamp, uniq, uniqBy, reduce, keyBy, mapValues } from 'lodash'
|
||||
@@ -30,13 +31,27 @@ import {
|
||||
GetCommits,
|
||||
GetSpecificBranchCommits,
|
||||
InsertBranchCommits,
|
||||
InsertStreamCommits
|
||||
InsertStreamCommits,
|
||||
GetCommitBranches,
|
||||
GetCommitBranch,
|
||||
SwitchCommitBranch,
|
||||
UpdateCommit,
|
||||
GetAllBranchCommits,
|
||||
GetStreamCommitCounts,
|
||||
GetStreamCommitCount,
|
||||
GetUserStreamCommitCounts,
|
||||
GetUserAuthoredCommitCounts,
|
||||
GetCommitsAndTheirBranchIds,
|
||||
GetBatchedStreamCommits,
|
||||
GetBatchedBranchCommits,
|
||||
InsertCommits
|
||||
} from '@/modules/core/domain/commits/operations'
|
||||
|
||||
const tables = {
|
||||
commits: (db: Knex) => db<CommitRecord>(Commits.name),
|
||||
branchCommits: (db: Knex) => db<BranchCommitRecord>(BranchCommits.name),
|
||||
streamCommits: (db: Knex) => db<StreamCommitRecord>(StreamCommits.name)
|
||||
streamCommits: (db: Knex) => db<StreamCommitRecord>(StreamCommits.name),
|
||||
streamAcl: (db: Knex) => db<StreamAclRecord>(StreamAcl.name)
|
||||
}
|
||||
|
||||
export const generateCommitId = () => crs({ length: 10 })
|
||||
@@ -121,38 +136,38 @@ export const deleteCommitFactory =
|
||||
return !!delCount
|
||||
}
|
||||
|
||||
export function getBatchedStreamCommits(
|
||||
streamId: string,
|
||||
options?: Partial<BatchedSelectOptions>
|
||||
) {
|
||||
const baseQuery = Commits.knex<CommitRecord[]>()
|
||||
.select<CommitRecord[]>(Commits.cols)
|
||||
.innerJoin(StreamCommits.name, StreamCommits.col.commitId, Commits.col.id)
|
||||
.where(StreamCommits.col.streamId, streamId)
|
||||
.orderBy(Commits.col.id)
|
||||
export const getBatchedStreamCommitsFactory =
|
||||
(deps: { db: Knex }): GetBatchedStreamCommits =>
|
||||
(streamId: string, options?: Partial<BatchedSelectOptions>) => {
|
||||
const baseQuery = tables
|
||||
.commits(deps.db)
|
||||
.select<CommitRecord[]>(Commits.cols)
|
||||
.innerJoin(StreamCommits.name, StreamCommits.col.commitId, Commits.col.id)
|
||||
.where(StreamCommits.col.streamId, streamId)
|
||||
.orderBy(Commits.col.id)
|
||||
|
||||
return executeBatchedSelect(baseQuery, options)
|
||||
}
|
||||
return executeBatchedSelect(baseQuery, options)
|
||||
}
|
||||
|
||||
export function getBatchedBranchCommits(
|
||||
branchIds: string[],
|
||||
options?: Partial<BatchedSelectOptions>
|
||||
) {
|
||||
const baseQuery = BranchCommits.knex<BranchCommitRecord[]>()
|
||||
.whereIn(BranchCommits.col.branchId, branchIds)
|
||||
.orderBy(BranchCommits.col.branchId)
|
||||
export const getBatchedBranchCommitsFactory =
|
||||
(deps: { db: Knex }): GetBatchedBranchCommits =>
|
||||
(branchIds: string[], options?: Partial<BatchedSelectOptions>) => {
|
||||
const baseQuery = tables
|
||||
.branchCommits(deps.db)
|
||||
.select<BranchCommitRecord[]>('*')
|
||||
.whereIn(BranchCommits.col.branchId, branchIds)
|
||||
.orderBy(BranchCommits.col.branchId)
|
||||
|
||||
return executeBatchedSelect(baseQuery, options)
|
||||
}
|
||||
return executeBatchedSelect(baseQuery, options)
|
||||
}
|
||||
|
||||
export async function insertCommits(
|
||||
commits: CommitRecord[],
|
||||
options?: Partial<{ trx: Knex.Transaction }>
|
||||
) {
|
||||
const q = Commits.knex().insert(commits)
|
||||
if (options?.trx) q.transacting(options.trx)
|
||||
return await q
|
||||
}
|
||||
export const insertCommitsFactory =
|
||||
(deps: { db: Knex }): InsertCommits =>
|
||||
async (commits: CommitRecord[], options?: Partial<{ trx: Knex.Transaction }>) => {
|
||||
const q = tables.commits(deps.db).insert(commits)
|
||||
if (options?.trx) q.transacting(options.trx)
|
||||
return await q
|
||||
}
|
||||
|
||||
export const insertStreamCommitsFactory =
|
||||
(deps: { db: Knex }): InsertStreamCommits =>
|
||||
@@ -176,53 +191,55 @@ export const insertBranchCommitsFactory =
|
||||
return await q
|
||||
}
|
||||
|
||||
export async function getStreamCommitCounts(
|
||||
streamIds: string[],
|
||||
options?: Partial<{ ignoreGlobalsBranch: boolean }>
|
||||
) {
|
||||
if (!streamIds?.length) return []
|
||||
export const getStreamCommitCountsFactory =
|
||||
(deps: { db: Knex }): GetStreamCommitCounts =>
|
||||
async (streamIds: string[], options?: Partial<{ ignoreGlobalsBranch: boolean }>) => {
|
||||
if (!streamIds?.length) return []
|
||||
|
||||
const { ignoreGlobalsBranch } = options || {}
|
||||
const { ignoreGlobalsBranch } = options || {}
|
||||
|
||||
const q = StreamCommits.knex()
|
||||
.select(StreamCommits.col.streamId)
|
||||
.whereIn(StreamCommits.col.streamId, streamIds)
|
||||
.count()
|
||||
.groupBy(StreamCommits.col.streamId)
|
||||
const q = tables
|
||||
.streamCommits(deps.db)
|
||||
.select(StreamCommits.col.streamId)
|
||||
.whereIn(StreamCommits.col.streamId, streamIds)
|
||||
.count()
|
||||
.groupBy(StreamCommits.col.streamId)
|
||||
|
||||
if (ignoreGlobalsBranch) {
|
||||
q.innerJoin(
|
||||
BranchCommits.name,
|
||||
StreamCommits.col.commitId,
|
||||
BranchCommits.col.commitId
|
||||
)
|
||||
.innerJoin(Branches.name, Branches.col.id, BranchCommits.col.branchId)
|
||||
.andWhereNot(Branches.col.name, 'globals')
|
||||
if (ignoreGlobalsBranch) {
|
||||
q.innerJoin(
|
||||
BranchCommits.name,
|
||||
StreamCommits.col.commitId,
|
||||
BranchCommits.col.commitId
|
||||
)
|
||||
.innerJoin(Branches.name, Branches.col.id, BranchCommits.col.branchId)
|
||||
.andWhereNot(Branches.col.name, 'globals')
|
||||
}
|
||||
|
||||
const results = (await q) as { streamId: string; count: string }[]
|
||||
return results.map((r) => ({ ...r, count: parseInt(r.count) }))
|
||||
}
|
||||
|
||||
const results = (await q) as { streamId: string; count: string }[]
|
||||
return results.map((r) => ({ ...r, count: parseInt(r.count) }))
|
||||
}
|
||||
export const getStreamCommitCountFactory =
|
||||
(deps: { db: Knex }): GetStreamCommitCount =>
|
||||
async (streamId: string, options?: Partial<{ ignoreGlobalsBranch: boolean }>) => {
|
||||
const [res] = await getStreamCommitCountsFactory(deps)([streamId], options)
|
||||
return res?.count || 0
|
||||
}
|
||||
|
||||
export async function getStreamCommitCount(
|
||||
streamId: string,
|
||||
options?: Partial<{ ignoreGlobalsBranch: boolean }>
|
||||
) {
|
||||
const [res] = await getStreamCommitCounts([streamId], options)
|
||||
return res?.count || 0
|
||||
}
|
||||
export const getCommitsAndTheirBranchIdsFactory =
|
||||
(deps: { db: Knex }): GetCommitsAndTheirBranchIds =>
|
||||
async (commitIds: string[]) => {
|
||||
if (!commitIds.length) return []
|
||||
|
||||
export async function getCommitsAndTheirBranchIds(commitIds: string[]) {
|
||||
if (!commitIds.length) return []
|
||||
|
||||
return await Commits.knex()
|
||||
.select<Array<CommitRecord & { branchId: string }>>([
|
||||
...Commits.cols,
|
||||
BranchCommits.col.branchId
|
||||
])
|
||||
.innerJoin(BranchCommits.name, BranchCommits.col.commitId, Commits.col.id)
|
||||
.whereIn(Commits.col.id, commitIds)
|
||||
}
|
||||
return await tables
|
||||
.commits(deps.db)
|
||||
.select<Array<CommitRecord & { branchId: string }>>([
|
||||
...Commits.cols,
|
||||
BranchCommits.col.branchId
|
||||
])
|
||||
.innerJoin(BranchCommits.name, BranchCommits.col.commitId, Commits.col.id)
|
||||
.whereIn(Commits.col.id, commitIds)
|
||||
}
|
||||
|
||||
export const getSpecificBranchCommitsFactory =
|
||||
(deps: { db: Knex }): GetSpecificBranchCommits =>
|
||||
@@ -321,47 +338,54 @@ export async function getBranchCommitsTotalCount(
|
||||
return parseInt(res?.count || '0')
|
||||
}
|
||||
|
||||
export async function getCommitBranches(commitIds: string[]) {
|
||||
if (!commitIds?.length) return []
|
||||
export const getCommitBranchesFactory =
|
||||
(deps: { db: Knex }): GetCommitBranches =>
|
||||
async (commitIds: string[]) => {
|
||||
if (!commitIds?.length) return []
|
||||
|
||||
const q = BranchCommits.knex()
|
||||
.select<Array<BranchRecord & { commitId: string }>>([
|
||||
...Branches.cols,
|
||||
knex.raw(`?? as "commitId"`, [BranchCommits.col.commitId])
|
||||
])
|
||||
.innerJoin(Branches.name, Branches.col.id, BranchCommits.col.branchId)
|
||||
.whereIn(BranchCommits.col.commitId, commitIds)
|
||||
const q = tables
|
||||
.branchCommits(deps.db)
|
||||
.select<Array<BranchRecord & { commitId: string }>>([
|
||||
...Branches.cols,
|
||||
knex.raw(`?? as "commitId"`, [BranchCommits.col.commitId])
|
||||
])
|
||||
.innerJoin(Branches.name, Branches.col.id, BranchCommits.col.branchId)
|
||||
.whereIn(BranchCommits.col.commitId, commitIds)
|
||||
|
||||
return await q
|
||||
}
|
||||
|
||||
export async function getCommitBranch(commitId: string) {
|
||||
const [commit] = await getCommitBranches([commitId])
|
||||
return commit as Optional<typeof commit>
|
||||
}
|
||||
|
||||
export async function switchCommitBranch(
|
||||
commitId: string,
|
||||
newBranchId: string,
|
||||
oldBranchId?: string
|
||||
) {
|
||||
const q = BranchCommits.knex()
|
||||
.where(BranchCommits.col.commitId, commitId)
|
||||
.update(BranchCommits.withoutTablePrefix.col.branchId, newBranchId)
|
||||
|
||||
if (oldBranchId) {
|
||||
q.andWhere(BranchCommits.col.branchId, oldBranchId)
|
||||
return await q
|
||||
}
|
||||
|
||||
await q
|
||||
}
|
||||
export const getCommitBranchFactory =
|
||||
(deps: { db: Knex }): GetCommitBranch =>
|
||||
async (commitId: string) => {
|
||||
const [commit] = await getCommitBranchesFactory(deps)([commitId])
|
||||
return commit as Optional<typeof commit>
|
||||
}
|
||||
|
||||
export async function updateCommit(commitId: string, commit: Partial<CommitRecord>) {
|
||||
const [newCommit] = (await Commits.knex()
|
||||
.where(Commits.col.id, commitId)
|
||||
.update(commit, '*')) as CommitRecord[]
|
||||
return newCommit
|
||||
}
|
||||
export const switchCommitBranchFactory =
|
||||
(deps: { db: Knex }): SwitchCommitBranch =>
|
||||
async (commitId: string, newBranchId: string, oldBranchId?: string) => {
|
||||
const q = tables
|
||||
.branchCommits(deps.db)
|
||||
.where(BranchCommits.col.commitId, commitId)
|
||||
.update(BranchCommits.withoutTablePrefix.col.branchId, newBranchId)
|
||||
|
||||
if (oldBranchId) {
|
||||
q.andWhere(BranchCommits.col.branchId, oldBranchId)
|
||||
}
|
||||
|
||||
await q
|
||||
}
|
||||
|
||||
export const updateCommitFactory =
|
||||
(deps: { db: Knex }): UpdateCommit =>
|
||||
async (commitId: string, commit: Partial<CommitRecord>) => {
|
||||
const [newCommit] = (await tables
|
||||
.commits(deps.db)
|
||||
.where(Commits.col.id, commitId)
|
||||
.update(commit, '*')) as CommitRecord[]
|
||||
return newCommit
|
||||
}
|
||||
|
||||
export const createCommitFactory =
|
||||
(deps: { db: Knex }): StoreCommit =>
|
||||
@@ -407,97 +431,106 @@ export async function getObjectCommitsWithStreamIds(
|
||||
return await q
|
||||
}
|
||||
|
||||
export async function getAllBranchCommits(params: {
|
||||
branchIds?: string[]
|
||||
projectId?: string
|
||||
}): Promise<Record<string, CommitRecord[]>> {
|
||||
const { branchIds, projectId } = params
|
||||
if (!branchIds?.length && !projectId) return {}
|
||||
export const getAllBranchCommitsFactory =
|
||||
(deps: { db: Knex }): GetAllBranchCommits =>
|
||||
async (params: {
|
||||
branchIds?: string[]
|
||||
projectId?: string
|
||||
}): Promise<Record<string, CommitRecord[]>> => {
|
||||
const { branchIds, projectId } = params
|
||||
if (!branchIds?.length && !projectId) return {}
|
||||
|
||||
const q = BranchCommits.knex()
|
||||
.select<Array<CommitRecord & { branchId: string }>>([
|
||||
...Commits.cols,
|
||||
BranchCommits.col.branchId
|
||||
])
|
||||
.innerJoin(Commits.name, Commits.col.id, BranchCommits.col.commitId)
|
||||
const q = tables
|
||||
.branchCommits(deps.db)
|
||||
.select<Array<CommitRecord & { branchId: string }>>([
|
||||
...Commits.cols,
|
||||
BranchCommits.col.branchId
|
||||
])
|
||||
.innerJoin(Commits.name, Commits.col.id, BranchCommits.col.commitId)
|
||||
|
||||
if (branchIds?.length) {
|
||||
q.whereIn(BranchCommits.col.branchId, branchIds)
|
||||
if (branchIds?.length) {
|
||||
q.whereIn(BranchCommits.col.branchId, branchIds)
|
||||
}
|
||||
|
||||
if (projectId) {
|
||||
q.innerJoin(Branches.name, Branches.col.id, BranchCommits.col.branchId)
|
||||
q.andWhere(Branches.col.streamId, projectId)
|
||||
}
|
||||
|
||||
const res = await q
|
||||
return reduce(
|
||||
res,
|
||||
(res, item) => {
|
||||
const branchId = item.branchId
|
||||
;(res[branchId] = res[branchId] || []).push(item)
|
||||
return res
|
||||
},
|
||||
{} as Record<string, CommitRecord[]>
|
||||
)
|
||||
}
|
||||
|
||||
if (projectId) {
|
||||
q.innerJoin(Branches.name, Branches.col.id, BranchCommits.col.branchId)
|
||||
q.andWhere(Branches.col.streamId, projectId)
|
||||
export const getUserStreamCommitCountsFactory =
|
||||
(deps: { db: Knex }): GetUserStreamCommitCounts =>
|
||||
async (params: {
|
||||
userIds: string[]
|
||||
/**
|
||||
* Only include commits from public/discoverable streams
|
||||
*/
|
||||
publicOnly?: boolean
|
||||
}) => {
|
||||
const { userIds, publicOnly } = params
|
||||
if (!userIds?.length) return {}
|
||||
|
||||
const q = tables
|
||||
.streamAcl(deps.db)
|
||||
.select<{ userId: string; count: string }[]>([
|
||||
StreamAcl.col.userId,
|
||||
knex.raw('COUNT(*)')
|
||||
])
|
||||
.join(StreamCommits.name, StreamCommits.col.streamId, StreamAcl.col.resourceId)
|
||||
.whereIn(StreamAcl.col.userId, userIds)
|
||||
.groupBy(StreamAcl.col.userId)
|
||||
|
||||
if (publicOnly) {
|
||||
q.join(Streams.name, Streams.col.id, StreamAcl.col.resourceId)
|
||||
q.andWhere((q1) => {
|
||||
q1.where(Streams.col.isPublic, true).orWhere(Streams.col.isDiscoverable, true)
|
||||
})
|
||||
}
|
||||
|
||||
const res = await q
|
||||
return mapValues(keyBy(res, 'userId'), (r) => parseInt(r.count))
|
||||
}
|
||||
|
||||
const res = await q
|
||||
return reduce(
|
||||
res,
|
||||
(res, item) => {
|
||||
const branchId = item.branchId
|
||||
;(res[branchId] = res[branchId] || []).push(item)
|
||||
return res
|
||||
},
|
||||
{} as Record<string, CommitRecord[]>
|
||||
)
|
||||
}
|
||||
export const getUserAuthoredCommitCountsFactory =
|
||||
(deps: { db: Knex }): GetUserAuthoredCommitCounts =>
|
||||
async (params: {
|
||||
userIds: string[]
|
||||
/**
|
||||
* Only include commits from public/discoverable streams
|
||||
*/
|
||||
publicOnly?: boolean
|
||||
}) => {
|
||||
const { userIds, publicOnly } = params
|
||||
if (!userIds?.length) return {}
|
||||
|
||||
export async function getUserStreamCommitCounts(params: {
|
||||
userIds: string[]
|
||||
/**
|
||||
* Only include commits from public/discoverable streams
|
||||
*/
|
||||
publicOnly?: boolean
|
||||
}) {
|
||||
const { userIds, publicOnly } = params
|
||||
if (!userIds?.length) return {}
|
||||
const q = tables
|
||||
.commits(deps.db)
|
||||
.select<{ authorId: string; count: string }[]>([
|
||||
Commits.col.author,
|
||||
knex.raw('COUNT(*)')
|
||||
])
|
||||
.whereIn(Commits.col.author, userIds)
|
||||
.groupBy(Commits.col.author)
|
||||
|
||||
const q = StreamAcl.knex()
|
||||
.select<{ userId: string; count: string }[]>([
|
||||
StreamAcl.col.userId,
|
||||
knex.raw('COUNT(*)')
|
||||
])
|
||||
.join(StreamCommits.name, StreamCommits.col.streamId, StreamAcl.col.resourceId)
|
||||
.whereIn(StreamAcl.col.userId, userIds)
|
||||
.groupBy(StreamAcl.col.userId)
|
||||
if (publicOnly) {
|
||||
q.join(StreamCommits.name, StreamCommits.col.commitId, Commits.col.id)
|
||||
q.join(Streams.name, Streams.col.id, StreamCommits.col.streamId)
|
||||
q.andWhere((q1) => {
|
||||
q1.where(Streams.col.isPublic, true).orWhere(Streams.col.isDiscoverable, true)
|
||||
})
|
||||
}
|
||||
|
||||
if (publicOnly) {
|
||||
q.join(Streams.name, Streams.col.id, StreamAcl.col.resourceId)
|
||||
q.andWhere((q1) => {
|
||||
q1.where(Streams.col.isPublic, true).orWhere(Streams.col.isDiscoverable, true)
|
||||
})
|
||||
const res = await q
|
||||
return mapValues(keyBy(res, 'author'), (r) => parseInt(r.count))
|
||||
}
|
||||
|
||||
const res = await q
|
||||
return mapValues(keyBy(res, 'userId'), (r) => parseInt(r.count))
|
||||
}
|
||||
|
||||
export async function getUserAuthoredCommitCounts(params: {
|
||||
userIds: string[]
|
||||
/**
|
||||
* Only include commits from public/discoverable streams
|
||||
*/
|
||||
publicOnly?: boolean
|
||||
}) {
|
||||
const { userIds, publicOnly } = params
|
||||
if (!userIds?.length) return {}
|
||||
|
||||
const q = Commits.knex()
|
||||
.select<{ authorId: string; count: string }[]>([
|
||||
Commits.col.author,
|
||||
knex.raw('COUNT(*)')
|
||||
])
|
||||
.whereIn(Commits.col.author, userIds)
|
||||
.groupBy(Commits.col.author)
|
||||
|
||||
if (publicOnly) {
|
||||
q.join(StreamCommits.name, StreamCommits.col.commitId, Commits.col.id)
|
||||
q.join(Streams.name, Streams.col.id, StreamCommits.col.streamId)
|
||||
q.andWhere((q1) => {
|
||||
q1.where(Streams.col.isPublic, true).orWhere(Streams.col.isDiscoverable, true)
|
||||
})
|
||||
}
|
||||
|
||||
const res = await q
|
||||
return mapValues(keyBy(res, 'author'), (r) => parseInt(r.count))
|
||||
}
|
||||
|
||||
@@ -16,9 +16,13 @@ import {
|
||||
DeleteCommit,
|
||||
DeleteCommitAndNotify,
|
||||
GetCommit,
|
||||
GetCommitBranch,
|
||||
InsertBranchCommits,
|
||||
InsertStreamCommits,
|
||||
StoreCommit
|
||||
StoreCommit,
|
||||
SwitchCommitBranch,
|
||||
UpdateCommit,
|
||||
UpdateCommitAndNotify
|
||||
} from '@/modules/core/domain/commits/operations'
|
||||
import {
|
||||
CommitCreateError,
|
||||
@@ -37,16 +41,7 @@ import {
|
||||
UpdateVersionInput
|
||||
} from '@/modules/core/graph/generated/graphql'
|
||||
import { CommitRecord } from '@/modules/core/helpers/types'
|
||||
import {
|
||||
getStreamBranchByNameFactory,
|
||||
markCommitBranchUpdatedFactory
|
||||
} from '@/modules/core/repositories/branches'
|
||||
import {
|
||||
getCommitBranch,
|
||||
getCommitFactory,
|
||||
switchCommitBranch,
|
||||
updateCommit
|
||||
} from '@/modules/core/repositories/commits'
|
||||
import { getCommitFactory } from '@/modules/core/repositories/commits'
|
||||
import { getObject } from '@/modules/core/repositories/objects'
|
||||
import {
|
||||
getCommitStream,
|
||||
@@ -255,99 +250,111 @@ const isOldVersionUpdateInput = (
|
||||
i: CommitUpdateInput | UpdateVersionInput
|
||||
): i is CommitUpdateInput => has(i, 'streamId')
|
||||
|
||||
export async function updateCommitAndNotify(
|
||||
params: CommitUpdateInput | UpdateVersionInput,
|
||||
userId: string
|
||||
) {
|
||||
const {
|
||||
message,
|
||||
newBranchName,
|
||||
streamId,
|
||||
id: commitId
|
||||
} = isOldVersionUpdateInput(params)
|
||||
? params
|
||||
: {
|
||||
message: params.message,
|
||||
id: params.versionId,
|
||||
streamId: null,
|
||||
newBranchName: null
|
||||
}
|
||||
export const updateCommitAndNotifyFactory =
|
||||
(deps: {
|
||||
getCommit: GetCommit
|
||||
getStream: typeof getStream
|
||||
getCommitStream: typeof getCommitStream
|
||||
getStreamBranchByName: GetStreamBranchByName
|
||||
getCommitBranch: GetCommitBranch
|
||||
switchCommitBranch: SwitchCommitBranch
|
||||
updateCommit: UpdateCommit
|
||||
addCommitUpdatedActivity: typeof addCommitUpdatedActivity
|
||||
markCommitStreamUpdated: typeof markCommitStreamUpdated
|
||||
markCommitBranchUpdated: MarkCommitBranchUpdated
|
||||
}): UpdateCommitAndNotify =>
|
||||
async (params: CommitUpdateInput | UpdateVersionInput, userId: string) => {
|
||||
const {
|
||||
message,
|
||||
newBranchName,
|
||||
streamId,
|
||||
id: commitId
|
||||
} = isOldVersionUpdateInput(params)
|
||||
? params
|
||||
: {
|
||||
message: params.message,
|
||||
id: params.versionId,
|
||||
streamId: null,
|
||||
newBranchName: null
|
||||
}
|
||||
|
||||
if (!message && !newBranchName) {
|
||||
throw new CommitUpdateError('Nothing to update', {
|
||||
info: { ...params, userId }
|
||||
})
|
||||
}
|
||||
|
||||
const [commit, stream] = await Promise.all([
|
||||
getCommitFactory({ db })(commitId),
|
||||
streamId ? getStream({ streamId, userId }) : getCommitStream({ commitId, userId })
|
||||
])
|
||||
if (!commit) {
|
||||
throw new CommitUpdateError("Can't update nonexistant commit", {
|
||||
info: { ...params, userId }
|
||||
})
|
||||
}
|
||||
if (!stream) {
|
||||
throw new CommitUpdateError("Can't resolve commit stream", {
|
||||
info: { ...params, userId }
|
||||
})
|
||||
}
|
||||
if (commit.author !== userId && stream.role !== Roles.Stream.Owner) {
|
||||
throw new CommitUpdateError(
|
||||
'Only the author of a commit or a stream owner may update it',
|
||||
{
|
||||
info: { ...params, userId, streamRole: stream.role }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (newBranchName) {
|
||||
try {
|
||||
const [newBranch, oldBranch] = await Promise.all([
|
||||
getStreamBranchByNameFactory({ db })(streamId, newBranchName),
|
||||
getCommitBranch(commitId)
|
||||
])
|
||||
|
||||
if (!newBranch || !oldBranch) {
|
||||
throw new Error("Couldn't resolve branch")
|
||||
}
|
||||
if (!commit) {
|
||||
throw new Error("Couldn't find commit")
|
||||
}
|
||||
|
||||
await switchCommitBranch(commitId, newBranch.id, oldBranch.id)
|
||||
} catch (e) {
|
||||
throw new CommitUpdateError('Failed to update commit branch', {
|
||||
cause: ensureError(e),
|
||||
info: params
|
||||
if (!message && !newBranchName) {
|
||||
throw new CommitUpdateError('Nothing to update', {
|
||||
info: { ...params, userId }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let newCommit: CommitRecord = commit
|
||||
if (message) {
|
||||
newCommit = await updateCommit(commitId, { message })
|
||||
}
|
||||
|
||||
if (commit) {
|
||||
await addCommitUpdatedActivity({
|
||||
commitId,
|
||||
streamId: stream.id,
|
||||
userId,
|
||||
originalCommit: commit,
|
||||
update: params,
|
||||
newCommit
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
markCommitStreamUpdated(commit.id),
|
||||
markCommitBranchUpdatedFactory({ db })(commit.id)
|
||||
const [commit, stream] = await Promise.all([
|
||||
deps.getCommit(commitId),
|
||||
streamId
|
||||
? deps.getStream({ streamId, userId })
|
||||
: deps.getCommitStream({ commitId, userId })
|
||||
])
|
||||
}
|
||||
if (!commit) {
|
||||
throw new CommitUpdateError("Can't update nonexistant commit", {
|
||||
info: { ...params, userId }
|
||||
})
|
||||
}
|
||||
if (!stream) {
|
||||
throw new CommitUpdateError("Can't resolve commit stream", {
|
||||
info: { ...params, userId }
|
||||
})
|
||||
}
|
||||
if (commit.author !== userId && stream.role !== Roles.Stream.Owner) {
|
||||
throw new CommitUpdateError(
|
||||
'Only the author of a commit or a stream owner may update it',
|
||||
{
|
||||
info: { ...params, userId, streamRole: stream.role }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return newCommit
|
||||
}
|
||||
if (newBranchName) {
|
||||
try {
|
||||
const [newBranch, oldBranch] = await Promise.all([
|
||||
deps.getStreamBranchByName(streamId, newBranchName),
|
||||
deps.getCommitBranch(commitId)
|
||||
])
|
||||
|
||||
if (!newBranch || !oldBranch) {
|
||||
throw new Error("Couldn't resolve branch")
|
||||
}
|
||||
if (!commit) {
|
||||
throw new Error("Couldn't find commit")
|
||||
}
|
||||
|
||||
await deps.switchCommitBranch(commitId, newBranch.id, oldBranch.id)
|
||||
} catch (e) {
|
||||
throw new CommitUpdateError('Failed to update commit branch', {
|
||||
cause: ensureError(e),
|
||||
info: params
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let newCommit: CommitRecord = commit
|
||||
if (message) {
|
||||
newCommit = await deps.updateCommit(commitId, { message })
|
||||
}
|
||||
|
||||
if (commit) {
|
||||
await deps.addCommitUpdatedActivity({
|
||||
commitId,
|
||||
streamId: stream.id,
|
||||
userId,
|
||||
originalCommit: commit,
|
||||
update: params,
|
||||
newCommit
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
deps.markCommitStreamUpdated(commit.id),
|
||||
deps.markCommitBranchUpdated(commit.id)
|
||||
])
|
||||
}
|
||||
|
||||
return newCommit
|
||||
}
|
||||
|
||||
export const deleteCommitAndNotifyFactory =
|
||||
(deps: {
|
||||
|
||||
@@ -7,12 +7,10 @@ import {
|
||||
getBranchCommitsTotalCount,
|
||||
getPaginatedBranchCommits as getPaginatedBranchCommitsDb,
|
||||
getSpecificBranchCommitsFactory,
|
||||
getStreamCommitCountFactory,
|
||||
PaginatedBranchCommitsParams
|
||||
} from '@/modules/core/repositories/commits'
|
||||
import {
|
||||
getCommitsByStreamId,
|
||||
getCommitsTotalCountByStreamId
|
||||
} from '@/modules/core/services/commits'
|
||||
import { getCommitsByStreamId } from '@/modules/core/services/commits'
|
||||
import { BadRequestError } from '@/modules/shared/errors'
|
||||
import { db } from '@/db/knex'
|
||||
|
||||
@@ -30,8 +28,7 @@ export async function getPaginatedStreamCommits(
|
||||
cursor: params.cursor,
|
||||
ignoreGlobalsBranch: true
|
||||
})
|
||||
const totalCount = await getCommitsTotalCountByStreamId({
|
||||
streamId,
|
||||
const totalCount = await getStreamCommitCountFactory({ db })(streamId, {
|
||||
ignoreGlobalsBranch: true
|
||||
})
|
||||
|
||||
|
||||
@@ -10,7 +10,11 @@ import {
|
||||
GetBranchLatestCommits,
|
||||
GetStreamBranchesByName
|
||||
} from '@/modules/core/domain/branches/operations'
|
||||
import { GetSpecificBranchCommits } from '@/modules/core/domain/commits/operations'
|
||||
import {
|
||||
GetAllBranchCommits,
|
||||
GetCommitsAndTheirBranchIds,
|
||||
GetSpecificBranchCommits
|
||||
} from '@/modules/core/domain/commits/operations'
|
||||
import {
|
||||
ResourceIdentifier,
|
||||
ResourceIdentifierInput,
|
||||
@@ -20,10 +24,6 @@ import {
|
||||
ViewerUpdateTrackingTarget
|
||||
} from '@/modules/core/graph/generated/graphql'
|
||||
import { CommitRecord } from '@/modules/core/helpers/types'
|
||||
import {
|
||||
getAllBranchCommits,
|
||||
getCommitsAndTheirBranchIds
|
||||
} from '@/modules/core/repositories/commits'
|
||||
import { getStreamObjects } from '@/modules/core/repositories/objects'
|
||||
import { Optional, SpeckleViewer } from '@speckle/shared'
|
||||
import { flatten, keyBy, reduce, uniq, uniqWith } from 'lodash'
|
||||
@@ -77,7 +77,7 @@ const getObjectResourceGroupsFactory =
|
||||
|
||||
type GetVersionResourceGroupsIncludingAllVersionsFactoryDeps = {
|
||||
getStreamBranchesByName: GetStreamBranchesByName
|
||||
getAllBranchCommits: typeof getAllBranchCommits
|
||||
getAllBranchCommits: GetAllBranchCommits
|
||||
}
|
||||
|
||||
const getVersionResourceGroupsIncludingAllVersionsFactory =
|
||||
@@ -370,7 +370,7 @@ export const getViewerResourcesFromLegacyIdentifiersFactory =
|
||||
(
|
||||
deps: {
|
||||
getViewerResourcesForComments: GetViewerResourcesForComments
|
||||
getCommitsAndTheirBranchIds: typeof getCommitsAndTheirBranchIds
|
||||
getCommitsAndTheirBranchIds: GetCommitsAndTheirBranchIds
|
||||
} & GetObjectResourceGroupsDeps
|
||||
): GetViewerResourcesFromLegacyIdentifiers =>
|
||||
async (
|
||||
|
||||
@@ -6,11 +6,9 @@ const Commits = () => knex('commits')
|
||||
const StreamCommits = () => knex('stream_commits')
|
||||
|
||||
const {
|
||||
getStreamCommitCount,
|
||||
getPaginatedBranchCommits,
|
||||
getBranchCommitsTotalCount
|
||||
} = require('@/modules/core/repositories/commits')
|
||||
const { updateCommitAndNotify } = require('@/modules/core/services/commit/management')
|
||||
const { clamp } = require('lodash')
|
||||
|
||||
const getCommitsByUserIdBase = ({ userId, publicOnly, streamIdWhitelist }) => {
|
||||
@@ -47,14 +45,6 @@ const getCommitsByUserIdBase = ({ userId, publicOnly, streamIdWhitelist }) => {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* @deprecated Use 'updateCommitAndNotify()'
|
||||
*/
|
||||
async updateCommit({ streamId, id, message, newBranchName, userId }) {
|
||||
await updateCommitAndNotify({ streamId, id, message, newBranchName }, userId)
|
||||
return true
|
||||
},
|
||||
|
||||
/**
|
||||
* @deprecated Use `getBranchCommitsTotalCount()` instead
|
||||
*/
|
||||
@@ -89,10 +79,6 @@ module.exports = {
|
||||
return module.exports.getCommitsByBranchId({ branchId: myBranch.id, limit, cursor })
|
||||
},
|
||||
|
||||
async getCommitsTotalCountByStreamId({ streamId, ignoreGlobalsBranch }) {
|
||||
return await getStreamCommitCount(streamId, { ignoreGlobalsBranch })
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {Promise<{
|
||||
* commits: import('@/modules/core/helpers/types').CommitRecord[],
|
||||
|
||||
@@ -15,12 +15,12 @@ import {
|
||||
insertObjects
|
||||
} from '@/modules/core/repositories/objects'
|
||||
import {
|
||||
getBatchedStreamCommits,
|
||||
generateCommitId,
|
||||
insertCommits,
|
||||
getBatchedBranchCommits,
|
||||
insertStreamCommitsFactory,
|
||||
insertBranchCommitsFactory
|
||||
insertBranchCommitsFactory,
|
||||
getBatchedStreamCommitsFactory,
|
||||
getBatchedBranchCommitsFactory,
|
||||
insertCommitsFactory
|
||||
} from '@/modules/core/repositories/commits'
|
||||
import { chunk } from 'lodash'
|
||||
import {
|
||||
@@ -165,6 +165,8 @@ async function cloneCommits(state: CloneStreamInitialState) {
|
||||
// oldCommitId/newCommitId
|
||||
const commitIdMap = new Map<string, string>()
|
||||
|
||||
const insertCommits = insertCommitsFactory({ db })
|
||||
const getBatchedStreamCommits = getBatchedStreamCommitsFactory({ db })
|
||||
for await (const commitsBatch of getBatchedStreamCommits(state.targetStream.id, {
|
||||
trx: state.trx
|
||||
})) {
|
||||
@@ -237,6 +239,8 @@ async function createBranchCommitReferences(
|
||||
branchIdMap: Map<string, string>
|
||||
) {
|
||||
const oldBranchIds = [...branchIdMap.keys()]
|
||||
const getBatchedBranchCommits = getBatchedBranchCommitsFactory({ db })
|
||||
|
||||
for await (const branchCommits of getBatchedBranchCommits(oldBranchIds, {
|
||||
trx: state.trx
|
||||
})) {
|
||||
|
||||
@@ -8,11 +8,9 @@ const { createStream } = require('../services/streams')
|
||||
const { createObject } = require('../services/objects')
|
||||
|
||||
const {
|
||||
updateCommit,
|
||||
getCommitsTotalCountByBranchName,
|
||||
getCommitsByBranchName,
|
||||
getCommitsByStreamId,
|
||||
getCommitsTotalCountByStreamId,
|
||||
getCommitsByUserId
|
||||
} = require('../services/commits')
|
||||
const {
|
||||
@@ -34,17 +32,27 @@ const {
|
||||
deleteCommitFactory,
|
||||
createCommitFactory,
|
||||
insertStreamCommitsFactory,
|
||||
insertBranchCommitsFactory
|
||||
insertBranchCommitsFactory,
|
||||
getCommitBranchFactory,
|
||||
switchCommitBranchFactory,
|
||||
updateCommitFactory,
|
||||
getStreamCommitCountFactory
|
||||
} = require('@/modules/core/repositories/commits')
|
||||
const {
|
||||
deleteCommitAndNotifyFactory,
|
||||
createCommitByBranchIdFactory,
|
||||
createCommitByBranchNameFactory
|
||||
createCommitByBranchNameFactory,
|
||||
updateCommitAndNotifyFactory
|
||||
} = require('@/modules/core/services/commit/management')
|
||||
const { markCommitStreamUpdated } = require('@/modules/core/repositories/streams')
|
||||
const {
|
||||
markCommitStreamUpdated,
|
||||
getCommitStream,
|
||||
getStream
|
||||
} = require('@/modules/core/repositories/streams')
|
||||
const {
|
||||
addCommitDeletedActivity,
|
||||
addCommitCreatedActivity
|
||||
addCommitCreatedActivity,
|
||||
addCommitUpdatedActivity
|
||||
} = require('@/modules/activitystream/services/commitActivity')
|
||||
const { getObject } = require('@/modules/core/repositories/objects')
|
||||
const { VersionsEmitter } = require('@/modules/core/events/versionsEmitter')
|
||||
@@ -82,6 +90,20 @@ const createCommitByBranchName = createCommitByBranchNameFactory({
|
||||
getBranchById: getBranchByIdFactory({ db })
|
||||
})
|
||||
|
||||
const updateCommitAndNotify = updateCommitAndNotifyFactory({
|
||||
getCommit: getCommitFactory({ db }),
|
||||
getStream,
|
||||
getCommitStream,
|
||||
getStreamBranchByName: getStreamBranchByNameFactory({ db }),
|
||||
getCommitBranch: getCommitBranchFactory({ db }),
|
||||
switchCommitBranch: switchCommitBranchFactory({ db }),
|
||||
updateCommit: updateCommitFactory({ db }),
|
||||
addCommitUpdatedActivity,
|
||||
markCommitStreamUpdated,
|
||||
markCommitBranchUpdated: markCommitBranchUpdatedFactory({ db })
|
||||
})
|
||||
const getStreamCommitCount = getStreamCommitCountFactory({ db })
|
||||
|
||||
describe('Commits @core-commits', () => {
|
||||
const user = {
|
||||
name: 'Dimitrie Stefanescu',
|
||||
@@ -255,13 +277,15 @@ describe('Commits @core-commits', () => {
|
||||
})
|
||||
|
||||
it('Should update a commit', async () => {
|
||||
const res = await updateCommit({
|
||||
id: commitId1,
|
||||
message: 'FIRST COMMIT YOOOOOO',
|
||||
userId: user.id,
|
||||
streamId: stream.id
|
||||
})
|
||||
expect(res).to.equal(true)
|
||||
const res = await updateCommitAndNotify(
|
||||
{
|
||||
id: commitId1,
|
||||
message: 'FIRST COMMIT YOOOOOO',
|
||||
streamId: stream.id
|
||||
},
|
||||
user.id
|
||||
)
|
||||
expect(res).to.be.ok
|
||||
})
|
||||
|
||||
it('Should delete a commit', async () => {
|
||||
@@ -356,7 +380,7 @@ describe('Commits @core-commits', () => {
|
||||
expect(commits.length).to.equal(10)
|
||||
expect(commits2.length).to.equal(5)
|
||||
|
||||
const c = await getCommitsTotalCountByStreamId({ streamId })
|
||||
const c = await getStreamCommitCount(streamId)
|
||||
expect(c).to.equal(15)
|
||||
})
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import {
|
||||
} from '@/modules/core/repositories/branches'
|
||||
import {
|
||||
createCommitFactory,
|
||||
getAllBranchCommits,
|
||||
getAllBranchCommitsFactory,
|
||||
getSpecificBranchCommitsFactory,
|
||||
insertBranchCommitsFactory,
|
||||
insertStreamCommitsFactory
|
||||
@@ -76,7 +76,7 @@ const crossServerSyncModule: SpeckleModule = {
|
||||
getBranchLatestCommits: getBranchLatestCommitsFactory({ db }),
|
||||
getStreamBranchesByName: getStreamBranchesByNameFactory({ db }),
|
||||
getSpecificBranchCommits: getSpecificBranchCommitsFactory({ db }),
|
||||
getAllBranchCommits
|
||||
getAllBranchCommits: getAllBranchCommitsFactory({ db })
|
||||
})
|
||||
})
|
||||
const createCommentThreadAndNotify = createCommentThreadAndNotifyFactory({
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex flex-col gap-y-1 sm:gap-y-2 border border-outline-3 rounded-lg py-2 px-3 sm:p-4 select-none"
|
||||
>
|
||||
<h6
|
||||
v-if="title"
|
||||
class="text-body-xs sm:text-heading-sm font-medium text-foreground"
|
||||
>
|
||||
{{ title }}
|
||||
</h6>
|
||||
<p v-if="text" class="text-body-2xs sm:text-body-xs text-foreground-2 !leading-5">
|
||||
{{ text }}
|
||||
</p>
|
||||
<FormButton
|
||||
v-if="buttonText"
|
||||
size="sm"
|
||||
class="mt-1"
|
||||
:to="to"
|
||||
:target="to ? '_blank' : undefined"
|
||||
@click="$emit('onClick')"
|
||||
>
|
||||
{{ buttonText }}
|
||||
</FormButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import FormButton from '~~/src/components/form/Button.vue'
|
||||
|
||||
defineEmits(['onClick'])
|
||||
|
||||
defineProps<{
|
||||
title?: string
|
||||
text?: string
|
||||
to?: string
|
||||
buttonText?: string
|
||||
}>()
|
||||
</script>
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Meta, StoryObj } from '@storybook/vue3'
|
||||
import LayoutSidebar from '~~/src/components/layout/sidebar/Sidebar.vue'
|
||||
import LayoutSidebarPromo from '~~/src/components/layout/sidebar/Promo.vue'
|
||||
import LayoutSidebarMenu from '~~/src/components/layout/sidebar/menu/Menu.vue'
|
||||
import LayoutSidebarMenuGroup from '~~/src/components/layout/sidebar/menu/group/Group.vue'
|
||||
import LayoutSidebarMenuGroupItem from '~~/src/components/layout/sidebar/menu/group/Item.vue'
|
||||
@@ -20,6 +21,7 @@ export const Dashboard: StoryObj = {
|
||||
render: (args) => ({
|
||||
components: {
|
||||
LayoutSidebar,
|
||||
LayoutSidebarPromo,
|
||||
LayoutSidebarMenu,
|
||||
LayoutSidebarMenuGroup,
|
||||
LayoutSidebarMenuGroupItem,
|
||||
@@ -68,6 +70,9 @@ export const Dashboard: StoryObj = {
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</LayoutSidebarMenuGroup>
|
||||
</LayoutSidebarMenu>
|
||||
<template #promo>
|
||||
<LayoutSidebarPromo title="Example Title" text="An example piece of text" />
|
||||
</template>
|
||||
</LayoutSidebar>
|
||||
`
|
||||
})
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
<template>
|
||||
<!-- If promo content is defined, scroll the menu items. If not, scroll the whole aside -->
|
||||
<aside
|
||||
class="flex flex-col justify-between h-full w-full overflow-y-auto overflow-x-hidden simple-scrollbar"
|
||||
class="flex flex-col justify-between h-full w-full"
|
||||
:class="$slots.promo ? '' : 'overflow-y-auto overflow-x-hidden simple-scrollbar'"
|
||||
>
|
||||
<slot></slot>
|
||||
<div
|
||||
class="flex flex-col h-full w-full"
|
||||
:class="$slots.promo ? 'overflow-y-auto overflow-x-hidden simple-scrollbar' : ''"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div v-if="$slots.promo" class="shrink-0 pt-2">
|
||||
<slot name="promo"></slot>
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
@@ -65,6 +65,7 @@ import InfiniteLoading from '~~/src/components/InfiniteLoading.vue'
|
||||
import type { InfiniteLoaderState } from '~~/src/helpers/global/components'
|
||||
import LayoutPanel from '~~/src/components/layout/Panel.vue'
|
||||
import LayoutSidebar from '~~/src/components/layout/sidebar/Sidebar.vue'
|
||||
import LayoutSidebarPromo from '~~/src/components/layout/sidebar/Promo.vue'
|
||||
import LayoutSidebarMenu from '~~/src/components/layout/sidebar/menu/Menu.vue'
|
||||
import LayoutSidebarMenuGroup from '~~/src/components/layout/sidebar/menu/group/Group.vue'
|
||||
import LayoutSidebarMenuGroupItem from '~~/src/components/layout/sidebar/menu/group/Item.vue'
|
||||
@@ -153,6 +154,7 @@ export {
|
||||
LayoutTabsVertical,
|
||||
LayoutTable,
|
||||
LayoutSidebar,
|
||||
LayoutSidebarPromo,
|
||||
LayoutSidebarMenu,
|
||||
LayoutSidebarMenuGroup,
|
||||
LayoutSidebarMenuGroupItem,
|
||||
|
||||
@@ -208,7 +208,7 @@ export class LegacyViewer extends Viewer {
|
||||
ghost = false
|
||||
): Promise<FilteringState> {
|
||||
return new Promise<FilteringState>((resolve) => {
|
||||
const filteringState = this.preserveSelectionFilter(() => {
|
||||
const filteringState = this.preserveSelectionHighlightFilter(() => {
|
||||
return this.filtering.hideObjects(
|
||||
objectIds,
|
||||
stateKey,
|
||||
@@ -226,7 +226,7 @@ export class LegacyViewer extends Viewer {
|
||||
includeDescendants = false
|
||||
): Promise<FilteringState> {
|
||||
return new Promise<FilteringState>((resolve) => {
|
||||
const filteringState = this.preserveSelectionFilter(() => {
|
||||
const filteringState = this.preserveSelectionHighlightFilter(() => {
|
||||
return this.filtering.showObjects(objectIds, stateKey, includeDescendants)
|
||||
})
|
||||
resolve(filteringState)
|
||||
@@ -240,7 +240,7 @@ export class LegacyViewer extends Viewer {
|
||||
ghost = true
|
||||
): Promise<FilteringState> {
|
||||
return new Promise<FilteringState>((resolve) => {
|
||||
const filteringState = this.preserveSelectionFilter(() => {
|
||||
const filteringState = this.preserveSelectionHighlightFilter(() => {
|
||||
return this.filtering.isolateObjects(
|
||||
objectIds,
|
||||
stateKey,
|
||||
@@ -258,7 +258,7 @@ export class LegacyViewer extends Viewer {
|
||||
includeDescendants = false
|
||||
): Promise<FilteringState> {
|
||||
return new Promise<FilteringState>((resolve) => {
|
||||
const filteringState = this.preserveSelectionFilter(() => {
|
||||
const filteringState = this.preserveSelectionHighlightFilter(() => {
|
||||
return this.filtering.unIsolateObjects(objectIds, stateKey, includeDescendants)
|
||||
})
|
||||
resolve(filteringState)
|
||||
@@ -278,7 +278,7 @@ export class LegacyViewer extends Viewer {
|
||||
|
||||
public setColorFilter(property: PropertyInfo, ghost = true): Promise<FilteringState> {
|
||||
return new Promise<FilteringState>((resolve) => {
|
||||
const filteringState = this.preserveSelectionFilter(() => {
|
||||
const filteringState = this.preserveSelectionHighlightFilter(() => {
|
||||
return this.filtering.setColorFilter(property, ghost)
|
||||
})
|
||||
resolve(filteringState)
|
||||
@@ -287,7 +287,7 @@ export class LegacyViewer extends Viewer {
|
||||
|
||||
public removeColorFilter(): Promise<FilteringState> {
|
||||
return new Promise<FilteringState>((resolve) => {
|
||||
const filteringState = this.preserveSelectionFilter(() => {
|
||||
const filteringState = this.preserveSelectionHighlightFilter(() => {
|
||||
return this.filtering.removeColorFilter()
|
||||
})
|
||||
resolve(filteringState)
|
||||
@@ -298,7 +298,7 @@ export class LegacyViewer extends Viewer {
|
||||
groups: { objectIds: string[]; color: string }[]
|
||||
): Promise<FilteringState> {
|
||||
return new Promise<FilteringState>((resolve) => {
|
||||
const filteringState = this.preserveSelectionFilter(() => {
|
||||
const filteringState = this.preserveSelectionHighlightFilter(() => {
|
||||
return this.filtering.setUserObjectColors(groups)
|
||||
})
|
||||
resolve(filteringState)
|
||||
@@ -307,20 +307,25 @@ export class LegacyViewer extends Viewer {
|
||||
|
||||
public resetFilters(): Promise<FilteringState | null> {
|
||||
return new Promise<FilteringState>((resolve) => {
|
||||
const filteringState = this.preserveSelectionFilter(() => {
|
||||
const filteringState = this.preserveSelectionHighlightFilter(() => {
|
||||
return this.filtering.resetFilters()
|
||||
})
|
||||
resolve(filteringState)
|
||||
})
|
||||
}
|
||||
|
||||
private preserveSelectionFilter(
|
||||
private preserveSelectionHighlightFilter(
|
||||
filterFn: () => FilteringState | null
|
||||
): FilteringState {
|
||||
const selectedObjects = this.selection
|
||||
.getSelectedObjects()
|
||||
.map((obj) => obj.id) as string[]
|
||||
const highLightedObjects = this.highlightExtension
|
||||
.getSelectedObjects()
|
||||
.map((obj) => obj.id) as string[]
|
||||
if (selectedObjects.length) this.selection.clearSelection()
|
||||
if (highLightedObjects.length)
|
||||
this.highlightExtension.unselectObjects(highLightedObjects)
|
||||
const filteringState = filterFn()
|
||||
if (filteringState) {
|
||||
if (!filteringState.selectedObjects)
|
||||
@@ -328,6 +333,8 @@ export class LegacyViewer extends Viewer {
|
||||
|
||||
this.selection.selectObjects(filteringState.selectedObjects)
|
||||
}
|
||||
if (highLightedObjects.length)
|
||||
this.highlightExtension.selectObjects(highLightedObjects)
|
||||
return filteringState || this.filtering.filteringState
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user