From 77f22af5ed2eace570b47ea2bd7a7540b01b5c5f Mon Sep 17 00:00:00 2001 From: Justin Fagnani Date: Tue, 17 Jan 2023 17:13:01 -0800 Subject: [PATCH 1/3] Move route modules out of subfolders --- packages/site-server/src/lib/catalog/router.ts | 9 +++------ .../lib/catalog/routes/{catalog => }/catalog-route.ts | 0 .../lib/catalog/routes/{element => }/element-route.ts | 2 +- .../src/lib/catalog/routes/{catalog => }/search-route.ts | 2 +- 4 files changed, 5 insertions(+), 8 deletions(-) rename packages/site-server/src/lib/catalog/routes/{catalog => }/catalog-route.ts (100%) rename packages/site-server/src/lib/catalog/routes/{element => }/element-route.ts (99%) rename packages/site-server/src/lib/catalog/routes/{catalog => }/search-route.ts (96%) diff --git a/packages/site-server/src/lib/catalog/router.ts b/packages/site-server/src/lib/catalog/router.ts index c2d76cc1..f330eda1 100644 --- a/packages/site-server/src/lib/catalog/router.ts +++ b/packages/site-server/src/lib/catalog/router.ts @@ -5,15 +5,12 @@ */ import Router from '@koa/router'; -import {handleCatalogRoute} from './routes/catalog/catalog-route.js'; -import {handleCatalogSearchRoute} from './routes/catalog/search-route.js'; -import {handleElementRoute} from './routes/element/element-route.js'; -// import cors from '@koa/cors'; +import {handleCatalogRoute} from './routes/catalog-route.js'; +import {handleCatalogSearchRoute} from './routes/search-route.js'; +import {handleElementRoute} from './routes/element-route.js'; export const catalogRouter = new Router(); -// catalogRouter.use(cors()); - catalogRouter.get('/', handleCatalogRoute); catalogRouter.get('/search', handleCatalogSearchRoute); diff --git a/packages/site-server/src/lib/catalog/routes/catalog/catalog-route.ts b/packages/site-server/src/lib/catalog/routes/catalog-route.ts similarity index 100% rename from packages/site-server/src/lib/catalog/routes/catalog/catalog-route.ts rename to packages/site-server/src/lib/catalog/routes/catalog-route.ts diff --git a/packages/site-server/src/lib/catalog/routes/element/element-route.ts b/packages/site-server/src/lib/catalog/routes/element-route.ts similarity index 99% rename from packages/site-server/src/lib/catalog/routes/element/element-route.ts rename to packages/site-server/src/lib/catalog/routes/element-route.ts index d0de2082..7cfb984f 100644 --- a/packages/site-server/src/lib/catalog/routes/element/element-route.ts +++ b/packages/site-server/src/lib/catalog/routes/element-route.ts @@ -14,7 +14,7 @@ import Router from '@koa/router'; import {marked} from 'marked'; import {renderElementPage} from '@webcomponents/internal-site-client/lib/pages/element/shell.js'; -import {client} from '../../graphql.js'; +import {client} from '../graphql.js'; import type {ElementData} from '@webcomponents/internal-site-client/lib/pages/element/wco-element-page.js'; diff --git a/packages/site-server/src/lib/catalog/routes/catalog/search-route.ts b/packages/site-server/src/lib/catalog/routes/search-route.ts similarity index 96% rename from packages/site-server/src/lib/catalog/routes/catalog/search-route.ts rename to packages/site-server/src/lib/catalog/routes/search-route.ts index 3dcc817b..ba6e4469 100644 --- a/packages/site-server/src/lib/catalog/routes/catalog/search-route.ts +++ b/packages/site-server/src/lib/catalog/routes/search-route.ts @@ -6,7 +6,7 @@ import {DefaultContext, DefaultState, ParameterizedContext} from 'koa'; import Router from '@koa/router'; -import {client} from '../../graphql.js'; +import {client} from '../graphql.js'; import {gql} from '@apollo/client/core/index.js'; const elementsQuery = gql` From 491203330b7ab7d3459422e3ef429977cdab5995 Mon Sep 17 00:00:00 2001 From: Justin Fagnani Date: Tue, 17 Jan 2023 17:24:36 -0800 Subject: [PATCH 2/3] Rename route modules to be more specific --- .../src/lib/catalog/routes/{catalog-route.ts => catalog-page.ts} | 0 .../src/lib/catalog/routes/{element-route.ts => element-page.ts} | 0 .../src/lib/catalog/routes/{search-route.ts => search-api.ts} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename packages/site-server/src/lib/catalog/routes/{catalog-route.ts => catalog-page.ts} (100%) rename packages/site-server/src/lib/catalog/routes/{element-route.ts => element-page.ts} (100%) rename packages/site-server/src/lib/catalog/routes/{search-route.ts => search-api.ts} (100%) diff --git a/packages/site-server/src/lib/catalog/routes/catalog-route.ts b/packages/site-server/src/lib/catalog/routes/catalog-page.ts similarity index 100% rename from packages/site-server/src/lib/catalog/routes/catalog-route.ts rename to packages/site-server/src/lib/catalog/routes/catalog-page.ts diff --git a/packages/site-server/src/lib/catalog/routes/element-route.ts b/packages/site-server/src/lib/catalog/routes/element-page.ts similarity index 100% rename from packages/site-server/src/lib/catalog/routes/element-route.ts rename to packages/site-server/src/lib/catalog/routes/element-page.ts diff --git a/packages/site-server/src/lib/catalog/routes/search-route.ts b/packages/site-server/src/lib/catalog/routes/search-api.ts similarity index 100% rename from packages/site-server/src/lib/catalog/routes/search-route.ts rename to packages/site-server/src/lib/catalog/routes/search-api.ts From 87974a6151dc3976c9b299a6a4bb86d206b556e8 Mon Sep 17 00:00:00 2001 From: Justin Fagnani Date: Tue, 17 Jan 2023 19:01:42 -0800 Subject: [PATCH 3/3] Add rudimentary catalog import page --- package-lock.json | 31 ++++++- packages/site-client/package.json | 1 + packages/site-client/src/pages/import/boot.ts | 8 ++ .../pages/import/wco-catalog-import-page.ts | 59 +++++++++++++ packages/site-server/package.json | 2 + .../site-server/src/lib/catalog/router.ts | 15 +++- .../src/lib/catalog/routes/import-api.ts | 84 +++++++++++++++++++ .../src/lib/catalog/routes/import-page.ts | 36 ++++++++ 8 files changed, 231 insertions(+), 5 deletions(-) create mode 100644 packages/site-client/src/pages/import/boot.ts create mode 100644 packages/site-client/src/pages/import/wco-catalog-import-page.ts create mode 100644 packages/site-server/src/lib/catalog/routes/import-api.ts create mode 100644 packages/site-server/src/lib/catalog/routes/import-page.ts diff --git a/package-lock.json b/package-lock.json index 4f63cf38..87bdf627 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3764,6 +3764,14 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/@lit-labs/task": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@lit-labs/task/-/task-2.0.0.tgz", + "integrity": "sha512-r567PcR6Koq7DoBwdnMWxyO3Ww9BkJshGmuviwhCcNRATSgDx/O6SEZ95oBfgxN6hKyoYT3lbtRzMPKhKRHUow==", + "dependencies": { + "@lit/reactive-element": "^1.1.0" + } + }, "node_modules/@lit/reactive-element": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.0.tgz", @@ -23805,6 +23813,7 @@ "version": "0.0.0", "license": "Apache-2.0", "dependencies": { + "@lit-labs/task": "^2.0.0", "@webcomponents/catalog-api": "^0.0.0", "lit": "^2.6.0", "lit-analyzer": "^1.2.1" @@ -23818,7 +23827,8 @@ "@11ty/eleventy": "^1.0.2", "@11ty/eleventy-navigation": "^0.3.5", "@webcomponents/internal-site-client": "^0.0.0", - "@webcomponents/internal-site-server": "^0.0.0" + "@webcomponents/internal-site-server": "^0.0.0", + "@webcomponents/internal-site-templates": "^0.0.0" } }, "packages/site-server": { @@ -23839,18 +23849,22 @@ "@types/marked": "^4.0.8", "@web/dev-server": "^0.1.34", "@webcomponents/internal-site-content": "^0.0.0", + "@webcomponents/internal-site-templates": "^0.0.0", "google-auth-library": "^8.7.0", "koa": "^2.13.4", + "koa-bodyparser": "^4.3.0", "koa-conditional-get": "^3.0.0", "koa-etag": "^4.0.0", "koa-static": "^5.0.0", "marked": "^4.2.5" }, "devDependencies": { + "@types/koa-bodyparser": "^4.3.10", "uvu": "^0.5.6" } }, "packages/site-templates": { + "name": "@webcomponents/internal-site-templates", "version": "0.0.0", "license": "Apache-2.0" } @@ -26774,6 +26788,14 @@ "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.0.0.tgz", "integrity": "sha512-ic93MBXfApIFTrup4a70M/+ddD8xdt2zxxj9sRwHQzhS9ag/syqkD8JPdTXsc1gUy2K8TTirhlCqyTEM/sifNw==" }, + "@lit-labs/task": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@lit-labs/task/-/task-2.0.0.tgz", + "integrity": "sha512-r567PcR6Koq7DoBwdnMWxyO3Ww9BkJshGmuviwhCcNRATSgDx/O6SEZ95oBfgxN6hKyoYT3lbtRzMPKhKRHUow==", + "requires": { + "@lit/reactive-element": "^1.1.0" + } + }, "@lit/reactive-element": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.0.tgz", @@ -27648,6 +27670,7 @@ "@webcomponents/internal-site-client": { "version": "file:packages/site-client", "requires": { + "@lit-labs/task": "^2.0.0", "@webcomponents/catalog-api": "^0.0.0", "lit": "^2.6.0", "lit-analyzer": "^1.2.1" @@ -27659,7 +27682,8 @@ "@11ty/eleventy": "^1.0.2", "@11ty/eleventy-navigation": "^0.3.5", "@webcomponents/internal-site-client": "^0.0.0", - "@webcomponents/internal-site-server": "^0.0.0" + "@webcomponents/internal-site-server": "^0.0.0", + "@webcomponents/internal-site-templates": "^0.0.0" } }, "@webcomponents/internal-site-server": { @@ -27672,14 +27696,17 @@ "@types/koa": "^2.13.5", "@types/koa__cors": "^3.3.0", "@types/koa__router": "^12.0.0", + "@types/koa-bodyparser": "*", "@types/koa-conditional-get": "^2.0.0", "@types/koa-etag": "^3.0.0", "@types/koa-static": "^4.0.2", "@types/marked": "^4.0.8", "@web/dev-server": "^0.1.34", "@webcomponents/internal-site-content": "^0.0.0", + "@webcomponents/internal-site-templates": "^0.0.0", "google-auth-library": "^8.7.0", "koa": "^2.13.4", + "koa-bodyparser": "^4.3.0", "koa-conditional-get": "^3.0.0", "koa-etag": "^4.0.0", "koa-static": "^5.0.0", diff --git a/packages/site-client/package.json b/packages/site-client/package.json index 014cf002..f9df9217 100644 --- a/packages/site-client/package.json +++ b/packages/site-client/package.json @@ -86,6 +86,7 @@ } }, "dependencies": { + "@lit-labs/task": "^2.0.0", "@webcomponents/catalog-api": "^0.0.0", "lit": "^2.6.0", "lit-analyzer": "^1.2.1" diff --git a/packages/site-client/src/pages/import/boot.ts b/packages/site-client/src/pages/import/boot.ts new file mode 100644 index 00000000..bc20e8c2 --- /dev/null +++ b/packages/site-client/src/pages/import/boot.ts @@ -0,0 +1,8 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import 'lit/experimental-hydrate-support.js'; +import './wco-catalog-import-page.js'; diff --git a/packages/site-client/src/pages/import/wco-catalog-import-page.ts b/packages/site-client/src/pages/import/wco-catalog-import-page.ts new file mode 100644 index 00000000..86021b79 --- /dev/null +++ b/packages/site-client/src/pages/import/wco-catalog-import-page.ts @@ -0,0 +1,59 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {html} from 'lit'; +import {customElement, state} from 'lit/decorators.js'; +import {WCOPage} from '../../shared/wco-page.js'; +import {Task} from '@lit-labs/task'; + +@customElement('wco-catalog-import-page') +export class WCOCatalogImportPage extends WCOPage { + private _importTask = new Task(this, { + task: async ([packageName]: [packageName: string | undefined]) => { + console.log('_importTask', packageName); + + if (packageName !== undefined && packageName.trim().length > 0) { + const response = await fetch(`/catalog/import`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + packageName, + }), + }); + const result = await response.json(); + return result; + } + }, + args: () => [this._packageName] as [string], + }); + + @state() + private _packageName?: string; + + renderContent() { + return html` +

