diff --git a/.circleci/config.yml b/.circleci/config.yml index 9a7eda562c..47030bceeb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -496,6 +496,7 @@ jobs: S3_REGION: '' # optional, defaults to 'us-east-1' ENCRYPTION_KEYS_PATH: 'test/assets/automate/encryptionKeys.json' FF_BILLING_INTEGRATION_ENABLED: 'true' + RATELIMITER_ENABLED: 'false' steps: - checkout - restore_cache: @@ -578,6 +579,7 @@ jobs: S3_REGION: '' # optional, defaults to 'us-east-1' ENCRYPTION_KEYS_PATH: 'test/assets/automate/encryptionKeys.json' DISABLE_ALL_FFS: 'true' + RATELIMITER_ENABLED: 'false' test-server-multiregion: <<: *test-server-job @@ -623,8 +625,8 @@ jobs: MULTI_REGION_CONFIG_PATH: '../../.circleci/multiregion.test-ci.json' FF_WORKSPACES_MODULE_ENABLED: 'true' FF_WORKSPACES_MULTI_REGION_ENABLED: 'true' - FF_WORKSPACES_MULTI_REGION_BLOB_STORAGE_ENABLED: 'true' RUN_TESTS_IN_MULTIREGION_MODE: true + RATELIMITER_ENABLED: 'false' test-frontend-2: docker: &docker-node-browsers-image @@ -1049,7 +1051,6 @@ jobs: docker-build-monitor-container: <<: *build-job environment: - FOLDER: utils SPECKLE_SERVER_PACKAGE: monitor-deployment docker-build-docker-compose-ingress: @@ -1119,7 +1120,6 @@ jobs: docker-publish-monitor-container: <<: *publish-job environment: - FOLDER: utils SPECKLE_SERVER_PACKAGE: monitor-deployment docker-publish-docker-compose-ingress: diff --git a/.gitignore b/.gitignore index 8c373e06f6..449785fc3b 100644 --- a/.gitignore +++ b/.gitignore @@ -74,7 +74,9 @@ redis-data/ .tshy-build obj/ bin/ - +!packages/monitor-deployment/bin +!packages/preview-service/bin +!packages/server/bin # Server multiregion.json diff --git a/packages/dui3/lib/common/generated/gql/graphql.ts b/packages/dui3/lib/common/generated/gql/graphql.ts index 5e243b3b95..c05b3c77b4 100644 --- a/packages/dui3/lib/common/generated/gql/graphql.ts +++ b/packages/dui3/lib/common/generated/gql/graphql.ts @@ -68,6 +68,16 @@ export type AdminInviteList = { totalCount: Scalars['Int']['output']; }; +export type AdminMutations = { + __typename?: 'AdminMutations'; + updateWorkspacePlan: Scalars['Boolean']['output']; +}; + + +export type AdminMutationsUpdateWorkspacePlanArgs = { + input: AdminUpdateWorkspacePlanInput; +}; + export type AdminQueries = { __typename?: 'AdminQueries'; inviteList: AdminInviteList; @@ -108,6 +118,12 @@ export type AdminQueriesWorkspaceListArgs = { query?: InputMaybe; }; +export type AdminUpdateWorkspacePlanInput = { + plan: WorkspacePlans; + status: WorkspacePlanStatuses; + workspaceId: Scalars['ID']['input']; +}; + export type AdminUserList = { __typename?: 'AdminUserList'; cursor?: Maybe; @@ -1240,6 +1256,7 @@ export type Mutation = { _?: Maybe; /** Various Active User oriented mutations */ activeUserMutations: ActiveUserMutations; + admin: AdminMutations; adminDeleteUser: Scalars['Boolean']['output']; /** Creates an personal api token. */ apiTokenCreate: Scalars['String']['output']; @@ -4535,9 +4552,16 @@ export type WorkspaceSubscription = { billingInterval: BillingInterval; createdAt: Scalars['DateTime']['output']; currentBillingCycleEnd: Scalars['DateTime']['output']; + seats: WorkspaceSubscriptionSeats; updatedAt: Scalars['DateTime']['output']; }; +export type WorkspaceSubscriptionSeats = { + __typename?: 'WorkspaceSubscriptionSeats'; + guest: Scalars['Int']['output']; + plan: Scalars['Int']['output']; +}; + export type WorkspaceTeamFilter = { /** Limit team members to provided role(s) */ roles?: InputMaybe>; diff --git a/packages/fileimport-service/Dockerfile b/packages/fileimport-service/Dockerfile index 088f024c2e..2a893ef635 100644 --- a/packages/fileimport-service/Dockerfile +++ b/packages/fileimport-service/Dockerfile @@ -20,7 +20,7 @@ RUN chmod +x /usr/bin/tini RUN apt-get update -y \ && DEBIAN_FRONTEND=noninteractive apt-get install -y \ --no-install-recommends \ - curl=8.5.0-2ubuntu10.5 \ + curl=8.5.0-2ubuntu10.6 \ && curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \ && DEBIAN_FRONTEND=noninteractive apt-get install -y \ --no-install-recommends \ diff --git a/packages/fileimport-service/ifc-dotnet/ifc-converter.csproj b/packages/fileimport-service/ifc-dotnet/ifc-converter.csproj index 9c8c46297e..3183ad96ca 100644 --- a/packages/fileimport-service/ifc-dotnet/ifc-converter.csproj +++ b/packages/fileimport-service/ifc-dotnet/ifc-converter.csproj @@ -10,7 +10,7 @@ - + diff --git a/packages/fileimport-service/knex.js b/packages/fileimport-service/knex.js index aa1729c9a1..ff8285fefb 100644 --- a/packages/fileimport-service/knex.js +++ b/packages/fileimport-service/knex.js @@ -14,8 +14,15 @@ const isDevEnv = process.env.NODE_ENV !== 'production' let dbClients const getDbClients = async () => { if (dbClients) return dbClients - const maxConnections = - parseInt(process.env.POSTGRES_MAX_CONNECTIONS_FILE_IMPORT_SERVICE) || 1 + const maxConnections = parseInt( + process.env['POSTGRES_MAX_CONNECTIONS_FILE_IMPORT_SERVICE'] || '1' + ) + const connectionAcquireTimeoutMillis = parseInt( + process.env['POSTGRES_CONNECTION_ACQUIRE_TIMEOUT_MILLIS'] || '16000' + ) + const connectionCreateTimeoutMillis = parseInt( + process.env['POSTGRES_CONNECTION_CREATE_TIMEOUT_MILLIS'] || '5000' + ) const configArgs = { migrationDirs: [], @@ -23,7 +30,9 @@ const getDbClients = async () => { isDevOrTestEnv: isDevEnv, logger, maxConnections, - applicationName: 'speckle_fileimport_service' + applicationName: 'speckle_fileimport_service', + connectionAcquireTimeoutMillis, + connectionCreateTimeoutMillis } if (!FF_WORKSPACES_MULTI_REGION_ENABLED) { const mainClient = configureKnexClient( diff --git a/packages/fileimport-service/package.json b/packages/fileimport-service/package.json index 88cd403bf6..7e2dea43ce 100644 --- a/packages/fileimport-service/package.json +++ b/packages/fileimport-service/package.json @@ -26,7 +26,7 @@ "@speckle/shared": "workspace:^", "bcrypt": "^5.0.1", "crypto-random-string": "^3.3.1", - "knex": "^2.4.1", + "knex": "^2.5.1", "pg": "^8.7.3", "pino": "^8.7.0", "pino-http": "^8.0.0", diff --git a/packages/frontend-2/components/automate/runs/StatusBadge.vue b/packages/frontend-2/components/automate/runs/StatusBadge.vue index 3e4b2084d0..c14e12ef40 100644 --- a/packages/frontend-2/components/automate/runs/StatusBadge.vue +++ b/packages/frontend-2/components/automate/runs/StatusBadge.vue @@ -1,5 +1,9 @@ diff --git a/packages/frontend-2/components/billing/Alert.vue b/packages/frontend-2/components/billing/Alert.vue index 63a54edf77..d8acae64ff 100644 --- a/packages/frontend-2/components/billing/Alert.vue +++ b/packages/frontend-2/components/billing/Alert.vue @@ -1,13 +1,29 @@ @@ -39,6 +55,7 @@ graphql(` const props = defineProps<{ workspace: BillingAlert_WorkspaceFragment actions?: Array + condensed?: boolean }>() const { billingPortalRedirect } = useBillingActions() @@ -62,9 +79,17 @@ const trialDaysLeft = computed(() => { }) const title = computed(() => { if (isTrial.value) { - return `You have ${trialDaysLeft.value} day${ - trialDaysLeft.value !== 1 ? 's' : '' - } left on your free trial` + if (trialDaysLeft.value === 0) { + return 'Final day of free trial' + } + if (props.condensed) { + return `${trialDaysLeft.value} day${ + trialDaysLeft.value !== 1 ? 's' : '' + } left in trial` + } else + return `You have ${trialDaysLeft.value} day${ + trialDaysLeft.value !== 1 ? 's' : '' + } left on your free trial` } switch (planStatus.value) { case WorkspacePlanStatuses.CancelationScheduled: @@ -98,6 +123,8 @@ const description = computed(() => { return '' } }) +const hasValidPlan = computed(() => planStatus.value === WorkspacePlanStatuses.Valid) + const alertColor = computed(() => { switch (planStatus.value) { case WorkspacePlanStatuses.PaymentFailed: @@ -110,6 +137,7 @@ const alertColor = computed(() => { return 'neutral' } }) + const actions = computed((): AlertAction[] => { const actions: Array = props.actions ?? [] @@ -129,5 +157,4 @@ const actions = computed((): AlertAction[] => { return actions }) -const hasValidPlan = computed(() => planStatus.value === WorkspacePlanStatuses.Valid) diff --git a/packages/frontend-2/components/dashboard/Sidebar.vue b/packages/frontend-2/components/dashboard/Sidebar.vue index b4a52aca76..461914dad9 100644 --- a/packages/frontend-2/components/dashboard/Sidebar.vue +++ b/packages/frontend-2/components/dashboard/Sidebar.vue @@ -58,8 +58,8 @@ v-if="isWorkspacesEnabled" collapsible title="Workspaces" - :plus-click="isNotGuest ? handlePlusClick : undefined" - plus-text="Create workspace" + :icon-click="isNotGuest ? handlePlusClick : undefined" + icon-text="Create workspace" > +
@@ -17,19 +17,10 @@ >
-
+

{{ webflowItem.title }}

-

- - {{ createdOn.relative }} - - -

@@ -37,13 +28,18 @@ diff --git a/packages/frontend-2/components/dashboard/Blog/Wrapper.vue b/packages/frontend-2/components/dashboard/tutorials/Wrapper.vue similarity index 88% rename from packages/frontend-2/components/dashboard/Blog/Wrapper.vue rename to packages/frontend-2/components/dashboard/tutorials/Wrapper.vue index c92f35eacc..df5700ad8e 100644 --- a/packages/frontend-2/components/dashboard/Blog/Wrapper.vue +++ b/packages/frontend-2/components/dashboard/tutorials/Wrapper.vue @@ -1,8 +1,8 @@ diff --git a/packages/frontend-2/components/project/page/settings/general/block/Delete/Delete.vue b/packages/frontend-2/components/project/page/settings/general/block/Delete/Delete.vue index a71df99ef8..09c37656e0 100644 --- a/packages/frontend-2/components/project/page/settings/general/block/Delete/Delete.vue +++ b/packages/frontend-2/components/project/page/settings/general/block/Delete/Delete.vue @@ -13,9 +13,10 @@ - @@ -23,30 +24,16 @@ diff --git a/packages/frontend-2/components/projects/AddDialog.vue b/packages/frontend-2/components/projects/AddDialog.vue index ba15583418..c3f5405315 100644 --- a/packages/frontend-2/components/projects/AddDialog.vue +++ b/packages/frontend-2/components/projects/AddDialog.vue @@ -1,11 +1,5 @@ - - diff --git a/packages/frontend-2/components/projects/NewSpeckle/Dialog.vue b/packages/frontend-2/components/projects/NewSpeckle/Dialog.vue deleted file mode 100644 index cee0c2fa12..0000000000 --- a/packages/frontend-2/components/projects/NewSpeckle/Dialog.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - diff --git a/packages/frontend-2/components/projects/ProjectDashboardCard.vue b/packages/frontend-2/components/projects/ProjectDashboardCard.vue index c946acbdec..d6f9e89d3a 100644 --- a/packages/frontend-2/components/projects/ProjectDashboardCard.vue +++ b/packages/frontend-2/components/projects/ProjectDashboardCard.vue @@ -52,9 +52,7 @@ -
+
@@ -100,6 +99,7 @@ import { workspaceRoute } from '~/lib/common/helpers/route' const props = defineProps<{ project: ProjectDashboardItemFragment showWorkspaceLink?: boolean + workspacePage?: boolean }>() const router = useRouter() @@ -130,4 +130,29 @@ const hasNoModels = computed(() => !models.value.length && !pendingModels.value. const modelItemTotalCount = computed( () => props.project.models.totalCount + pendingModels.value.length ) + +const gridClasses = computed(() => [ + // Base classes + 'grid', + 'gap-2', + 'flex-grow', + 'col-span-4', + 'xl:col-span-3', + 'w-full', + + // Grid columns + 'grid-cols-1', + 'sm:grid-cols-2', + props.workspacePage && 'lg:grid-cols-1', + props.workspacePage ? 'xl:grid-cols-2' : 'xl:grid-cols-3', + props.workspacePage && '2xl:grid-cols-3', + + // Visibility rules + 'sm:[&>*:nth-child(n+3)]:hidden', + props.workspacePage && 'lg:[&>*:nth-child(n+2)]:hidden', + props.workspacePage && 'xl:[&>*:nth-child(n+2)]:block', + !props.workspacePage && 'xl:[&>*:nth-child(n+3)]:block', + props.workspacePage && '2xl:[&>*:nth-child(n+2)]:block', + '2xl:[&>*:nth-child(n+3)]:block' +]) diff --git a/packages/frontend-2/components/projects/WorkspaceSelect.vue b/packages/frontend-2/components/projects/WorkspaceSelect.vue index 185cb11e51..465359dcf9 100644 --- a/packages/frontend-2/components/projects/WorkspaceSelect.vue +++ b/packages/frontend-2/components/projects/WorkspaceSelect.vue @@ -13,7 +13,6 @@ clearable :disabled-item-predicate="disabledItemPredicate" :help="help" - :disabled-item-tooltip="disabledItemTooltip" > + + @@ -98,7 +103,7 @@ :user="userToModify" /> - +
diff --git a/packages/frontend-2/components/settings/server/General.vue b/packages/frontend-2/components/settings/server/General.vue index 788f7d4418..df5694a2f4 100644 --- a/packages/frontend-2/components/settings/server/General.vue +++ b/packages/frontend-2/components/settings/server/General.vue @@ -18,7 +18,7 @@ type="text" />
- - + diff --git a/packages/frontend-2/components/settings/server/user/InviteDialog.vue b/packages/frontend-2/components/settings/server/user/InviteDialog.vue deleted file mode 100644 index b8e38bf716..0000000000 --- a/packages/frontend-2/components/settings/server/user/InviteDialog.vue +++ /dev/null @@ -1,136 +0,0 @@ - - diff --git a/packages/frontend-2/components/settings/shared/ChangeRoleDialog.vue b/packages/frontend-2/components/settings/shared/ChangeRoleDialog.vue deleted file mode 100644 index 69c1ded00d..0000000000 --- a/packages/frontend-2/components/settings/shared/ChangeRoleDialog.vue +++ /dev/null @@ -1,106 +0,0 @@ - - - diff --git a/packages/frontend-2/components/settings/shared/DeleteUserDialog.vue b/packages/frontend-2/components/settings/shared/DeleteUserDialog.vue index 8ef50054c0..e8d0bc57f7 100644 --- a/packages/frontend-2/components/settings/shared/DeleteUserDialog.vue +++ b/packages/frontend-2/components/settings/shared/DeleteUserDialog.vue @@ -1,32 +1,94 @@ diff --git a/packages/frontend-2/components/settings/shared/projects/index.vue b/packages/frontend-2/components/settings/shared/projects/index.vue index 17d1dd2377..23ad2bc66e 100644 --- a/packages/frontend-2/components/settings/shared/projects/index.vue +++ b/packages/frontend-2/components/settings/shared/projects/index.vue @@ -12,7 +12,9 @@ v-on="on" /> - Create + + Create + - @@ -99,10 +102,11 @@ diff --git a/packages/frontend-2/components/settings/workspaces/members/GuestsTable.vue b/packages/frontend-2/components/settings/workspaces/members/GuestsTable.vue index 6e96c9cd1c..569f3ed1d2 100644 --- a/packages/frontend-2/components/settings/workspaces/members/GuestsTable.vue +++ b/packages/frontend-2/components/settings/workspaces/members/GuestsTable.vue @@ -75,6 +75,7 @@ v-model:open="showDeleteUserRoleDialog" title="Remove guest" :name="userToModify?.user.name ?? ''" + :workspace="workspace" @remove-user="onRemoveUser" /> @@ -85,12 +86,13 @@ :workspace-id="workspaceId" /> - @@ -135,6 +137,8 @@ graphql(` fragment SettingsWorkspacesMembersGuestsTable_Workspace on Workspace { id ...SettingsWorkspacesMembersTableHeader_Workspace + ...SettingsSharedDeleteUserDialog_Workspace + ...SettingsWorkspacesMembersChangeRoleDialog_Workspace team { items { id @@ -200,7 +204,7 @@ const actionItems = computed(() => { ] if (isWorkspaceAdmin.value) { - items.unshift([{ title: 'Update role...', id: ActionTypes.ChangeRole }]) + items.unshift([{ title: 'Change role...', id: ActionTypes.ChangeRole }]) } if (guests.value.find((guest) => guest.projectRoles.length)) { diff --git a/packages/frontend-2/components/settings/workspaces/members/MembersTable.vue b/packages/frontend-2/components/settings/workspaces/members/MembersTable.vue index 1ea9f0a870..49090b3332 100644 --- a/packages/frontend-2/components/settings/workspaces/members/MembersTable.vue +++ b/packages/frontend-2/components/settings/workspaces/members/MembersTable.vue @@ -80,18 +80,17 @@
- { // Allow role change if the active user is an admin if (isWorkspaceAdmin.value && !isActiveUserCurrentUser.value(user)) { - baseItems.push([{ title: 'Update role...', id: ActionTypes.ChangeRole }]) + baseItems.push([{ title: 'Change role...', id: ActionTypes.ChangeRole }]) } // Allow the current user to leave the workspace diff --git a/packages/frontend-2/components/settings/workspaces/members/TableHeader.vue b/packages/frontend-2/components/settings/workspaces/members/TableHeader.vue index 5227914e33..6e69cac733 100644 --- a/packages/frontend-2/components/settings/workspaces/members/TableHeader.vue +++ b/packages/frontend-2/components/settings/workspaces/members/TableHeader.vue @@ -1,37 +1,39 @@