From 9b1fb15ee1ba4a1ad0dad41ff075ecebb39e6b99 Mon Sep 17 00:00:00 2001 From: Lasantha Samarakoon Date: Thu, 18 Jun 2026 23:32:12 +0530 Subject: [PATCH 01/11] Fix settings menu in sidebar --- .../developer-portal/src/defaultContent/partials/sidebar.hbs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/portals/developer-portal/src/defaultContent/partials/sidebar.hbs b/portals/developer-portal/src/defaultContent/partials/sidebar.hbs index 57ff0cbfd..f527b5187 100644 --- a/portals/developer-portal/src/defaultContent/partials/sidebar.hbs +++ b/portals/developer-portal/src/defaultContent/partials/sidebar.hbs @@ -84,14 +84,12 @@ - {{#if showApiWorkflowsNav}} {{#if profile.isAdmin}} - + Settings {{/if}} - {{/if}} + + + + +
+

Deploying sample APIs

+

Starting deployment…

+
+
+
+
+
+ + +
+
+ + + +
+

All set!

+

Sample APIs were deployed to your portal. Taking you to your API catalog…

+

+
+ + + + diff --git a/portals/developer-portal/src/routes/pages/apiContentRoute.js b/portals/developer-portal/src/routes/pages/apiContentRoute.js index 63130fd78..a5b0700f3 100644 --- a/portals/developer-portal/src/routes/pages/apiContentRoute.js +++ b/portals/developer-portal/src/routes/pages/apiContentRoute.js @@ -46,6 +46,11 @@ router.get('/:orgName/views/:viewName/mcps.md', (req, res, next) => { next(); }, util.enforcePortalMode, apiController.loadMCPsMd); +router.post('/:orgName/views/:viewName/apis/seed-samples', (req, res, next) => { + if (req.params.orgName === 'favicon.ico') return res.status(404).json({ error: 'Not Found' }); + next(); +}, ensureAuthenticated, apiController.seedSamples); + router.get('/:orgName/views/:viewName/apis', (req, res, next) => { if (req.params.orgName === 'favicon.ico') { return res.status(404).send('Not Found'); diff --git a/portals/developer-portal/src/services/apiMetadataService.js b/portals/developer-portal/src/services/apiMetadataService.js index 17cc3510b..8c3d24a62 100644 --- a/portals/developer-portal/src/services/apiMetadataService.js +++ b/portals/developer-portal/src/services/apiMetadataService.js @@ -1901,5 +1901,7 @@ module.exports = { getView, getAllViews, getViewsFromDB, - getViewInfo + getViewInfo, + parseApiMetadataFromYamlFile, + prepareApiDefinitionForStorage, }; diff --git a/portals/developer-portal/src/services/sampleSeederService.js b/portals/developer-portal/src/services/sampleSeederService.js new file mode 100644 index 000000000..ccb6b406a --- /dev/null +++ b/portals/developer-portal/src/services/sampleSeederService.js @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2026, WSO2 LLC. (http://www.wso2.com) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const { Sequelize } = require('sequelize'); +const sequelize = require('../db/sequelizeConfig'); +const apiDao = require('../dao/apiDao'); +const apiFileDao = require('../dao/apiFileDao'); +const labelDao = require('../dao/labelDao'); +const subscriptionPolicyDao = require('../dao/subscriptionPolicyDao'); +const constants = require('../utils/constants'); +const logger = require('../config/logger'); +const { parseApiMetadataFromYamlFile, prepareApiDefinitionForStorage } = require('./apiMetadataService'); + +const DEFINITION_CANDIDATES = ['definition.yaml', 'definition.yml', 'definition.json', 'definition.graphql', 'definition.wsdl']; +const SAMPLES_DIR = path.join(process.cwd(), 'samples', 'apis'); + +function findDefinitionPath(apiDir) { + for (const name of DEFINITION_CANDIDATES) { + const candidate = path.join(apiDir, name); + if (fs.existsSync(candidate)) return candidate; + } + return null; +} + +/** + * Deploy all sample APIs from samples/apis/ into the given org. + * Already-existing APIs (UniqueConstraintError) are skipped silently. + * Returns an array of { name, status ('ok'|'exists'|'failed'), apiId?, error? }. + */ +async function seedSampleAPIs(orgId) { + if (!fs.existsSync(SAMPLES_DIR)) { + logger.warn('samples/apis directory not found — skipping sample seeding', { SAMPLES_DIR }); + return []; + } + + const entries = fs.readdirSync(SAMPLES_DIR) + .filter(e => { + const p = path.join(SAMPLES_DIR, e); + return fs.statSync(p).isDirectory() && fs.existsSync(path.join(p, 'api.yaml')); + }); + + const results = []; + + for (const entry of entries) { + const apiDir = path.join(SAMPLES_DIR, entry); + let apiName = entry; + let apiId; + + try { + const yamlBuffer = Buffer.from(fs.readFileSync(path.join(apiDir, 'api.yaml'))); + const apiMetadata = parseApiMetadataFromYamlFile('api.yaml', yamlBuffer); + apiName = apiMetadata.apiInfo.apiName || entry; + + // Load definition file if present + let apiDefinitionFile = null; + let apiFileName = ''; + const defPath = findDefinitionPath(apiDir); + if (defPath) { + const defName = path.basename(defPath); + const defBuffer = Buffer.from(fs.readFileSync(defPath)); + try { + const prepared = prepareApiDefinitionForStorage(defName, defBuffer); + apiDefinitionFile = prepared.apiDefinitionFile; + apiFileName = prepared.apiDefinitionFileName; + } catch (prepErr) { + // Non-standard type (e.g. WSDL): store raw + logger.debug(`prepareApiDefinitionForStorage skipped for ${entry}: ${prepErr.message}`); + apiDefinitionFile = defBuffer; + apiFileName = defName; + } + } + + await sequelize.transaction(async (t) => { + const created = await apiDao.create(orgId, apiMetadata, t); + apiId = created.dataValues.API_ID; + + // Subscription policy mappings (skip unknown policies — don't fail the whole deployment) + if (Array.isArray(apiMetadata.subscriptionPolicies) && apiMetadata.subscriptionPolicies.length) { + const mappings = []; + for (const p of apiMetadata.subscriptionPolicies) { + const policy = await subscriptionPolicyDao.getByName(orgId, p.policyName); + if (policy) mappings.push({ apiID: apiId, policyID: policy.POLICY_ID }); + } + if (mappings.length) await subscriptionPolicyDao.createApiMapping(mappings, apiId, t); + } + + // Label mappings + const labels = Array.isArray(apiMetadata.apiInfo.labels) && apiMetadata.apiInfo.labels.length + ? apiMetadata.apiInfo.labels + : ['default']; + await labelDao.createApiMapping(orgId, apiId, labels, t); + + // Definition file + if (apiDefinitionFile) { + const isGraphQL = apiMetadata.apiInfo.apiType === constants.API_TYPE.GRAPHQL; + const storedName = isGraphQL ? constants.FILE_NAME.API_DEFINITION_GRAPHQL : apiFileName; + await apiFileDao.store(apiDefinitionFile, storedName, apiId, constants.DOC_TYPES.API_DEFINITION, t); + } + }); + + results.push({ name: apiName, handle: apiMetadata.apiInfo.apiHandle, status: 'ok', apiId }); + logger.info('Seeded sample API', { orgId, apiName, apiId }); + + } catch (err) { + if (err instanceof Sequelize.UniqueConstraintError) { + results.push({ name: apiName, status: 'exists' }); + } else { + results.push({ name: apiName, status: 'failed', error: err.message }); + logger.error('Failed to seed sample API', { orgId, entry, error: err.message }); + } + } + } + + return results; +} + +module.exports = { seedSampleAPIs }; From ad53094a9a573f84d722b4eff9702b786f21f84d Mon Sep 17 00:00:00 2001 From: Lasantha Samarakoon Date: Fri, 19 Jun 2026 00:01:54 +0530 Subject: [PATCH 03/11] Revamp API listing page --- .../pages/apis/partials/api-listing.hbs | 243 +++--- .../src/defaultContent/styles/api-listing.css | 819 ++++++------------ 2 files changed, 398 insertions(+), 664 deletions(-) diff --git a/portals/developer-portal/src/defaultContent/pages/apis/partials/api-listing.hbs b/portals/developer-portal/src/defaultContent/pages/apis/partials/api-listing.hbs index 20d6cf22f..55933ad18 100644 --- a/portals/developer-portal/src/defaultContent/pages/apis/partials/api-listing.hbs +++ b/portals/developer-portal/src/defaultContent/pages/apis/partials/api-listing.hbs @@ -1,5 +1,5 @@
+
-
-

- Discover, Integrate, and Innovate with Scalable APIs -

-
- Explore our extensive API catalog and discover how to integrate them seamlessly into your application. -
-
+

Discover, Integrate, and Innovate with Scalable APIs

+

Explore our extensive API catalog and discover how to integrate them seamlessly into your application.

-
- Hero Image +
+ + + + + + + + + + + + + + +
+
+
- search +
-
- {{#if (eq apiMetadata.length 0)}} -
-
-
-
- No APIs available. -
-
-
+ + {{#if (eq apiMetadata.length 0)}} + +
+
+
- {{/if}} +
+
No APIs available yet
+

There are no published APIs in this developer portal right now. Once APIs are published, they'll appear here for you to explore and subscribe to.

+
+
+ {{else}} + +
+

APIs {{apiMetadata.length}}

+
+ {{/if}} + + +
+ {{#apiMetadata}} {{#unless (eq apiInfo.apiType "MCP")}}
-
-
- {{#if apiInfo.apiImageMetadata.api-icon}} - ... - {{else}} -
{{firstTwoLetters apiInfo.apiName}}
- {{/if}} -
-
{{apiInfo.apiName}}
-
-

{{apiInfo.apiVersion}}

-
-
- {{#if (eq apiInfo.apiType "WS")}} - - {{else if (eq apiInfo.apiType "GRAPHQL")}} - - {{else if (eq apiInfo.apiType "WEBSUB")}} - - {{else}} - - {{/if}} -
- {{#if (eq apiInfo.apiType "WS")}} - WebSocket - {{else if (eq apiInfo.apiType "WEBSUB")}} - WebSub - {{else}} - {{apiInfo.apiType}} - {{/if}} -
+
+ + +
+ {{#if apiInfo.apiImageMetadata.api-icon}} + {{apiInfo.apiName}} + {{else}} + {{firstTwoLetters apiInfo.apiName}} + {{/if}} +
+
{{apiInfo.apiName}}
+
+ {{apiInfo.apiVersion}} + + {{#if (eq apiInfo.apiType "GRAPHQL")}} GraphQL + {{else if (eq apiInfo.apiType "WS")}} WebSocket + {{else if (eq apiInfo.apiType "WEBSUB")}} WebSub + {{else if (eq apiInfo.apiType "SOAP")}} SOAP + {{else}} REST{{/if}} +
-
- {{#if ../showApiWorkflowsNav}} - {{#unless (eq apiInfo.agentVisibility "HIDDEN")}} - - - AI Ready + {{#if ../showApiWorkflowsNav}} + {{#unless (eq apiInfo.agentVisibility "HIDDEN")}} +
+ + + AI Ready - {{/unless}} - {{/if}}
+ {{/unless}} + {{/if}}
{{#if ../isAuthenticated}} -
Subscribed
+
Subscribed
{{/if}}
-
-
{{apiInfo.apiDescription}}
- - {{#if ../isAuthenticated}} - {{#if subscriptionPolicies}} -
-
-
- - - Plans - ({{subscriptionPolicies.length}}) - - {{!-- optional: show “Free available” if any plan is free --}} - {{#if (some subscriptionPolicies "isFreePlan")}} - Free available - {{/if}} -
+ +

{{apiInfo.apiDescription}}

- - View plans - -
-
- {{/if}} - {{/if}} -
-
- {{#apiInfo.tags}} - {{this}} - {{/apiInfo.tags}} -
-
+ +
+ {{#apiInfo.tags}} + {{this}} + {{/apiInfo.tags}}
- {{#if subscriptionPolicies.length}} -
- {{/if}} + + @@ -184,6 +164,7 @@ {{/apiMetadata}}
+ @@ -9,37 +10,195 @@ {{/pageScripts}} -
-
- - Home + + + +
+ + + Home + +

Settings

+ +
+ + + + + +
+ + +
+
+ {{> llms-config}}
- + + +
+
+ {{> api-flows}}
-
-
+
+ + +
+
+
+

Manage APIs

+

Publish, unpublish, and manage the APIs visible in this developer portal.

+
+ +
+ +
+ + + + + + + + + + + {{#orgAPIs}} + + + + + + + {{/orgAPIs}} + {{#unless orgAPIs.length}} + + + + {{/unless}} + +
APITypeStatus
+
+ {{firstTwoLetters apiName}} + {{apiName}} +
+
+ + {{#if (eq apiType "WS")}}WebSocket + {{else if (eq apiType "GRAPHQL")}}GraphQL + {{else if (eq apiType "SOAP")}}SOAP + {{else if (eq apiType "WEBSUB")}}WebSub + {{else}}REST{{/if}} + + + + Published + + + +
No APIs found.
+
+
+ + +
+
+
+

Manage Organizations

+

Organizations group members and their access to this developer portal.

+
+
+ +
+ +
+
+
{{> alert}} + + diff --git a/portals/developer-portal/src/services/sampleSeederService.js b/portals/developer-portal/src/services/sampleSeederService.js index ccb6b406a..8fd9c7046 100644 --- a/portals/developer-portal/src/services/sampleSeederService.js +++ b/portals/developer-portal/src/services/sampleSeederService.js @@ -41,6 +41,32 @@ function findDefinitionPath(apiDir) { return null; } +/** + * Recursively read docs/ under an API directory. + * Top-level .md files → TYPE = DOC_Other + * Files in a subdirectory (e.g. docs/FAQ/) → TYPE = DOC_FAQ + * Returns [{ type, fileName, content }] + */ +function readDocFiles(docsDir, subDir) { + const docs = []; + if (!fs.existsSync(docsDir)) return docs; + for (const entry of fs.readdirSync(docsDir)) { + if (entry.startsWith('.')) continue; + const full = path.join(docsDir, entry); + if (fs.statSync(full).isDirectory()) { + docs.push(...readDocFiles(full, entry)); + } else if (/\.(md|MD)$/.test(entry)) { + const docType = subDir || constants.DOC_TYPES.DOCS.OTHER; + docs.push({ + type: constants.DOC_TYPES.DOC_ID + docType, + fileName: entry, + content: Buffer.from(fs.readFileSync(full)), + }); + } + } + return docs; +} + /** * Deploy all sample APIs from samples/apis/ into the given org. * Already-existing APIs (UniqueConstraintError) are skipped silently. @@ -115,6 +141,12 @@ async function seedSampleAPIs(orgId) { const storedName = isGraphQL ? constants.FILE_NAME.API_DEFINITION_GRAPHQL : apiFileName; await apiFileDao.store(apiDefinitionFile, storedName, apiId, constants.DOC_TYPES.API_DEFINITION, t); } + + // Documentation files from docs/ + const docs = readDocFiles(path.join(apiDir, 'docs'), ''); + if (docs.length) { + await apiFileDao.storeMany(docs, apiId, t); + } }); results.push({ name: apiName, handle: apiMetadata.apiInfo.apiHandle, status: 'ok', apiId }); diff --git a/portals/developer-portal/src/styles/settings-layout.css b/portals/developer-portal/src/styles/settings-layout.css new file mode 100644 index 000000000..346d2d339 --- /dev/null +++ b/portals/developer-portal/src/styles/settings-layout.css @@ -0,0 +1,352 @@ +/* ── Settings page layout ────────────────────────────────── */ + +:root { + --wso2-gradient: linear-gradient(135deg, #ef4223 0%, #ff8636 100%); +} + +.cfg-page { + padding: 24px 36px 40px; +} + +.cfg-back-link { + display: inline-flex; + align-items: center; + gap: 8px; + color: #637282; + font-size: 0.844rem; + font-weight: 500; + text-decoration: none; +} + +.cfg-back-link:hover { color: #1a2433; } + +.cfg-heading { + margin: 14px 0 22px; + font-size: 1.5rem; + font-weight: 700; + color: #1a2433; +} + +/* ── Two-column layout ───────────────────────────────────── */ + +.cfg-layout { + display: flex; + gap: 32px; + align-items: flex-start; +} + +/* ── Left sub-nav ────────────────────────────────────────── */ + +.cfg-nav { + width: 252px; + flex: none; +} + +.cfg-nav-section { + font-size: 0.688rem; + font-weight: 700; + letter-spacing: 0.07em; + color: #9aa3af; + padding: 0 12px; + text-transform: uppercase; +} + +.cfg-nav-section + .cfg-nav-items { margin-top: 10px; } + +.cfg-nav-items { + display: flex; + flex-direction: column; + gap: 3px; + margin-bottom: 22px; +} + +.cfg-nav-item { + display: flex; + align-items: center; + gap: 11px; + padding: 10px 12px; + border-radius: 9px; + cursor: pointer; + text-decoration: none; + font-size: 0.844rem; + font-weight: 500; + color: #44505f; + background: transparent; + transition: background-color 0.15s; + white-space: nowrap; +} + +.cfg-nav-item i { font-size: 1rem; flex: none; } + +.cfg-nav-item:hover { + background: #f1f4f8; + color: #1a2433; + text-decoration: none; +} + +.cfg-nav-item.active { + background: #eef4fb; + color: #1f6feb; + font-weight: 600; +} + +/* ── Content area ────────────────────────────────────────── */ + +.cfg-content { + flex: 1; + min-width: 0; + border-left: 1px solid #e6eaf0; + padding-left: 32px; +} + +.cfg-panel { + display: none; + flex-direction: column; +} + +.cfg-panel.active { + display: flex; +} + +/* ── Panel header (title + action button) ───────────────── */ + +.cfg-panel-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 16px; + margin-bottom: 22px; +} + +.cfg-panel-title { + margin: 0; + font-size: 1.25rem; + font-weight: 700; + color: #1a2433; +} + +.cfg-panel-desc { + margin: 6px 0 0; + font-size: 0.875rem; + line-height: 1.5; + color: #637282; +} + +/* ── Primary button ──────────────────────────────────────── */ + +.cfg-btn-primary { + flex: none; + display: inline-flex; + align-items: center; + gap: 8px; + background: var(--wso2-gradient); + color: #fff; + border: none; + border-radius: 20px; + padding: 11px 20px; + font-size: 0.844rem; + font-weight: 600; + cursor: pointer; + text-decoration: none; + transition: opacity 0.15s; + white-space: nowrap; +} + +.cfg-btn-primary:hover { opacity: 0.9; color: #fff; text-decoration: none; } + +.cfg-btn-primary:disabled { + opacity: 0.55; + cursor: default; + pointer-events: none; +} + +/* ── Manage APIs table ───────────────────────────────────── */ + +.cfg-table-wrap { + border: 1px solid #e6eaf0; + border-radius: 12px; + overflow: hidden; +} + +.cfg-table { + width: 100%; + border-collapse: collapse; +} + +.cfg-table thead tr { background: #f6f8fb; } + +.cfg-table th { + text-align: left; + padding: 12px 18px; + font-size: 0.719rem; + font-weight: 600; + letter-spacing: 0.04em; + color: #8a93a0; + text-transform: uppercase; +} + +.cfg-table tbody tr { border-top: 1px solid #eef1f5; } + +.cfg-table tbody tr:hover { background: #fafbfc; } + +.cfg-table td { padding: 13px 18px; } + +/* API name cell */ +.cfg-api-cell { + display: flex; + align-items: center; + gap: 11px; +} + +.cfg-api-avatar { + width: 32px; + height: 32px; + flex: none; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.75rem; + font-weight: 700; + text-transform: uppercase; +} + +.cfg-api-avatar--rest { background: #e6f2fb; color: #0277bd; } +.cfg-api-avatar--graphql { background: #fce4ef; color: #d6336c; } +.cfg-api-avatar--soap { background: #ece9fb; color: #6741d9; } +.cfg-api-avatar--ws { background: #fff1e6; color: #e65100; } + +.cfg-cell-name { + font-size: 0.875rem; + font-weight: 600; + color: #1a2433; +} + +/* Type badge */ +.cfg-type-badge { + display: inline-flex; + align-items: center; + border-radius: 6px; + padding: 4px 8px; + font-size: 0.688rem; + font-weight: 600; +} + +.cfg-type-badge--rest { background: #e6f2fb; color: #0277bd; } +.cfg-type-badge--graphql { background: #fce4ef; color: #d6336c; } +.cfg-type-badge--soap { background: #ece9fb; color: #6741d9; } +.cfg-type-badge--ws { background: #fff1e6; color: #e65100; } + +/* Status badge */ +.cfg-status-badge { + display: inline-flex; + align-items: center; + gap: 6px; + border-radius: 20px; + padding: 5px 11px; + font-size: 0.75rem; + font-weight: 600; +} + +.cfg-status-dot { + width: 6px; + height: 6px; + border-radius: 50%; + flex: none; +} + +.cfg-status-published { + background: #e6f4ea; + color: #2e7d32; +} + +.cfg-status-published .cfg-status-dot { background: #2e7d32; } + +.cfg-status-draft { + background: #f1f4f8; + color: #8a93a0; +} + +.cfg-status-draft .cfg-status-dot { background: #8a93a0; } + +/* Actions cell */ +.cfg-cell-actions { text-align: center; } + +.cfg-action-btn { + background: none; + border: none; + color: #9aa3af; + cursor: pointer; + padding: 4px 8px; + border-radius: 6px; + transition: color 0.15s, background 0.15s; +} + +.cfg-action-btn:hover { color: #1a2433; background: #f1f4f8; } +.cfg-action-btn:disabled { opacity: 0.4; cursor: default; pointer-events: none; } + +.cfg-empty-row { + text-align: center; + color: #9aa3af; + font-size: 0.875rem; + padding: 28px 18px !important; +} + +/* ── Manage Organizations link panel ─────────────────────── */ + +.cfg-orgs-link-panel { + display: flex; + align-items: flex-start; + gap: 16px; + background: #f6f8fb; + border: 1px solid #e6eaf0; + border-radius: 12px; + padding: 22px 24px; +} + +.cfg-orgs-link-icon { + flex: none; + width: 46px; + height: 46px; + border-radius: 11px; + background: #e6f2fb; + color: #0277bd; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.375rem; +} + +.cfg-orgs-link-body { flex: 1; min-width: 0; } + +.cfg-orgs-link-title { + font-size: 0.9375rem; + font-weight: 600; + color: #1a2433; + line-height: 1.3; +} + +.cfg-orgs-link-desc { + margin: 4px 0 16px; + font-size: 0.844rem; + line-height: 1.5; + color: #637282; +} + +.cfg-orgs-link-btn { margin-top: 0; } + +/* ── Responsive ──────────────────────────────────────────── */ + +@media (max-width: 900px) { + .cfg-layout { flex-direction: column; gap: 0; } + .cfg-nav { + width: 100%; + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-bottom: 20px; + } + .cfg-nav-section { display: none; } + .cfg-nav-items { flex-direction: row; flex-wrap: wrap; margin-bottom: 0; } + .cfg-content { border-left: none; padding-left: 0; border-top: 1px solid #e6eaf0; padding-top: 20px; } +} From 11cb840a188bf6e2508f540f49e27ccf892296da Mon Sep 17 00:00:00 2001 From: Lasantha Samarakoon Date: Fri, 19 Jun 2026 12:55:20 +0530 Subject: [PATCH 05/11] Fix admin user flow --- .../controllers/viewConfigureController.js | 1 + .../src/pages/api-flows/page.hbs | 513 +++++++++++++++-- .../src/styles/settings-layout.css | 543 ++++++++++++++++++ 3 files changed, 995 insertions(+), 62 deletions(-) diff --git a/portals/developer-portal/src/controllers/viewConfigureController.js b/portals/developer-portal/src/controllers/viewConfigureController.js index c795175ef..d5072cdf0 100644 --- a/portals/developer-portal/src/controllers/viewConfigureController.js +++ b/portals/developer-portal/src/controllers/viewConfigureController.js @@ -61,6 +61,7 @@ const loadViewSettingsPage = async (req, res) => { apiHandle: api.API_HANDLE, apiDescription: api.API_DESCRIPTION, apiType: api.API_TYPE, + apiVersion: api.API_VERSION, productionUrl: api.PRODUCTION_URL, agentVisibility: api.AGENT_VISIBILITY })); diff --git a/portals/developer-portal/src/pages/api-flows/page.hbs b/portals/developer-portal/src/pages/api-flows/page.hbs index 50df35198..b941f17b5 100644 --- a/portals/developer-portal/src/pages/api-flows/page.hbs +++ b/portals/developer-portal/src/pages/api-flows/page.hbs @@ -69,72 +69,244 @@
-
-
-

Manage APIs

-

Publish, unpublish, and manage the APIs visible in this developer portal.

+ + +
+
+
+

Manage APIs

+

Add, edit, and remove the APIs visible in this developer portal.

+
+ +
+ +
+ + + + + + + + + + + + {{#orgAPIs}} + + + + + + + + {{/orgAPIs}} + {{#unless orgAPIs.length}} + + + + {{/unless}} + +
APITypeVersionStatus
+
+ {{firstTwoLetters apiName}} +
+
{{apiName}}
+
/{{apiHandle}}
+
+
+
+ + {{#if (eq apiType "WS")}}WebSocket + {{else if (eq apiType "GRAPHQL")}}GraphQL + {{else if (eq apiType "SOAP")}}SOAP + {{else if (eq apiType "WEBSUB")}}WebSub + {{else}}REST{{/if}} + + {{apiVersion}} + + Published + + + +
+ + +
+
No APIs found.
-
-
- - - - - - - - - - - {{#orgAPIs}} - - - - - - - {{/orgAPIs}} - {{#unless orgAPIs.length}} - - - - {{/unless}} - -
APITypeStatus
-
- {{firstTwoLetters apiName}} - {{apiName}} -
-
- - {{#if (eq apiType "WS")}}WebSocket - {{else if (eq apiType "GRAPHQL")}}GraphQL - {{else if (eq apiType "SOAP")}}SOAP - {{else if (eq apiType "WEBSUB")}}WebSub - {{else}}REST{{/if}} - - - - Published - - - -
No APIs found.
+ + +
@@ -161,6 +333,21 @@
+ + + {{> alert}} + + diff --git a/portals/developer-portal/src/styles/settings-layout.css b/portals/developer-portal/src/styles/settings-layout.css index 346d2d339..b422fc141 100644 --- a/portals/developer-portal/src/styles/settings-layout.css +++ b/portals/developer-portal/src/styles/settings-layout.css @@ -350,3 +350,546 @@ .cfg-nav-items { flex-direction: row; flex-wrap: wrap; margin-bottom: 0; } .cfg-content { border-left: none; padding-left: 0; border-top: 1px solid #e6eaf0; padding-top: 20px; } } + +/* ── Table extras (version / context cells) ──────────────── */ + +.cfg-cell-version { + font-family: monospace; + font-size: 0.8125rem; + color: #637282; + padding: 13px 14px !important; +} + +.cfg-cell-context { + font-family: monospace; + font-size: 0.6875rem; + color: #9aa3af; + margin-top: 3px; +} + +/* ── Dropdown menu ───────────────────────────────────────── */ + +.cfg-cell-actions { position: relative; text-align: center; } + +.cfg-dropdown { + position: absolute; + top: calc(100% - 6px); + right: 8px; + z-index: 50; + width: 148px; + background: #fff; + border: 1px solid #e6eaf0; + border-radius: 10px; + box-shadow: 0 10px 28px rgba(20, 40, 70, 0.16); + padding: 6px; + flex-direction: column; + display: none; +} + +.cfg-dropdown-item { + display: flex; + align-items: center; + gap: 9px; + width: 100%; + padding: 9px 10px; + border: none; + background: none; + border-radius: 7px; + font-size: 0.844rem; + font-weight: 500; + color: #1a2433; + cursor: pointer; + text-align: left; + transition: background 0.12s; +} + +.cfg-dropdown-item:hover:not(:disabled) { background: #f4f6f9; } +.cfg-dropdown-item--danger { color: #c62828; } +.cfg-dropdown-item--danger:hover:not(:disabled) { background: #fdeaea; } +.cfg-dropdown-item:disabled { opacity: 0.45; cursor: default; pointer-events: none; } + +/* ── Wizard container ────────────────────────────────────── */ + +#cfg-apis-wizard { + flex-direction: column; +} + +.cfg-wizard-back { + display: inline-flex; + align-items: center; + gap: 7px; + color: #637282; + font-size: 0.8125rem; + font-weight: 600; + text-decoration: none; +} + +.cfg-wizard-back:hover { color: #1a2433; text-decoration: none; } + +/* ── Stepper ─────────────────────────────────────────────── */ + +.cfg-stepper { + display: flex; + align-items: center; + margin-top: 22px; + margin-bottom: 0; +} + +.cfg-step { + display: flex; + align-items: center; + gap: 10px; + cursor: default; +} + +.cfg-step-circle { + width: 28px; + height: 28px; + flex: none; + border-radius: 50%; + background: #eef1f5; + color: #8a93a0; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.781rem; + font-weight: 700; + line-height: 1; + transition: background 0.2s, color 0.2s; +} + +.cfg-step--active .cfg-step-circle { background: #1f6feb; color: #fff; } +.cfg-step--done .cfg-step-circle { background: #2e7d32; color: #fff; } +.cfg-step--done { cursor: pointer; } + +.cfg-step-label { + font-size: 0.8125rem; + font-weight: 600; + color: #9aa3af; + white-space: nowrap; + transition: color 0.2s; +} + +.cfg-step--active .cfg-step-label { color: #1f6feb; } +.cfg-step--done .cfg-step-label { color: #1a2433; } + +.cfg-step-connector { + flex: 1; + height: 2px; + min-width: 24px; + background: #e6eaf0; + margin: 0 14px; + transition: background 0.2s; +} + +.cfg-step-connector--done { background: #2e7d32; } + +/* ── Wizard step panels ──────────────────────────────────── */ + +.cfg-wizard-step { + margin-top: 26px; + max-width: 680px; + display: flex; + flex-direction: column; +} + +.cfg-wstep-desc { + margin: 0 0 18px; + font-size: 0.844rem; + line-height: 1.55; + color: #637282; +} + +/* ── Wizard form ─────────────────────────────────────────── */ + +.cfg-form-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 18px; +} + +.cfg-form-group label { + display: block; + font-size: 0.8125rem; + font-weight: 600; + color: #1a2433; + margin-bottom: 8px; +} + +.cfg-form-group .required { color: #c62828; } + +.cfg-form-input { + width: 100%; + border: 1px solid #d0d7de; + border-radius: 8px; + padding: 11px 13px; + font-size: 0.875rem; + font-family: inherit; + color: #1a2433; + background: #fff; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; + appearance: auto; +} + +.cfg-form-input:focus { + border-color: #1f6feb; + box-shadow: 0 0 0 3px rgba(31, 111, 235, 0.12); +} + +.cfg-form-input--mono { font-family: monospace; font-size: 0.8125rem; } + +/* ── File upload zone ────────────────────────────────────── */ + +.cfg-upload-zone { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 12px; + padding: 42px 20px; + border: 1.5px dashed #c3d0de; + border-radius: 14px; + background: #f8fafc; + cursor: pointer; + transition: border-color 0.15s, background 0.15s; +} + +.cfg-upload-zone:hover { border-color: #1f6feb; background: #f1f6fd; } +.cfg-upload-zone input[type=file] { display: none; } + +.cfg-upload-icon { + width: 54px; + height: 54px; + border-radius: 13px; + background: #e6f2fb; + color: #0277bd; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.5rem; +} + +.cfg-upload-label { + font-size: 0.906rem; + font-weight: 600; + color: #1a2433; +} + +.cfg-upload-label span { color: #1f6feb; } +.cfg-upload-hint { font-size: 0.781rem; color: #9aa3af; } + +/* ── Spec chip (uploaded file indicator) ─────────────────── */ + +.cfg-spec-chip { + display: none; + align-items: center; + gap: 12px; + margin-top: 16px; + border: 1px solid #d4e7d9; + background: #f3faf4; + border-radius: 10px; + padding: 13px 15px; +} + +.cfg-spec-chip.visible { display: flex; } + +.cfg-spec-icon { + width: 34px; + height: 34px; + flex: none; + border-radius: 8px; + background: #e6f4ea; + color: #2e7d32; + display: flex; + align-items: center; + justify-content: center; + font-size: 1rem; +} + +.cfg-spec-name { + flex: 1; + min-width: 0; + font-size: 0.844rem; + font-weight: 600; + color: #1a2433; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.cfg-spec-sub { font-size: 0.719rem; color: #637282; margin-top: 2px; } + +/* ── Docs upload (compact variant) ──────────────────────── */ + +.cfg-upload-compact { + display: flex; + align-items: center; + justify-content: center; + gap: 11px; + padding: 22px; + border: 1.5px dashed #c3d0de; + border-radius: 12px; + background: #f8fafc; + cursor: pointer; + transition: border-color 0.15s, background 0.15s; +} + +.cfg-upload-compact:hover { border-color: #1f6feb; background: #f1f6fd; } +.cfg-upload-compact input[type=file] { display: none; } + +.cfg-docs-empty { + margin-top: 16px; + font-size: 0.8125rem; + color: #9aa3af; + text-align: center; + padding: 14px; +} + +.cfg-docs-list { + margin-top: 14px; + display: flex; + flex-direction: column; + gap: 10px; +} + +.cfg-docs-item { + display: flex; + align-items: center; + gap: 12px; + border: 1px solid #e6eaf0; + border-radius: 10px; + padding: 12px 14px; +} + +.cfg-docs-icon { + width: 32px; + height: 32px; + flex: none; + border-radius: 8px; + background: #eef1f5; + color: #52606d; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.9rem; +} + +.cfg-docs-name { + flex: 1; + min-width: 0; + font-size: 0.844rem; + font-weight: 600; + color: #1a2433; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.cfg-docs-remove { + color: #9aa3af; + cursor: pointer; + padding: 5px; + border: none; + background: none; + border-radius: 6px; + line-height: 1; + display: inline-flex; + align-items: center; + justify-content: center; + transition: color 0.12s, background 0.12s; +} + +.cfg-docs-remove:hover { color: #c62828; background: #fdeaea; } + +/* ── Review step ─────────────────────────────────────────── */ + +.cfg-review-section { + border: 1px solid #e6eaf0; + border-radius: 12px; + overflow: hidden; +} + +.cfg-review-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 14px 18px; + background: #f6f8fb; +} + +.cfg-review-header + .cfg-review-header { + border-top: 1px solid #eef1f5; +} + +.cfg-review-header-title { + font-size: 0.75rem; + font-weight: 700; + letter-spacing: 0.05em; + color: #8a93a0; + text-transform: uppercase; +} + +.cfg-review-edit { + font-size: 0.781rem; + font-weight: 600; + color: #1f6feb; + cursor: pointer; + background: none; + border: none; + padding: 0; +} + +.cfg-review-edit:hover { text-decoration: underline; } + +.cfg-review-body { padding: 8px 18px 16px; } + +.cfg-review-grid { + display: grid; + grid-template-columns: 160px 1fr; + gap: 4px 16px; + font-size: 0.844rem; + line-height: 1.7; +} + +.cfg-review-label { color: #8a93a0; } +.cfg-review-value { color: #1a2433; font-weight: 600; } +.cfg-review-value--mono { font-family: monospace; font-size: 0.8125rem; font-weight: 400; } + +/* ── Wizard footer ───────────────────────────────────────── */ + +.cfg-wizard-actions { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: 26px; + padding-top: 18px; + border-top: 1px solid #e6eaf0; +} + +.cfg-wizard-actions-right { + display: flex; + gap: 12px; + align-items: center; +} + +.cfg-btn-ghost { + background: none; + border: none; + color: #637282; + font-size: 0.875rem; + font-weight: 600; + cursor: pointer; + padding: 11px 4px; +} + +.cfg-btn-ghost:hover { color: #1a2433; } + +.cfg-btn-secondary { + display: inline-flex; + align-items: center; + gap: 7px; + background: #fff; + border: 1px solid #cdd8e6; + color: #1f3d5c; + border-radius: 20px; + padding: 11px 20px; + font-size: 0.875rem; + font-weight: 600; + cursor: pointer; + transition: background 0.15s; + text-decoration: none; +} + +.cfg-btn-secondary:hover { background: #f3f7fc; color: #1f3d5c; text-decoration: none; } + +/* ── Delete confirmation modal ───────────────────────────── */ + +.cfg-modal-overlay { + position: fixed; + inset: 0; + background: rgba(20, 40, 70, 0.34); + backdrop-filter: blur(6px); + -webkit-backdrop-filter: blur(6px); + align-items: center; + justify-content: center; + z-index: 1000; +} + +.cfg-modal { + width: 420px; + max-width: calc(100vw - 32px); + background: #fff; + border-radius: 16px; + padding: 30px; + box-shadow: 0 24px 60px rgba(10, 25, 50, 0.34); + animation: cfg-pop 0.28s ease; +} + +@keyframes cfg-pop { + from { opacity: 0; transform: translateY(10px) scale(0.985); } + to { opacity: 1; transform: none; } +} + +.cfg-modal-header { + display: flex; + align-items: center; + gap: 14px; + margin-bottom: 16px; +} + +.cfg-modal-icon { + width: 46px; + height: 46px; + flex: none; + border-radius: 11px; + background: #fdeaea; + color: #c62828; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.25rem; +} + +.cfg-modal-title { + margin: 0; + font-size: 1.125rem; + font-weight: 700; + color: #1a2433; +} + +.cfg-modal-body { + font-size: 0.875rem; + line-height: 1.6; + color: #56657a; + margin: 0 0 24px; +} + +.cfg-modal-actions { + display: flex; + justify-content: flex-end; + gap: 12px; +} + +.cfg-btn-danger { + background: #c62828; + border: none; + color: #fff; + border-radius: 20px; + padding: 10px 22px; + font-size: 0.875rem; + font-weight: 600; + cursor: pointer; + transition: opacity 0.15s; +} + +.cfg-btn-danger:hover { opacity: 0.9; } +.cfg-btn-danger:disabled { opacity: 0.45; cursor: default; pointer-events: none; } + +/* ── Responsive additions ────────────────────────────────── */ + +@media (max-width: 680px) { + .cfg-form-grid { grid-template-columns: 1fr; } + .cfg-step-label { display: none; } + .cfg-stepper { gap: 0; } +} From 9348060fb357c10f1b1550333feb5367d036265e Mon Sep 17 00:00:00 2001 From: Lasantha Samarakoon Date: Fri, 19 Jun 2026 13:05:48 +0530 Subject: [PATCH 06/11] Revamp application listing page --- .../partials/applications-listing.hbs | 332 +++++++++----- .../src/styles/applications.css | 427 ++++++++++++++++++ 2 files changed, 652 insertions(+), 107 deletions(-) diff --git a/portals/developer-portal/src/pages/applications/partials/applications-listing.hbs b/portals/developer-portal/src/pages/applications/partials/applications-listing.hbs index dc1bacedb..3a6dbce31 100644 --- a/portals/developer-portal/src/pages/applications/partials/applications-listing.hbs +++ b/portals/developer-portal/src/pages/applications/partials/applications-listing.hbs @@ -1,127 +1,245 @@ {{#pageHead}} {{/pageHead}} -{{#pageScripts}} - - -{{/pageScripts}} -
-
-
- Applications +
+
- {{#if applicationsMetadata.length}} - -
- + +
+
+

Applications

+

Applications hold the API keys and subscriptions you use to call APIs.

+ {{#if applicationsMetadata.length}} + {{/if}}
-
+ + {{#unless applicationsMetadata.length}} +
+ +

No applications yet

+

Create an application to generate API keys and subscribe to APIs. You can manage all your credentials in one place.

+ +
+ {{/unless}} - -
-
- + - Create Application -
+ + {{#if applicationsMetadata.length}} +
+ {{#applicationsMetadata}} +
-
-
-
-
-
-
- Application icon -
-
- -
- -
-
- Application name cannot be empty. -
-
-
- -
-
- +
+ +
+

{{name}}

-
+

{{description}}

- - {{#applicationsMetadata}} - -
-
-
-
- Application icon -
-
-
- -
-
-
-

- {{description}} -

-
-
- - -
-
+ +
{{/applicationsMetadata}}
+ {{/if}} + +
+
+ + +
\ No newline at end of file +
+ + + + + diff --git a/portals/developer-portal/src/styles/applications.css b/portals/developer-portal/src/styles/applications.css index 08bbc07b6..15a31638c 100644 --- a/portals/developer-portal/src/styles/applications.css +++ b/portals/developer-portal/src/styles/applications.css @@ -389,3 +389,430 @@ text-align: right; } +/* ═══════════════════════════════════════════════════════════ + Applications redesign — new layout styles + ══════════════════════════════════════════════════════════ */ + +:root { + --wso2-gradient: linear-gradient(135deg, #ef4223 0%, #ff8636 100%); +} + +/* ── Page container ───────────────────────────────────────── */ + +.apps-section { + padding: 0; +} + +.apps-page-container { + padding: 28px 36px 40px; +} + +/* ── Page header ──────────────────────────────────────────── */ + +.apps-page-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 16px; + margin-bottom: 26px; +} + +.apps-page-title { + margin: 0; + font-size: 1.5rem; + font-weight: 700; + color: #1a2433; + line-height: 1; +} + +.apps-page-desc { + margin: 9px 0 0; + font-size: 0.875rem; + line-height: 1.5; + color: #637282; +} + +/* ── Create button ────────────────────────────────────────── */ + +.apps-create-btn { + flex: none; + display: inline-flex; + align-items: center; + gap: 8px; + background: var(--wso2-gradient); + color: #fff; + border: none; + border-radius: 20px; + padding: 11px 22px; + font-size: 0.875rem; + font-weight: 600; + cursor: pointer; + transition: opacity 0.15s; + white-space: nowrap; +} + +.apps-create-btn:hover { opacity: 0.9; } +.apps-create-btn:disabled { opacity: 0.5; cursor: default; pointer-events: none; } + +/* ── Empty state ──────────────────────────────────────────── */ + +.apps-empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + padding: 60px 0 80px; +} + +.apps-empty-icon { + width: 84px; + height: 84px; + border-radius: 22px; + background: #eef4fb; + color: #1f6feb; + display: flex; + align-items: center; + justify-content: center; + font-size: 2rem; +} + +.apps-empty-title { + margin: 24px 0 0; + font-size: 1.1875rem; + font-weight: 700; + color: #1a2433; +} + +.apps-empty-desc { + margin: 10px 0 0; + max-width: 420px; + font-size: 0.875rem; + line-height: 1.6; + color: #637282; +} + +.apps-empty-state .apps-create-btn { + margin-top: 24px; + padding: 12px 26px; +} + +/* ── Card grid ────────────────────────────────────────────── */ + +.apps-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20px; +} + +/* ── Application card ─────────────────────────────────────── */ + +.app-card { + display: flex; + flex-direction: column; + border: 1px solid #e6eaf0; + border-radius: 14px; + padding: 22px; + background: var(--main-bg-color, #fff); + transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease; +} + +.app-card:hover { + transform: translateY(-3px); + box-shadow: 0 12px 28px rgba(20, 40, 70, 0.10); + border-color: #cdd9e8; +} + +.app-card-top { + display: flex; + align-items: center; + gap: 13px; +} + +.app-avatar { + width: 48px; + height: 48px; + flex: none; + border-radius: 12px; + display: flex; + align-items: center; + justify-content: center; + font-size: 1rem; + font-weight: 700; + text-transform: uppercase; + line-height: 1; +} + +.app-card-meta { + flex: 1; + min-width: 0; +} + +.app-card-name { + margin: 0; + font-size: 1rem; + font-weight: 600; + color: #1a2433; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.app-card-desc { + flex: 1; + margin: 14px 0 0; + font-size: 0.8125rem; + line-height: 1.55; + color: #637282; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.app-card-footer { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: 18px; + padding-top: 14px; + border-top: 1px solid #eef1f5; +} + +.app-subs-label { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 0.781rem; + font-weight: 500; + color: #637282; +} + +.app-delete-btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 6px; + border: none; + background: none; + border-radius: 7px; + color: #b9c2cd; + cursor: pointer; + transition: background 0.15s, color 0.15s; + font-size: 1rem; + line-height: 1; +} + +.app-delete-btn:hover { + background: #fdeaea; + color: #c62828; +} + +/* ── Modals ───────────────────────────────────────────────── */ + +.app-modal-overlay { + position: fixed; + inset: 0; + background: rgba(20, 40, 70, 0.34); + backdrop-filter: blur(6px); + -webkit-backdrop-filter: blur(6px); + align-items: center; + justify-content: center; + z-index: 1050; + animation: app-fade-in 0.18s ease; +} + +@keyframes app-fade-in { + from { opacity: 0; } + to { opacity: 1; } +} + +.app-modal { + width: 480px; + max-width: calc(100vw - 32px); + background: #fff; + border-radius: 16px; + padding: 28px 30px 24px; + box-shadow: 0 24px 60px rgba(10, 25, 50, 0.34); + animation: app-modal-pop 0.28s ease; +} + +.app-modal--sm { + width: 420px; +} + +@keyframes app-modal-pop { + from { opacity: 0; transform: translateY(10px) scale(0.985); } + to { opacity: 1; transform: none; } +} + +.app-modal-head { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 22px; +} + +.app-modal-head-left { + display: flex; + align-items: center; + gap: 13px; +} + +.app-modal-icon { + width: 44px; + height: 44px; + flex: none; + border-radius: 11px; + background: #eef4fb; + color: #1f6feb; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.25rem; +} + +.app-modal-icon--danger { + background: #fdeaea; + color: #c62828; +} + +.app-modal-title { + margin: 0; + font-size: 1.125rem; + font-weight: 700; + color: #1a2433; +} + +.app-modal-close { + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + border: none; + background: none; + border-radius: 7px; + color: #8a93a0; + cursor: pointer; + font-size: 0.875rem; + transition: background 0.12s, color 0.12s; +} + +.app-modal-close:hover { background: #eef1f5; color: #1a2433; } + +.app-modal-body { + display: flex; + flex-direction: column; + gap: 18px; +} + +.app-modal-body-text { + margin: 0 0 24px; + font-size: 0.875rem; + line-height: 1.6; + color: #56657a; +} + +.app-modal-footer { + display: flex; + justify-content: flex-end; + gap: 12px; + margin-top: 24px; +} + +/* ── Form elements ────────────────────────────────────────── */ + +.app-form-group label { + display: block; + font-size: 0.8125rem; + font-weight: 600; + color: #1a2433; + margin-bottom: 8px; +} + +.app-required { color: #c62828; } + +.app-form-input { + width: 100%; + border: 1px solid #d0d7de; + border-radius: 8px; + padding: 11px 13px; + font-size: 0.875rem; + font-family: inherit; + color: #1a2433; + background: #fff; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.app-form-input:focus { + border-color: #1f6feb; + box-shadow: 0 0 0 3px rgba(31, 111, 235, 0.12); +} + +/* ── Modal buttons ────────────────────────────────────────── */ + +.app-btn-primary { + display: inline-flex; + align-items: center; + gap: 8px; + background: var(--wso2-gradient); + color: #fff; + border: none; + border-radius: 20px; + padding: 10px 22px; + font-size: 0.875rem; + font-weight: 600; + cursor: pointer; + transition: opacity 0.15s; +} + +.app-btn-primary:hover { opacity: 0.9; } +.app-btn-primary:disabled { opacity: 0.5; cursor: default; pointer-events: none; } + +.app-btn-secondary { + display: inline-flex; + align-items: center; + background: #fff; + border: 1px solid #cdd8e6; + color: #1f3d5c; + border-radius: 20px; + padding: 10px 20px; + font-size: 0.875rem; + font-weight: 600; + cursor: pointer; + transition: background 0.15s; +} + +.app-btn-secondary:hover { background: #f3f7fc; } + +.app-btn-danger { + display: inline-flex; + align-items: center; + background: #c62828; + border: none; + color: #fff; + border-radius: 20px; + padding: 10px 22px; + font-size: 0.875rem; + font-weight: 600; + cursor: pointer; + transition: opacity 0.15s; +} + +.app-btn-danger:hover { opacity: 0.9; } +.app-btn-danger:disabled { opacity: 0.5; cursor: default; pointer-events: none; } + +/* ── Responsive ───────────────────────────────────────────── */ + +@media (max-width: 1100px) { + .apps-grid { grid-template-columns: repeat(2, 1fr); } +} + +@media (max-width: 700px) { + .apps-grid { grid-template-columns: 1fr; } + .apps-page-container { padding: 20px 16px 32px; } + .apps-page-header { flex-direction: column; align-items: flex-start; } +} + From f38c5022602a67bc149ed4b310bafb11dd15e64f Mon Sep 17 00:00:00 2001 From: Lasantha Samarakoon Date: Sat, 20 Jun 2026 01:05:29 +0530 Subject: [PATCH 07/11] Revamp application listing page --- .../src/controllers/apiContentController.js | 4 + .../defaultContent/images/devportal-logo.png | Bin 16727 -> 12473 bytes .../defaultContent/images/devportal-logo.svg | 5 + .../src/defaultContent/images/favicon.ico | Bin 0 -> 112311 bytes .../src/defaultContent/layout/main.hbs | 2 +- .../defaultContent/pages/api-landing/page.hbs | 79 ++-- .../api-landing/partials/api-default.hbs | 251 +++++------ .../partials/api-detail-banner.hbs | 138 +++--- .../partials/api-subscription-plans.hbs | 379 ++++++++++------ .../src/defaultContent/pages/docs/page.hbs | 131 +++--- .../pages/docs/partials/api-doc.hbs | 16 +- .../home/partials/onboarding-overlay.hbs | 14 +- .../src/defaultContent/partials/header.hbs | 2 +- .../src/defaultContent/styles/api-content.css | 426 ++++++++++++++++++ .../src/defaultContent/styles/doc.css | 294 +++++++----- .../developer-portal/src/utils/constants.js | 9 +- 16 files changed, 1189 insertions(+), 561 deletions(-) create mode 100644 portals/developer-portal/src/defaultContent/images/devportal-logo.svg create mode 100644 portals/developer-portal/src/defaultContent/images/favicon.ico diff --git a/portals/developer-portal/src/controllers/apiContentController.js b/portals/developer-portal/src/controllers/apiContentController.js index d514d3435..b058be86e 100644 --- a/portals/developer-portal/src/controllers/apiContentController.js +++ b/portals/developer-portal/src/controllers/apiContentController.js @@ -624,6 +624,8 @@ const loadDocument = async (req, res) => { templateContent.baseUrl = config.baseUrl + constants.ROUTE.VIEWS_PATH + viewName; templateContent.baseDocUrl = config.baseUrl + constants.ROUTE.VIEWS_PATH + viewName + '/api/' + apiHandle; templateContent.docTypes = metaData.docTypes; + templateContent.currentDocName = docName || null; + templateContent.currentDocType = docType || null; const metaForNav = { apiInfo: { gatewayType: metaData.apiInfo?.gatewayType }, apiReferenceID: metaData.apiReferenceID }; templateContent.showApiKeysNav = apiUsesApiKeySecurity(metaForNav); const html = renderTemplate(layoutPath + 'pages/docs/page.hbs', layoutPath + 'layout/main.hbs', templateContent, false); @@ -752,6 +754,8 @@ const loadDocument = async (req, res) => { templateContent.baseUrl = '/' + orgName + constants.ROUTE.VIEWS_PATH + viewName; templateContent.baseDocUrl = baseDocUrl; templateContent.docTypes = docNames; + templateContent.currentDocName = docName || null; + templateContent.currentDocType = docType || null; let profile = null; if (req.user) { profile = { diff --git a/portals/developer-portal/src/defaultContent/images/devportal-logo.png b/portals/developer-portal/src/defaultContent/images/devportal-logo.png index ae6ac6b1c2fa8088cf557e27146f05f7bf788ed7..6b7bda2f92efd8e068e4c8dfc44cfbf7541c4f5a 100644 GIT binary patch literal 12473 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 Tv}^s1uxxb+e6jRjuY3Ok0HZr9 literal 16727 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 + + + + diff --git a/portals/developer-portal/src/defaultContent/images/favicon.ico b/portals/developer-portal/src/defaultContent/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..fafb3e61cc937a41dea3b4a3cae1a74a5e2ad7e0 GIT binary patch literal 112311 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 DevPortal - + diff --git a/portals/developer-portal/src/defaultContent/pages/api-landing/page.hbs b/portals/developer-portal/src/defaultContent/pages/api-landing/page.hbs index 402dda0cb..4d551793a 100644 --- a/portals/developer-portal/src/defaultContent/pages/api-landing/page.hbs +++ b/portals/developer-portal/src/defaultContent/pages/api-landing/page.hbs @@ -28,52 +28,63 @@ {{/pageScripts}} + {{> api-detail-banner }} + +
+
{{#if loadDefault}} {{> api-default}} {{else}} {{> api-content }} {{/if}} +
+ {{#if subscriptionPlans.length}} +
{{> api-subscription-plans}} - {{> create-app }} - {{> warning modalTitle="Confirm" modalMessage="" modalFunction="" }} - {{> alert }} +
+ {{/if}} +
- {{!-- ── AGENT PROMPT MODAL ── --}} - {{#if showApiWorkflowsNav}} - {{#unless (eq apiMetadata.apiInfo.agentVisibility "HIDDEN")}} -