Import a Package

+ + ${this._importTask.render({ + complete: (value) => html`

Imported

+
${JSON.stringify(value, undefined, 2)}
`, + pending: () => html`

Importing package...

`, + })} + `; + } + + private _onPackageNameChange(e: Event) { + this._packageName = (e.target as HTMLInputElement).value; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'wco-catalog-import-page': WCOCatalogImportPage; + } +} diff --git a/packages/site-server/package.json b/packages/site-server/package.json index f8bda43c..786eb196 100644 --- a/packages/site-server/package.json +++ b/packages/site-server/package.json @@ -120,12 +120,14 @@ "@webcomponents/internal-site-templates": "^0.0.0", "google-auth-library": "^8.7.0", "koa": "^2.13.4", + "koa-bodyparser": "^4.3.0", "koa-conditional-get": "^3.0.0", "koa-etag": "^4.0.0", "koa-static": "^5.0.0", "marked": "^4.2.5" }, "devDependencies": { + "@types/koa-bodyparser": "^4.3.10", "uvu": "^0.5.6" } } diff --git a/packages/site-server/src/lib/catalog/router.ts b/packages/site-server/src/lib/catalog/router.ts index f330eda1..3958fff1 100644 --- a/packages/site-server/src/lib/catalog/router.ts +++ b/packages/site-server/src/lib/catalog/router.ts @@ -5,14 +5,23 @@ */ import Router from '@koa/router'; -import {handleCatalogRoute} from './routes/catalog-route.js'; -import {handleCatalogSearchRoute} from './routes/search-route.js'; -import {handleElementRoute} from './routes/element-route.js'; +import {handleCatalogRoute} from './routes/catalog-page.js'; +import {handleCatalogImportRoute} from './routes/import-page.js'; +import {handleCatalogImportApiRoute} from './routes/import-api.js'; +import {handleElementRoute} from './routes/element-page.js'; +import {handleCatalogSearchRoute} from './routes/search-api.js'; +import bodyParser from 'koa-bodyparser'; export const catalogRouter = new Router(); +// Needed for /import +catalogRouter.use(bodyParser()); + catalogRouter.get('/', handleCatalogRoute); catalogRouter.get('/search', handleCatalogSearchRoute); +catalogRouter.get('/import', handleCatalogImportRoute); +catalogRouter.post('/import', handleCatalogImportApiRoute); + catalogRouter.get('/element/:path+', handleElementRoute); diff --git a/packages/site-server/src/lib/catalog/routes/import-api.ts b/packages/site-server/src/lib/catalog/routes/import-api.ts new file mode 100644 index 00000000..2f7cedb9 --- /dev/null +++ b/packages/site-server/src/lib/catalog/routes/import-api.ts @@ -0,0 +1,84 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {DefaultContext, DefaultState, ParameterizedContext} from 'koa'; +import Router from '@koa/router'; +import {client} from '../graphql.js'; +import {gql} from '@apollo/client/core/index.js'; + +const importMutation = gql` + mutation ImportPackage($packageName: String!) { + importPackage(packageName: $packageName) { + ... on ReadablePackageInfo { + version { + ... on ReadablePackageVersion { + version + problems { + code + severity + message + filePath + } + customElements { + tagName + declaration + className + jsExport + } + } + ... on UnreadablePackageVersion { + version + status + problems { + code + severity + message + filePath + } + } + } + } + } + } +`; + +export const handleCatalogImportApiRoute = async ( + context: ParameterizedContext< + DefaultState, + DefaultContext & Router.RouterParamContext, + unknown + > +) => { + console.log('context.request.body', context.request.body); + const packageName = (context.request.body as Record)[ + 'packageName' + ]; + context.type = 'json'; + + if (typeof packageName !== 'string') { + context.status = 400; + context.body = { + message: 'Body parmeter `packageName` must be a string', + }; + return; + } + + const result = await client.mutate({ + mutation: importMutation, + variables: {packageName}, + }); + + if (result.errors) { + context.status = 500; + context.body = { + message: result.errors, + }; + return; + } + + context.status = 200; + context.body = result.data; +}; diff --git a/packages/site-server/src/lib/catalog/routes/import-page.ts b/packages/site-server/src/lib/catalog/routes/import-page.ts new file mode 100644 index 00000000..a8f7935a --- /dev/null +++ b/packages/site-server/src/lib/catalog/routes/import-page.ts @@ -0,0 +1,36 @@ +/** + * @license + * Copyright 2022 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// This must be imported before lit +import {renderPage} from '@webcomponents/internal-site-templates/lib/base.js'; +import {DefaultContext, DefaultState, ParameterizedContext} from 'koa'; +import {html} from 'lit'; +import {Readable} from 'stream'; +import Router from '@koa/router'; + +import '@webcomponents/internal-site-client/lib/pages/import/wco-catalog-import-page.js'; + +export const handleCatalogImportRoute = async ( + context: ParameterizedContext< + DefaultState, + DefaultContext & Router.RouterParamContext, + unknown + > +) => { + // Set location because wco-nav-bar reads pathname from it. URL isn't + // exactly a Location, but it's close enough for read-only uses + globalThis.location = new URL(context.URL.href) as unknown as Location; + + context.body = Readable.from( + renderPage({ + title: `Web Components Catalog - Import Package`, + initScript: '/js/import/boot.js', + content: html``, + }) + ); + context.type = 'html'; + context.status = 200; +};