diff --git a/packages/frontend-2/.env.example b/packages/frontend-2/.env.example index 17cfbc1071..b2ff12ddfb 100644 --- a/packages/frontend-2/.env.example +++ b/packages/frontend-2/.env.example @@ -41,6 +41,4 @@ NUXT_PUBLIC_SURVICATE_WORKSPACE_KEY= NUXT_PUBLIC_ENABLE_DIRECT_PREVIEWS=true # Ghost API -NUXT_PUBLIC_GHOST_API_KEY= - -NUXT_WEBFLOW_API_TOKEN=8c9bea4c120742a21ff308cda0bea73f13e89ffe26dcc886990bba353549b652 \ No newline at end of file +NUXT_PUBLIC_GHOST_API_KEY= \ No newline at end of file diff --git a/packages/frontend-2/components/dashboard/tutorials/Card.vue b/packages/frontend-2/components/dashboard/tutorials/Card.vue index 6c90d1b3c7..48638ebc5b 100644 --- a/packages/frontend-2/components/dashboard/tutorials/Card.vue +++ b/packages/frontend-2/components/dashboard/tutorials/Card.vue @@ -1,12 +1,12 @@ diff --git a/packages/frontend-2/components/dashboard/tutorials/Wrapper.vue b/packages/frontend-2/components/dashboard/tutorials/Wrapper.vue index df5700ad8e..5327ede2de 100644 --- a/packages/frontend-2/components/dashboard/tutorials/Wrapper.vue +++ b/packages/frontend-2/components/dashboard/tutorials/Wrapper.vue @@ -3,9 +3,9 @@

Tutorials

