diff --git a/.env.local.example b/.env.local.example
index fbf5658f..7381629e 100644
--- a/.env.local.example
+++ b/.env.local.example
@@ -25,7 +25,18 @@ SENTRY_DSN_URL=https://sentrydsnurl
NEXT_PUBLIC_SENTRY_DSN_URL=https://sentrydsnurl
SENTRY_ORG_NAME='orgname'
SENTRY_PROJECT_NAME='projectname'
-NEXT_PUBLIC_PLATFORM_URL = 'https://platformurl'
+NEXT_PUBLIC_PLATFORM_URL=https://platformurl
+
+# Domain used for slug subdomains (recommended to set explicitly)
+# Local : localhost
+# Dev : dev.civicdataspace.in
+# Prod : civicdataspace.in
+NEXT_PUBLIC_PLATFORM_DOMAIN=platformdomain
+
+# Optional: set protocol/port explicitly for slug subdomain URLs
+NEXT_PUBLIC_PLATFORM_PROTOCOL=https
+NEXT_PUBLIC_PLATFORM_PORT=3000
+
# Google Analytics
NEXT_PUBLIC_GA_ID='G-XXXXXXXXXX'
diff --git a/.github/workflows/deploy-Dataspace-dev.yml b/.github/workflows/deploy-Dataspace-dev.yml
deleted file mode 100644
index 6c4801d6..00000000
--- a/.github/workflows/deploy-Dataspace-dev.yml
+++ /dev/null
@@ -1,81 +0,0 @@
-name: Update DataSpace Dev
-
-on:
- push:
- branches: ['dev']
-
-jobs:
- deploy:
- runs-on: ubuntu-latest
- environment: development
- env:
- KEYCLOAK_CLIENT_ID: ${{ secrets.KEYCLOAK_CLIENT_ID }}
- KEYCLOAK_CLIENT_SECRET: ${{ secrets.KEYCLOAK_CLIENT_SECRET }}
- AUTH_ISSUER: ${{ secrets.AUTH_ISSUER }}
- NEXTAUTH_URL: ${{ vars.NEXTAUTH_URL }}
- NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
- NEXT_PUBLIC_NEXTAUTH_URL: ${{ vars.NEXT_PUBLIC_NEXTAUTH_URL }}
- END_SESSION_URL: ${{ secrets.END_SESSION_URL }}
- REFRESH_TOKEN_URL: ${{ secrets.REFRESH_TOKEN_URL }}
- NEXT_PUBLIC_BACKEND_URL: ${{ vars.NEXT_PUBLIC_BACKEND_URL }}
- BACKEND_URL: ${{ vars.BACKEND_URL }}
- NEXT_PUBLIC_BACKEND_GRAPHQL_URL: ${{ vars.NEXT_PUBLIC_BACKEND_GRAPHQL_URL }}
- BACKEND_GRAPHQL_URL: ${{ vars.BACKEND_GRAPHQL_URL }}
- NEXT_PUBLIC_ENABLE_ACCESSMODEL: ${{ vars.NEXT_PUBLIC_ENABLE_ACCESSMODEL }}
- NEXT_PUBLIC_ANALYTICS_URL: ${{ vars.NEXT_PUBLIC_ANALYTICS_URL }}
- NEXT_PUBLIC_PLATFORM_URL: ${{ vars.NEXT_PUBLIC_PLATFORM_URL }}
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Setup Node.js
- uses: actions/setup-node@v4
- with:
- node-version: '20'
- cache: 'npm'
-
- - name: Install dependencies
- run: npm install --legacy-peer-deps
-
- - name: Generate
- run: npm run generate:ci
- env:
- BACKEND_GRAPHQL_URL: ${{ vars.BACKEND_GRAPHQL_URL }}
- NODE_ENV: production
-
- - name: Build
- run: npm run build
-
- - name: Rename .next to .next2
- run: mv .next .next2
-
- - name: Rename public to public2
- run: mv public public2
-
- - name: Send .next2 to EC2
- uses: appleboy/scp-action@v0.1.7
- with:
- host: ${{ vars.EC2_HOST }}
- username: ${{ secrets.EC2_USERNAME }}
- key: ${{ secrets.EC2_PRIVATE_KEY }}
- source: .next2
- target: DataExchange/DataExFrontend
-
- - name: Send public2 to EC2
- uses: appleboy/scp-action@v0.1.7
- with:
- host: ${{ vars.EC2_HOST }}
- username: ${{ secrets.EC2_USERNAME }}
- key: ${{ secrets.EC2_PRIVATE_KEY }}
- source: public2
- target: DataExchange/DataExFrontend
-
- - name: Update with new Build
- uses: appleboy/ssh-action@v1.0.3
- continue-on-error: false
- with:
- host: ${{ vars.EC2_HOST }}
- username: ${{ secrets.EC2_USERNAME }}
- key: ${{ secrets.EC2_PRIVATE_KEY }}
- script: rm -rf DataExchange/DataExFrontend/.next; rm -rf DataExchange/DataExFrontend/public; mv DataExchange/DataExFrontend/.next2 DataExchange/DataExFrontend/.next; mv DataExchange/DataExFrontend/public2 DataExchange/DataExFrontend/public; /home/ubuntu/.nvm/versions/node/v20.11.1/bin/pm2 restart dataspace
diff --git a/.github/workflows/deploy-Dataspace.yml b/.github/workflows/deploy-Dataspace.yml
index 0bf47fa5..65985553 100644
--- a/.github/workflows/deploy-Dataspace.yml
+++ b/.github/workflows/deploy-Dataspace.yml
@@ -1,38 +1,52 @@
-name: Update DataSpace Prod
+name: Deploy DataSpace
on:
push:
- branches: ['main']
-env:
- KEYCLOAK_CLIENT_ID: ${{secrets.KEYCLOAK_CLIENT_ID}}
- KEYCLOAK_CLIENT_SECRET: ${{secrets.KEYCLOAK_CLIENT_SECRET}}
- AUTH_ISSUER: ${{secrets.AUTH_ISSUER}}
- NEXTAUTH_URL: ${{secrets.NEXTAUTH_URL_DS}}
- NEXT_PUBLIC_NEXTAUTH_URL: ${{secrets.NEXT_PUBLIC_NEXTAUTH_URL_DS}}
- NEXTAUTH_SECRET: ${{secrets.NEXTAUTH_SECRET}}
- END_SESSION_URL: ${{secrets.END_SESSION_URL}}
- REFRESH_TOKEN_URL: ${{secrets.REFRESH_TOKEN_URL}}
- NEXT_PUBLIC_BACKEND_URL: ${{secrets.NEXT_PUBLIC_BACKEND_URL_DS}}
- BACKEND_GRAPHQL_URL: ${{secrets.BACKEND_GRAPHQL_URL_DS}}
- NEXT_PUBLIC_ENABLE_ACCESSMODEL: ${{secrets.NEXT_PUBLIC_ENABLE_ACCESSMODEL_DS}}
- NEXT_PUBLIC_BACKEND_GRAPHQL_URL: ${{secrets.NEXT_PUBLIC_BACKEND_GRAPHQL_URL_DS}}
- BACKEND_URL: ${{secrets.BACKEND_URL}}
- NEXT_PUBLIC_PLATFORM_URL: ${{secrets.NEXT_PUBLIC_PLATFORM_URL}}
- NEXT_PUBLIC_ANALYTICS_URL: ${{secrets.NEXT_PUBLIC_ANALYTICS_URL}}
+ branches:
+ - dev
+ - main
jobs:
deploy:
runs-on: ubuntu-latest
+ environment: ${{ github.ref_name == 'main' && 'production' || 'development' }}
+ env:
+ KEYCLOAK_CLIENT_ID: ${{ secrets.KEYCLOAK_CLIENT_ID }}
+ KEYCLOAK_CLIENT_SECRET: ${{ secrets.KEYCLOAK_CLIENT_SECRET }}
+ AUTH_ISSUER: ${{ secrets.AUTH_ISSUER }}
+ NEXTAUTH_URL: ${{ vars.NEXTAUTH_URL }}
+ NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
+ NEXT_PUBLIC_NEXTAUTH_URL: ${{ vars.NEXT_PUBLIC_NEXTAUTH_URL }}
+ END_SESSION_URL: ${{ secrets.END_SESSION_URL }}
+ REFRESH_TOKEN_URL: ${{ secrets.REFRESH_TOKEN_URL }}
+ NEXT_PUBLIC_BACKEND_URL: ${{ vars.NEXT_PUBLIC_BACKEND_URL }}
+ BACKEND_URL: ${{ vars.BACKEND_URL }}
+ NEXT_PUBLIC_BACKEND_GRAPHQL_URL: ${{ vars.NEXT_PUBLIC_BACKEND_GRAPHQL_URL }}
+ BACKEND_GRAPHQL_URL: ${{ vars.BACKEND_GRAPHQL_URL }}
+ NEXT_PUBLIC_ENABLE_ACCESSMODEL: ${{ vars.NEXT_PUBLIC_ENABLE_ACCESSMODEL }}
+ NEXT_PUBLIC_ANALYTICS_URL: ${{ vars.NEXT_PUBLIC_ANALYTICS_URL }}
+ NEXT_PUBLIC_PLATFORM_URL: ${{ vars.NEXT_PUBLIC_PLATFORM_URL }}
+ NEXT_PUBLIC_PLATFORM_PROTOCOL: ${{ vars.NEXT_PUBLIC_PLATFORM_PROTOCOL }}
+ NEXT_PUBLIC_PLATFORM_DOMAIN: ${{ vars.NEXT_PUBLIC_PLATFORM_DOMAIN }}
steps:
- name: Checkout code
uses: actions/checkout@v4
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: 'npm'
+
- name: Install dependencies
- run: npm install
+ run: npm install --legacy-peer-deps
- name: Generate
- run: npm run generate
+ run: npm run generate:ci
+ env:
+ BACKEND_GRAPHQL_URL: ${{ vars.BACKEND_GRAPHQL_URL }}
+ NODE_ENV: production
- name: Build
run: npm run build
@@ -41,30 +55,31 @@ jobs:
run: mv .next .next2
- name: Rename public to public2
- run: mv public public2
+ run: mv public public2
- name: Send .next2 to EC2
- uses: appleboy/scp-action@master
+ uses: appleboy/scp-action@v0.1.7
with:
- host: ${{ secrets.EC2_HOST_DS }}
- username: ${{ secrets.EC2_USERNAME_DS }}
+ host: ${{ vars.EC2_HOST }}
+ username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
source: .next2
target: DataExchange/DataExFrontend
- name: Send public2 to EC2
- uses: appleboy/scp-action@master
+ uses: appleboy/scp-action@v0.1.7
with:
- host: ${{ secrets.EC2_HOST_DS }}
- username: ${{ secrets.EC2_USERNAME_DS }}
+ host: ${{ vars.EC2_HOST }}
+ username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
source: public2
- target: DataExchange/DataExFrontend
-
+ target: DataExchange/DataExFrontend
+
- name: Update with new Build
uses: appleboy/ssh-action@v1.0.3
+ continue-on-error: false
with:
- host: ${{ secrets.EC2_HOST_DS }}
- username: ${{ secrets.EC2_USERNAME_DS }}
+ host: ${{ vars.EC2_HOST }}
+ username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
script: rm -rf DataExchange/DataExFrontend/.next; rm -rf DataExchange/DataExFrontend/public; mv DataExchange/DataExFrontend/.next2 DataExchange/DataExFrontend/.next; mv DataExchange/DataExFrontend/public2 DataExchange/DataExFrontend/public; /home/ubuntu/.nvm/versions/node/v20.11.1/bin/pm2 restart dataspace
diff --git a/.github/workflows/pre-merge.yml b/.github/workflows/pre-merge.yml
index 3f81b490..0df80218 100644
--- a/.github/workflows/pre-merge.yml
+++ b/.github/workflows/pre-merge.yml
@@ -6,7 +6,6 @@ on:
pull_request:
branches: ['dev']
-
jobs:
build:
runs-on: ubuntu-latest
@@ -27,6 +26,8 @@ jobs:
BACKEND_URL: ${{vars.BACKEND_URL}}
NEXT_PUBLIC_PLATFORM_URL: ${{vars.NEXT_PUBLIC_PLATFORM_URL}}
NEXT_PUBLIC_ANALYTICS_URL: ${{vars.NEXT_PUBLIC_ANALYTICS_URL}}
+ NEXT_PUBLIC_PLATFORM_PROTOCOL: ${{ vars.NEXT_PUBLIC_PLATFORM_PROTOCOL }}
+ NEXT_PUBLIC_PLATFORM_DOMAIN: ${{ vars.NEXT_PUBLIC_PLATFORM_DOMAIN }}
strategy:
matrix:
node-version: [20.x]
diff --git a/app/[locale]/(user)/collaboratives/CollaborativesListingClient.tsx b/app/[locale]/(user)/collaboratives/CollaborativesListingClient.tsx
index 3e5c4904..f7cefb3a 100644
--- a/app/[locale]/(user)/collaboratives/CollaborativesListingClient.tsx
+++ b/app/[locale]/(user)/collaboratives/CollaborativesListingClient.tsx
@@ -8,6 +8,7 @@ import { useQuery } from '@tanstack/react-query';
import { Button, Card, Icon, SearchInput, Select, Text } from 'opub-ui';
import { GraphQLPublic } from '@/lib/api';
+import { getCollaborativeDetailUrl } from '@/lib/collaborativesRouting';
import { cn, formatDate, generateJsonLd } from '@/lib/utils';
import BreadCrumbs from '@/components/BreadCrumbs';
import { Icons } from '@/components/icons';
@@ -97,7 +98,7 @@ const CollaborativesListingClient = () => {
try {
// @ts-expect-error - Query has no variables
const result = await GraphQLPublic(PublishedCollaboratives as any, {});
- console.log('Collaboratives result:', result);
+ // console.log('Collaboratives result:', result);
return result as { publishedCollaboratives: TypeCollaborative[] };
} catch (err) {
console.error('Error fetching collaboratives:', err);
@@ -336,7 +337,7 @@ const CollaborativesListingClient = () => {
stroke: 1.2,
},
]}
- href={`/collaboratives/${collaborative.slug}`}
+ href={getCollaborativeDetailUrl(collaborative.slug)}
leftFooterChips={[
{
icon: collaborative.sectors?.[0]?.name
diff --git a/app/[locale]/(user)/collaboratives/[collaborativeSlug]/CollaborativeDetailsClient.tsx b/app/[locale]/(user)/collaboratives/[collaborativeSlug]/CollaborativeDetailsClient.tsx
index 5112b762..f7a84cad 100644
--- a/app/[locale]/(user)/collaboratives/[collaborativeSlug]/CollaborativeDetailsClient.tsx
+++ b/app/[locale]/(user)/collaboratives/[collaborativeSlug]/CollaborativeDetailsClient.tsx
@@ -1,6 +1,6 @@
'use client';
-import { useEffect } from 'react';
+import { useEffect, useState } from 'react';
import Image from 'next/image';
import Link from 'next/link';
import { useParams } from 'next/navigation';
@@ -15,6 +15,7 @@ import { useQuery } from '@tanstack/react-query';
import { Card, Text } from 'opub-ui';
import { GraphQLPublic } from '@/lib/api';
+import { isCollaborativeSubdomainHost as isCollaborativeSubdomainHostname } from '@/lib/collaborativesRouting';
import { formatDate, generateJsonLd } from '@/lib/utils';
import BreadCrumbs from '@/components/BreadCrumbs';
import { Icons } from '@/components/icons';
@@ -217,9 +218,41 @@ const CollaborativeDetails = graphql(`
}
`);
+const getPlatformEntityUrl = (
+ entityPath: 'usecases' | 'datasets',
+ entityId: string | number,
+ locale?: string
+) => {
+ //Removes trailing slash
+ const platformBaseUrl = (process.env.NEXT_PUBLIC_PLATFORM_URL || '').replace(
+ /\/$/,
+ ''
+ );
+ const localeSegment = locale ? `/${locale}` : '';
+
+ if (!platformBaseUrl) {
+ return `/${entityPath}/${entityId}`;
+ }
+
+ return `${platformBaseUrl}${localeSegment}/${entityPath}/${entityId}`;
+};
+
const CollaborativeDetailClient = () => {
const params = useParams();
const { trackCollaborative } = useAnalytics();
+ const locale =
+ typeof (params as any)?.locale === 'string'
+ ? (params as any).locale
+ : undefined;
+ const [isCollaborativeSubdomainHost, setIsCollaborativeSubdomainHost] =
+ useState(false);
+
+ useEffect(() => {
+ if (typeof window === 'undefined') return;
+ setIsCollaborativeSubdomainHost(
+ isCollaborativeSubdomainHostname(window.location.hostname)
+ );
+ }, []);
const {
data: CollaborativeDetailsData,
@@ -250,12 +283,6 @@ const CollaborativeDetailClient = () => {
}
);
- console.log('Collaborative details query state:', {
- isLoading,
- error,
- data: CollaborativeDetailsData,
- });
-
// Track collaborative view when data is loaded
useEffect(() => {
if (CollaborativeDetailsData?.collaborativeBySlug) {
@@ -295,6 +322,17 @@ const CollaborativeDetailClient = () => {
},
});
+ const organizationPublisherHref = (org: any) => {
+ const path = `/publishers/organization/${org.id}`;
+ // Original: `/publishers/organization/${org.slug + '_' + org.id}`;
+ // Match getPlatformEntityUrl() behavior (absolute to platform host + locale)
+ const platformBaseUrl = (
+ process.env.NEXT_PUBLIC_PLATFORM_URL || ''
+ ).replace(/\/$/, '');
+ const localeSegment = locale ? `/${locale}` : '';
+ return platformBaseUrl ? `${platformBaseUrl}${localeSegment}${path}` : path;
+ };
+
return (
<>