@@ -13,19 +13,19 @@ diff --git a/packages/frontend-2/lib/common/generated/gql/graphql.ts b/packages/frontend-2/lib/common/generated/gql/graphql.ts index 23b255cd1e..a12306758e 100644 --- a/packages/frontend-2/lib/common/generated/gql/graphql.ts +++ b/packages/frontend-2/lib/common/generated/gql/graphql.ts @@ -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,10 +4382,13 @@ 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']; projects: WorkspaceProjectMutations; + requestToJoin: Scalars['Boolean']['output']; /** Set the default region where project data will be stored. Only available to admins. */ setDefaultRegion: Workspace; update: Workspace; @@ -4415,6 +4422,11 @@ export type WorkspaceMutationsDeleteSsoProviderArgs = { }; +export type WorkspaceMutationsDismissArgs = { + input: WorkspaceDismissInput; +}; + + export type WorkspaceMutationsJoinArgs = { input: JoinWorkspaceInput; }; @@ -4425,6 +4437,11 @@ export type WorkspaceMutationsLeaveArgs = { }; +export type WorkspaceMutationsRequestToJoinArgs = { + input: WorkspaceRequestToJoinInput; +}; + + export type WorkspaceMutationsSetDefaultRegionArgs = { regionKey: Scalars['String']['input']; workspaceId: Scalars['String']['input']; @@ -4534,6 +4551,10 @@ export enum WorkspaceProjectsUpdatedMessageType { Removed = 'REMOVED' } +export type WorkspaceRequestToJoinInput = { + workspaceId: Scalars['ID']['input']; +}; + export enum WorkspaceRole { Admin = 'ADMIN', Guest = 'GUEST', @@ -8117,10 +8138,12 @@ export type WorkspaceMutationsFieldArgs = { delete: WorkspaceMutationsDeleteArgs, deleteDomain: WorkspaceMutationsDeleteDomainArgs, deleteSsoProvider: WorkspaceMutationsDeleteSsoProviderArgs, + dismiss: WorkspaceMutationsDismissArgs, invites: {}, join: WorkspaceMutationsJoinArgs, leave: WorkspaceMutationsLeaveArgs, projects: {}, + requestToJoin: WorkspaceMutationsRequestToJoinArgs, setDefaultRegion: WorkspaceMutationsSetDefaultRegionArgs, update: WorkspaceMutationsUpdateArgs, updateCreationState: WorkspaceMutationsUpdateCreationStateArgs, diff --git a/packages/frontend-2/lib/dashboard/helpers/types.ts b/packages/frontend-2/lib/dashboard/helpers/types.ts index b1a943952b..1329fd2e74 100644 --- a/packages/frontend-2/lib/dashboard/helpers/types.ts +++ b/packages/frontend-2/lib/dashboard/helpers/types.ts @@ -1,11 +1,10 @@ import { type LayoutDialogButton } from '@speckle/ui-components' -export type WebflowItem = { - id: string +export interface TutorialItem { title: string - createdOn: string - lastPublished: string - featureImageUrl?: string + publishedAt: string + image?: string + id: string url: string } diff --git a/packages/frontend-2/nuxt.config.ts b/packages/frontend-2/nuxt.config.ts index 6044d9140a..bbf5158d9e 100644 --- a/packages/frontend-2/nuxt.config.ts +++ b/packages/frontend-2/nuxt.config.ts @@ -48,7 +48,6 @@ export default defineNuxtConfig({ ], runtimeConfig: { redisUrl: '', - webflowApiToken: '', public: { ...featureFlags, apiOrigin: 'UNDEFINED', diff --git a/packages/frontend-2/package.json b/packages/frontend-2/package.json index c5cf579184..e360c37c44 100644 --- a/packages/frontend-2/package.json +++ b/packages/frontend-2/package.json @@ -99,6 +99,8 @@ "@nuxt/image": "^1.8.1", "@nuxtjs/tailwindcss": "^6.12.2", "@parcel/watcher": "^2.4.1", + "@sanity/image-url": "^1.1.0", + "@sanity/types": "^3.70.0", "@speckle/tailwind-theme": "workspace:^", "@tailwindcss/forms": "^0.5.3", "@tailwindcss/line-clamp": "^0.4.2", diff --git a/packages/frontend-2/server/api/tutorials.ts b/packages/frontend-2/server/api/tutorials.ts new file mode 100644 index 0000000000..0c7232b369 --- /dev/null +++ b/packages/frontend-2/server/api/tutorials.ts @@ -0,0 +1,59 @@ +import { ensureError } from '@speckle/shared' +import imageUrlBuilder from '@sanity/image-url' +import dayjs from 'dayjs' +import type { SanityDocument, Reference } from '@sanity/types' +import type { TutorialItem } from '~/lib/dashboard/helpers/types' + +export interface SanityTutorial extends SanityDocument { + title: string + publishedAt: string + mainImage?: { + asset: Reference + } + url: string + webflowUrl: string +} + +export default defineEventHandler(async (): Promise => { + const imageBuilder = imageUrlBuilder({ + projectId: '6kukgozu', + dataset: 'production' + }) + + const currentDate = dayjs().format('YYYY-MM-DD') + const query = encodeURIComponent( + '*[_type == "tutorial"] | order(publishedAt desc)[0...8]' + ) + const url = `https://6kukgozu.api.sanity.io/v${currentDate}/data/query/production?query=${query}` + + try { + const response = await fetch(url) + const data = (await response.json()) as { result: SanityTutorial[] } + + if (!response.ok) { + const errMsg = `Sanity API Error: ${response.status} ${response.statusText}` + throw createError({ + statusCode: response.status, + fatal: true, + message: errMsg + }) + } + + return data.result.map((item) => ({ + title: item.title, + publishedAt: item.publishedAt, + image: item.mainImage + ? imageBuilder.image(item.mainImage).width(600).height(300).fit('fillmax').url() + : undefined, + id: item._id, + url: item.webflowUrl + })) + } catch (e) { + const errMsg = ensureError(e).message + throw createError({ + statusCode: 500, + fatal: true, + message: `Error fetching tutorial items: ${errMsg}` + }) + } +}) diff --git a/packages/frontend-2/server/api/webflow.ts b/packages/frontend-2/server/api/webflow.ts deleted file mode 100644 index e388b9dee8..0000000000 --- a/packages/frontend-2/server/api/webflow.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { ensureError } from '@speckle/shared' -import type { WebflowItem } from '~/lib/dashboard/helpers/types' - -type WebflowApiResponse = { - items: Array<{ - id: string - lastPublished: string - createdOn: string - fieldData: { - name: string - slug: string - 'feature-image'?: { - url: string - } - html?: string - } - }> -} - -// Used to filter to last 6 months' articles to prevent old, -// recently edited posts from appearing at the top -const getSixMonthsAgo = (): Date => { - const date = new Date() - date.setMonth(date.getMonth() - 6) - return date -} - -export default defineEventHandler(async (): Promise<{ items: WebflowItem[] }> => { - const { webflowApiToken } = useRuntimeConfig() - const logger = useLogger() - - if (!webflowApiToken) { - logger.info('Webflow API token is not set. Returning an empty array of items.') - return { items: [] } - } - - const url = - 'https://api.webflow.com/v2/collections/66d79d1c9cdda972d5c718b4/items?limit=16&sortBy=lastPublished&sortOrder=desc' - - try { - const response = await fetch(url, { - headers: { - Authorization: `Bearer ${webflowApiToken}`, - 'accept-version': '2.0.0' - } - }) - - if (!response.ok) { - const errMsg = `Webflow API Error: ${response.status} ${response.statusText}` - throw createError({ - statusCode: response.status, - fatal: true, - message: errMsg - }) - } - - const data = (await response.json()) as WebflowApiResponse - - const sixMonthsAgo = getSixMonthsAgo() - - const filteredItems = data.items - .filter((item) => new Date(item.createdOn) > sixMonthsAgo) - .sort((a, b) => new Date(b.createdOn).getTime() - new Date(a.createdOn).getTime()) - .slice(0, 8) // Take only the first 8 items after filtering and sorting - - return { - items: filteredItems.map( - (item): WebflowItem => ({ - id: item.id, - title: item.fieldData.name, - createdOn: item.createdOn, - lastPublished: item.lastPublished, - featureImageUrl: item.fieldData['feature-image']?.url, - url: `https://speckle.systems/tutorials/${item.fieldData.slug}` - }) - ) - } - } catch (e) { - const errMsg = ensureError(e).message - throw createError({ - statusCode: 500, - fatal: true, - message: `Error fetching webflow items: ${errMsg}` - }) - } -}) diff --git a/utils/helm/speckle-server/templates/frontend_2/deployment.yml b/utils/helm/speckle-server/templates/frontend_2/deployment.yml index d43fbf0955..bbfc286c4d 100644 --- a/utils/helm/speckle-server/templates/frontend_2/deployment.yml +++ b/utils/helm/speckle-server/templates/frontend_2/deployment.yml @@ -97,9 +97,6 @@ spec: secretKeyRef: name: {{ default .Values.secretName .Values.redis.connectionString.secretName }} key: {{ default "redis_url" .Values.redis.connectionString.secretKey }} - {{- if .Values.frontend_2.webflowApiToken }} - - name: NUXT_WEBFLOW_API_TOKEN - value: {{ .Values.frontend_2.webflowApiToken | quote }} {{- end }} {{- if .Values.analytics.datadog_app_id }} - name: NUXT_PUBLIC_DATADOG_APP_ID diff --git a/utils/helm/speckle-server/values.schema.json b/utils/helm/speckle-server/values.schema.json index 55f5d69340..bf185ca4ef 100644 --- a/utils/helm/speckle-server/values.schema.json +++ b/utils/helm/speckle-server/values.schema.json @@ -1749,11 +1749,6 @@ "description": "The Docker image to be used for the Speckle Frontend 2 component. If blank, defaults to speckle/speckle-frontend-2:{{ .Values.docker_image_tag }}. If provided, this value should be the full path including tag. The docker_image_tag value will be ignored.", "default": "" }, - "webflowApiToken": { - "type": "string", - "description": "API Key for Webflow, which provides the blog content for the new web application frontend.", - "default": "" - }, "logClientApiToken": { "type": "string", "description": "SEQ API token", diff --git a/utils/helm/speckle-server/values.yaml b/utils/helm/speckle-server/values.yaml index 8922b5b002..de544b55e9 100644 --- a/utils/helm/speckle-server/values.yaml +++ b/utils/helm/speckle-server/values.yaml @@ -1047,9 +1047,6 @@ frontend_2: ## @param frontend_2.image The Docker image to be used for the Speckle Frontend 2 component. If blank, defaults to speckle/speckle-frontend-2:{{ .Values.docker_image_tag }}. If provided, this value should be the full path including tag. The docker_image_tag value will be ignored. ## image: '' - ## @param frontend_2.webflowApiToken API Key for Webflow, which provides the blog content for the new web application frontend. - ## - webflowApiToken: '' ## @param frontend_2.logClientApiToken SEQ API token ## logClientApiToken: '' diff --git a/yarn.lock b/yarn.lock index 092d9050d4..065a2bb16b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15545,6 +15545,47 @@ __metadata: languageName: node linkType: hard +"@sanity/client@npm:^6.24.3": + version: 6.24.3 + resolution: "@sanity/client@npm:6.24.3" + dependencies: + "@sanity/eventsource": "npm:^5.0.2" + get-it: "npm:^8.6.5" + rxjs: "npm:^7.0.0" + checksum: 10/41df837ed060d806de6ab2c8397996b8a42e5889fce73a75fc2558497a08bf47f8b046b157806df8b2c8496e87722817175872e988394cabb1d4fb92e2ba900b + languageName: node + linkType: hard + +"@sanity/eventsource@npm:^5.0.2": + version: 5.0.2 + resolution: "@sanity/eventsource@npm:5.0.2" + dependencies: + "@types/event-source-polyfill": "npm:1.0.5" + "@types/eventsource": "npm:1.1.15" + event-source-polyfill: "npm:1.0.31" + eventsource: "npm:2.0.2" + checksum: 10/a877f6175f2134e3f12119ec11b4f919ca03b7bd01dd7e400c88704f8de8085bfbe09216f225fc54344bcacba2f230642a3ea4a5f08e861652d742b3a1c4fa60 + languageName: node + linkType: hard + +"@sanity/image-url@npm:^1.1.0": + version: 1.1.0 + resolution: "@sanity/image-url@npm:1.1.0" + checksum: 10/e6caf270e19973d99ccb999ec5a1e6b185bb80ab275d31e21692d02dd109945ccda05fd54a9a797efc5768c10c32140a4d5dd85ec2c01a02955acc5d917b7e9f + languageName: node + linkType: hard + +"@sanity/types@npm:^3.70.0": + version: 3.70.0 + resolution: "@sanity/types@npm:3.70.0" + dependencies: + "@sanity/client": "npm:^6.24.3" + peerDependencies: + "@types/react": 18 || 19 + checksum: 10/b72d7b07c631547b4926b424359fd5b06989e54b4d6fa8dfea13364f8c0aa780c9ca71ebe3e35d4b95f5e7d7c87812d2f51073eaef9a7437a51d46409a2cae3c + languageName: node + linkType: hard + "@sideway/address@npm:^4.1.3": version: 4.1.4 resolution: "@sideway/address@npm:4.1.4" @@ -16861,6 +16902,8 @@ __metadata: "@nuxt/image": "npm:^1.8.1" "@nuxtjs/tailwindcss": "npm:^6.12.2" "@parcel/watcher": "npm:^2.4.1" + "@sanity/image-url": "npm:^1.1.0" + "@sanity/types": "npm:^3.70.0" "@speckle/shared": "workspace:^" "@speckle/tailwind-theme": "workspace:^" "@speckle/ui-components": "workspace:^" @@ -20006,6 +20049,20 @@ __metadata: languageName: node linkType: hard +"@types/event-source-polyfill@npm:1.0.5": + version: 1.0.5 + resolution: "@types/event-source-polyfill@npm:1.0.5" + checksum: 10/f506b68710162f2ade1bccbc5691b8c67e5a703e565df2bc0b7b5be2637ba838ef81ec6c10b03248fe4d054386d95a6e827c7aace6e924986c2b9985f77b55de + languageName: node + linkType: hard + +"@types/eventsource@npm:1.1.15": + version: 1.1.15 + resolution: "@types/eventsource@npm:1.1.15" + checksum: 10/52e024f5aebfd6bc166f2162d6e408cf788886007e571519c75f8c3623feaa3c5a74681fd3a128de6d21b28ef88dd683421264f10d5c98728959b99b1229b85e + languageName: node + linkType: hard + "@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.18": version: 4.17.28 resolution: "@types/express-serve-static-core@npm:4.17.28" @@ -20083,6 +20140,15 @@ __metadata: languageName: node linkType: hard +"@types/follow-redirects@npm:^1.14.4": + version: 1.14.4 + resolution: "@types/follow-redirects@npm:1.14.4" + dependencies: + "@types/node": "npm:*" + checksum: 10/bbf83961176957109dd92d350c2045a8550647886b78770a731b6e54cf97279c9ef21a55d6ee075243012ed3a4fab03cb5b184866cb975509f83de456a5b670a + languageName: node + linkType: hard + "@types/fs-extra@npm:^11.0.4": version: 11.0.4 resolution: "@types/fs-extra@npm:11.0.4" @@ -20741,6 +20807,15 @@ __metadata: languageName: node linkType: hard +"@types/progress-stream@npm:^2.0.5": + version: 2.0.5 + resolution: "@types/progress-stream@npm:2.0.5" + dependencies: + "@types/node": "npm:*" + checksum: 10/d97352a6146e4b5fa132b91352c6860ebebec48af3d52658a3b446ce1cb885d94e623b7a7d8ea2ddcaacf7a4b8ea67a4c30609c578b66c8ed49d31813adc2955 + languageName: node + linkType: hard + "@types/prosemirror-commands@npm:*, @types/prosemirror-commands@npm:^1.0.4": version: 1.0.4 resolution: "@types/prosemirror-commands@npm:1.0.4" @@ -28888,6 +28963,15 @@ __metadata: languageName: node linkType: hard +"decompress-response@npm:^7.0.0": + version: 7.0.0 + resolution: "decompress-response@npm:7.0.0" + dependencies: + mimic-response: "npm:^3.1.0" + checksum: 10/dfd216a4b24c6a9840e19986e8a9ca62e0b6ae35458e4135fdb84f2ba531a03ddc6ccfdc72782a361583c7d12a59787503381bd8372bf83f849eafadbaa8629c + languageName: node + linkType: hard + "dedent@npm:0.7.0": version: 0.7.0 resolution: "dedent@npm:0.7.0" @@ -31442,6 +31526,13 @@ __metadata: languageName: node linkType: hard +"event-source-polyfill@npm:1.0.31": + version: 1.0.31 + resolution: "event-source-polyfill@npm:1.0.31" + checksum: 10/901628a2fa1f83a430b657fdde6c86346df37956e208cd765c6761a8bca36c799a2372e37e48bc9e536956ae84a2b742e6ef20f1c5f047f79d8d2b4607bee3b8 + languageName: node + linkType: hard + "event-target-shim@npm:^5.0.0": version: 5.0.1 resolution: "event-target-shim@npm:5.0.1" @@ -31486,6 +31577,13 @@ __metadata: languageName: node linkType: hard +"eventsource@npm:2.0.2": + version: 2.0.2 + resolution: "eventsource@npm:2.0.2" + checksum: 10/e1c4c3664cebf9efdd55c90818ef847099f298bf521768d479cf22d8a681e666b3042de85327711ba6a8414ac6a04c70d2aeb4f405bba8239a8c36e06a019374 + languageName: node + linkType: hard + "evp_bytestokey@npm:^1.0.0, evp_bytestokey@npm:^1.0.3": version: 1.0.3 resolution: "evp_bytestokey@npm:1.0.3" @@ -32384,6 +32482,16 @@ __metadata: languageName: node linkType: hard +"follow-redirects@npm:^1.15.9": + version: 1.15.9 + resolution: "follow-redirects@npm:1.15.9" + peerDependenciesMeta: + debug: + optional: true + checksum: 10/e3ab42d1097e90d28b913903841e6779eb969b62a64706a3eb983e894a5db000fbd89296f45f08885a0e54cd558ef62e81be1165da9be25a6c44920da10f424c + languageName: node + linkType: hard + "for-each@npm:^0.3.3": version: 0.3.3 resolution: "for-each@npm:0.3.3" @@ -32880,6 +32988,21 @@ __metadata: languageName: node linkType: hard +"get-it@npm:^8.6.5": + version: 8.6.6 + resolution: "get-it@npm:8.6.6" + dependencies: + "@types/follow-redirects": "npm:^1.14.4" + "@types/progress-stream": "npm:^2.0.5" + decompress-response: "npm:^7.0.0" + follow-redirects: "npm:^1.15.9" + is-retry-allowed: "npm:^2.2.0" + progress-stream: "npm:^2.0.0" + tunnel-agent: "npm:^0.6.0" + checksum: 10/baa699c8aa456a01d010469a47df16b46aeb856eeb893b96d5114423c3a1b6f627f3d1211fc60e011d1c2939127d7e17809746b2ab916ad70c98e5efa1d81008 + languageName: node + linkType: hard + "get-nonce@npm:^1.0.0": version: 1.0.1 resolution: "get-nonce@npm:1.0.1" @@ -35726,6 +35849,13 @@ __metadata: languageName: node linkType: hard +"is-retry-allowed@npm:^2.2.0": + version: 2.2.0 + resolution: "is-retry-allowed@npm:2.2.0" + checksum: 10/6d8685530871f0b040346cc72322d90122473e921149affa16de363d6c2a6e46bc76abdfaac3259b93994ec8e7f70fbe67bbb080190e440533ff728e6a64494d + languageName: node + linkType: hard + "is-set@npm:^2.0.1, is-set@npm:^2.0.2": version: 2.0.2 resolution: "is-set@npm:2.0.2" @@ -44805,6 +44935,16 @@ __metadata: languageName: node linkType: hard +"progress-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "progress-stream@npm:2.0.0" + dependencies: + speedometer: "npm:~1.0.0" + through2: "npm:~2.0.3" + checksum: 10/839f1009f9feb3d14cbb9bef16eebaecf9560af7b7f64003bfb42c4db1a8e52b32d6bb5a14299a38522046c26bac1bbad1a99eec6fb8fc42b1d4ed3f21f22a41 + languageName: node + linkType: hard + "progress@npm:2.0.3": version: 2.0.3 resolution: "progress@npm:2.0.3" @@ -48625,6 +48765,13 @@ __metadata: languageName: node linkType: hard +"speedometer@npm:~1.0.0": + version: 1.0.0 + resolution: "speedometer@npm:1.0.0" + checksum: 10/6b322bbb0607c9994fba2a6ac189cf6caea4ce9f5067c1ccfc2848b55883f65d48292bfed4244ce855573ed7cdf0f69943ae6e507f7ec90eef232b64cdba6237 + languageName: node + linkType: hard + "split2@npm:^4.0.0, split2@npm:^4.1.0": version: 4.1.0 resolution: "split2@npm:4.1.0" @@ -50227,7 +50374,7 @@ __metadata: languageName: node linkType: hard -"through2@npm:^2.0.3": +"through2@npm:^2.0.3, through2@npm:~2.0.3": version: 2.0.5 resolution: "through2@npm:2.0.5" dependencies: