diff --git a/.github/workflows/test-on-pr-branch.yml b/.github/workflows/test-on-pr-branch.yml index 9690d99..ea91d4d 100644 --- a/.github/workflows/test-on-pr-branch.yml +++ b/.github/workflows/test-on-pr-branch.yml @@ -11,13 +11,18 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: '16' + node-version: "16" - name: Install dependencies - run: npm ci + run: | + npm i @nx/nx-linux-x64-gnu + npm ci - name: Install playwright browsers run: npx playwright install --with-deps - - name: Run tests - run: npm run-script test + - name: Build project + run: npm run build + + - name: Run tests for compas-docops + run: npx lerna run test diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d1e44a9..deb24a3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,16 +11,22 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: '16' + node-version: "16" - name: Install dependencies - run: npm ci + run: | + npm i @nx/nx-linux-x64-gnu + npm ci - name: Install playwright browsers run: npx playwright install --with-deps - - name: Run unit tests - run: npm run-script test:unit + - name: Build project + run: npm run build + + - name: Run unit tests for compas-docops + run: npx lerna run test:unit + visual: runs-on: ubuntu-latest steps: @@ -30,24 +36,31 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: '16' + node-version: "16" - name: Install dependencies - run: npm ci + run: | + npm i @nx/nx-linux-x64-gnu + npm ci - name: Install playwright browsers run: npx playwright install --with-deps - - name: Run visual test + - name: Build project + run: npm run build + + - name: Run visual test for compas-open + working-directory: ./components/compas-open run: npm run-script test:visual - - name: Update screenshots + - name: Update screenshots for compas-open if: failure() + working-directory: ./components/compas-open run: npm run test:update - name: Commit changes if: failure() uses: EndBug/add-and-commit@v9 with: - message: 'ci: update screenshots' - add: 'screenshots' + message: "ci: update screenshots" + add: "components/compas-open/screenshots" diff --git a/.gitignore b/.gitignore index 307fd05..9a77a7d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,28 +1,3 @@ -## editors -/.idea -/.vscode - -## system files -.DS_Store - -## npm -/node_modules/ -/npm-debug.log - -## testing -/coverage/ - -## failed screenshots -/screenshots/*/failed/ - -## temp folders -/.tmp/ - -# build -/_site/ -/dist/ -/out-tsc/ -/.rollup.cache/ - -storybook-static -custom-elements.json +node_modules/ +**/.tsbuildinfo +lerna-debug.log \ No newline at end of file diff --git a/README.foot.md b/README.foot.md deleted file mode 100644 index f0d030b..0000000 --- a/README.foot.md +++ /dev/null @@ -1,2 +0,0 @@ - -© 1970 THE AUTHORS diff --git a/README.md b/README.md index 76185ad..e69de29 100644 --- a/README.md +++ b/README.md @@ -1,81 +0,0 @@ -# \ - -This webcomponent follows the [open-wc](https://github.com/open-wc/open-wc) recommendation. - -## Installation - -```bash -npm i compas-open -``` - -## Usage - -```html - - - -``` - -## Linting and formatting - -To scan the project for linting and formatting errors, run - -```bash -npm run lint -``` - -To automatically fix linting and formatting errors, run - -```bash -npm run format -``` - -## Testing with Web Test Runner - -To execute a single test run: - -```bash -npm run test -``` - -To run the tests in interactive watch mode run: - -```bash -npm run test:watch -``` - -## Demoing with Storybook - -To run a local instance of Storybook for your component, run - -```bash -npm run storybook -``` - -To build a production version of Storybook, run - -```bash -npm run storybook:build -``` - -## Tooling configs - -For most of the tools, the configuration is in the `package.json` to reduce the amount of files in your project. - -If you customize the configuration a lot, you can consider moving them to individual files. - -## Local Demo with `web-dev-server` - -```bash -npm start -``` - -To run a local development server that serves the basic demo located in `demo/index.html` - - - - - -© 1970 THE AUTHORS diff --git a/.editorconfig b/components/compas-docops-components/.editorconfig similarity index 100% rename from .editorconfig rename to components/compas-docops-components/.editorconfig diff --git a/.eslintrc b/components/compas-docops-components/.eslintrc similarity index 100% rename from .eslintrc rename to components/compas-docops-components/.eslintrc diff --git a/components/compas-docops-components/.gitignore b/components/compas-docops-components/.gitignore new file mode 100644 index 0000000..921d3f6 --- /dev/null +++ b/components/compas-docops-components/.gitignore @@ -0,0 +1,33 @@ +## editors +/.idea +/.vscode + +## system files +.DS_Store + +## npm +/node_modules/ +/npm-debug.log + +## failed screenshots +/screenshots/*/failed/ + +## testing +/coverage/ + +## local debug +/.npmrc + +## temp folders +/.tmp/ + +# build +/_site/ +/dist/ +/out-tsc/ +/.tsbuildinfo + +storybook-static +custom-elements.json + +.rollup.cache/ diff --git a/components/compas-docops-components/.npmignore b/components/compas-docops-components/.npmignore new file mode 100644 index 0000000..a147ebe --- /dev/null +++ b/components/compas-docops-components/.npmignore @@ -0,0 +1,29 @@ +## editors +/.idea +/.vscode + +## system files +.DS_Store + +## npm +/node_modules/ +/npm-debug.log + +## failed screenshots +/screenshots/*/failed/ + +## testing +/coverage/ + +## local debug +/.npmrc + +## temp folders +/.tmp/ + +# build +/_site/ +/out-tsc/ + +storybook-static +custom-elements.json diff --git a/LICENSE b/components/compas-docops-components/LICENSE similarity index 100% rename from LICENSE rename to components/compas-docops-components/LICENSE diff --git a/components/compas-docops-components/package.json b/components/compas-docops-components/package.json new file mode 100644 index 0000000..37239f7 --- /dev/null +++ b/components/compas-docops-components/package.json @@ -0,0 +1,72 @@ +{ + "name": "@com-pas/compas-docops-components", + "description": "Compas-docops-components following open-wc recommendations", + "license": "Apache-2.0", + "author": "CoMPAS", + "version": "0.0.0", + "browser": "./dist/CompasDocopsComponent.js", + "module": "./dist/CompasDocopsComponent.js", + "types": "./dist/CompasDocopsComponent.d.ts", + "exports": { + ".": "./dist/CompasDocopsComponent.js", + "./compas-change-set-radiogroup.js": "./dist/compas-change-set-radiogroup.js", + "./compas-comment.js": "./dist/compas-comment.js", + "./compas-labels-field.js": "./dist/compas-labels-field.js", + "./compas-scltype-select.js": "./dist/compas-scltype-select.js" + }, + "type": "module", + "scripts": { + "analyze": "cem analyze", + "start": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"wds\"", + "build": "tsc && npm run analyze -- --exclude dist", + "prepublish": "tsc && npm run analyze -- --exclude dist", + "lint": "eslint --ext .ts,.html . --ignore-path .gitignore && prettier \"**/*.ts\" --check --ignore-path .gitignore", + "format": "eslint --ext .ts,.html . --fix --ignore-path .gitignore && prettier \"**/*.ts\" --write --ignore-path .gitignore", + "clean": "rimraf .tsbuildinfo custom-elements.json dist" + }, + "dependencies": { + "@material/mwc-list": "^0.27.0", + "@material/mwc-icon": "^0.27.0", + "@material/mwc-icon-button": "^0.27.0", + "@material/mwc-select": "^0.27.0", + "@com-pas/compas-open-core": "*", + "@openscd/oscd-textfield": "*", + "lit": "^2.7.4", + "lit-element": "2.5.1", + "lit-html": "1.4.1" + }, + "devDependencies": { + "@babel/preset-env": "^7.16.4", + "@custom-elements-manifest/analyzer": "^0.4.17", + "@open-wc/building-rollup": "^2.0.2", + "@open-wc/eslint-config": "^9.2.1", + "@open-wc/testing": "^3.1.6", + "@rollup/plugin-typescript": "^9.0.2", + "@rollup/plugin-babel": "^5.3.0", + "@rollup/plugin-node-resolve": "^13.0.6", + "@typescript-eslint/eslint-plugin": "^5.48.0", + "@typescript-eslint/parser": "^5.48.0", + "@web/dev-server": "^0.1.34", + "@web/dev-server-storybook": "^0.5.4", + "@web/rollup-plugin-html": "^1.11.0", + "@web/rollup-plugin-import-meta-assets": "^1.0.7", + "@web/test-runner": "^0.14.0", + "babel-plugin-template-html-minifier": "^4.1.0", + "cem-plugin-readme": "^0.1.4", + "concurrently": "^5.3.0", + "deepmerge": "^4.2.2", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.3.0", + "husky": "^4.3.8", + "lint-staged": "^10.5.4", + "prettier": "^2.4.1", + "sinon": "^11.1.2", + "rimraf": "^3.0.2", + "rollup": "^2.60.0", + "rollup-plugin-esbuild": "^5.0.0", + "rollup-plugin-workbox": "^6.2.0", + "tslib": "^2.3.1", + "typescript": "^4.9.2" + }, + "customElements": "custom-elements.json" +} diff --git a/components/compas-docops-components/src/CompasDocopsComponent.ts b/components/compas-docops-components/src/CompasDocopsComponent.ts new file mode 100644 index 0000000..e0015eb --- /dev/null +++ b/components/compas-docops-components/src/CompasDocopsComponent.ts @@ -0,0 +1,19 @@ +import { CompasChangeSetRadiogroup } from "./compas-change-set-radiogroup.js"; +import { CompasCommentElement } from "./compas-comment.js"; +import { CompasLabelsFieldElement } from "./compas-labels-field"; +import { CompasSclTypeSelect } from "./compas-scltype-select.js"; + +window.customElements.define("compas-comment", CompasCommentElement); +window.customElements.define( + "compas-changeset-radiogroup", + CompasChangeSetRadiogroup +); +window.customElements.define("compas-labels-field", CompasLabelsFieldElement); +window.customElements.define("compas-scltype-select", CompasSclTypeSelect); + +export { + CompasCommentElement, + CompasChangeSetRadiogroup, + CompasLabelsFieldElement, + CompasSclTypeSelect, +}; diff --git a/components/compas-docops-components/src/compas-change-set-radiogroup.ts b/components/compas-docops-components/src/compas-change-set-radiogroup.ts new file mode 100644 index 0000000..01197a2 --- /dev/null +++ b/components/compas-docops-components/src/compas-change-set-radiogroup.ts @@ -0,0 +1,47 @@ +import { html, LitElement, TemplateResult } from "lit-element"; +import { ListItemBase } from "@material/mwc-list/mwc-list-item-base"; + +import "@material/mwc-list"; +import "@material/mwc-list/mwc-radio-list-item"; + +import { ChangeSet } from "@com-pas/compas-open-core"; + +type ChangeSetDetail = { + translationKey: string; +}; +const changeSetDetails = new Map([ + [ChangeSet.MAJOR, { translationKey: "Major change" }], + [ChangeSet.MINOR, { translationKey: "Minor change" }], + [ChangeSet.PATCH, { translationKey: "Patch change" }], +]); + +export class CompasChangeSetRadiogroup extends LitElement { + private getSelectedListItem(): ListItemBase | null { + return this.shadowRoot!.querySelector("mwc-list")!.selected; + } + + getSelectedValue(): ChangeSet | null { + const changeSet = this.getSelectedListItem(); + if (changeSet) { + return changeSet.value; + } + return null; + } + + valid(): boolean { + return this.getSelectedListItem() !== null; + } + + render(): TemplateResult { + return html` + + ${Object.values(ChangeSet).map( + (key) => + html` + ${changeSetDetails.get(key)!.translationKey} + ` + )} + + `; + } +} diff --git a/components/compas-docops-components/src/compas-comment.ts b/components/compas-docops-components/src/compas-comment.ts new file mode 100644 index 0000000..d61afa5 --- /dev/null +++ b/components/compas-docops-components/src/compas-comment.ts @@ -0,0 +1,42 @@ +import { + css, + html, + customElement, + query, + LitElement, + TemplateResult, +} from "lit-element"; +import type { OscdTextfield } from "@openscd/oscd-textfield"; + +import "@openscd/oscd-textfield"; + +export class CompasCommentElement extends LitElement { + @query("oscd-textfield#comment") + private commentField!: OscdTextfield; + + set value(value: string | null) { + this.commentField.maybeValue = value; + } + + get value(): string | null { + return this.commentField.maybeValue; + } + + valid(): boolean { + return this.commentField?.checkValidity(); + } + + render(): TemplateResult { + return html` +

test

+ + + `; + } + + static styles = css` + oscd-textfield { + width: 100%; + } + `; +} diff --git a/components/compas-docops-components/src/compas-labels-field.ts b/components/compas-docops-components/src/compas-labels-field.ts new file mode 100644 index 0000000..945c431 --- /dev/null +++ b/components/compas-docops-components/src/compas-labels-field.ts @@ -0,0 +1,160 @@ +import { + css, + customElement, + html, + LitElement, + property, + query, + state, + TemplateResult, +} from "lit-element"; + +import "@material/mwc-list"; +import "@material/mwc-list/mwc-list-item"; +import "@material/mwc-icon"; +import "@material/mwc-icon-button"; + +import type { OscdTextfield } from "@openscd/oscd-textfield"; + +import "@openscd/oscd-textfield"; + +import { + COMPAS_LABELS_MAXIMUM, + COMPAS_NAMESPACE, + createLabel, + createLabels, + getLabels, +} from "@com-pas/compas-open-core"; + +export class CompasLabelsFieldElement extends LitElement { + @property({ type: Element }) + set privateElement(privateElement: Element) { + this.originalLabelsElement = getLabels(privateElement); + if (this.originalLabelsElement) { + this.newLabelsElement = ( + this.originalLabelsElement.cloneNode(true) + ); + } else { + this.newLabelsElement = createLabels(privateElement); + } + } + + @property({ type: Element }) + originalLabelsElement: Element | null = null; + + @property({ type: Element }) + newLabelsElement!: Element; + + @state() + private get labels(): Element[] { + return Array.from( + this.newLabelsElement?.querySelectorAll(`:scope > Label`) ?? [] + ) + .filter((element) => element.namespaceURI === COMPAS_NAMESPACE) + .sort((label1, label2) => + (label1.textContent ?? "").localeCompare(label2.textContent ?? "") + ); + } + + @query("oscd-textfield#newLabel") + private newLabelField!: OscdTextfield; + + private addLabel(): void { + if (this.newLabelField.checkValidity()) { + const value = this.newLabelField.value; + createLabel(this.newLabelsElement!, value); + + this.newLabelField.value = ""; + this.requestUpdate("labels"); + } + } + + private removeLabel(element: Element): void { + this.newLabelsElement!.removeChild(element); + + this.requestUpdate("labels"); + } + + public updateLabelsInPrivateElement(privateElement: Element): void { + // We will just add or replace the complete Labels Element, so if it exists + // first remove it and always add the new one. + if (this.originalLabelsElement) { + privateElement?.removeChild(this.originalLabelsElement); + } + privateElement?.append(this.newLabelsElement); + this.originalLabelsElement = this.newLabelsElement; + } + + render(): TemplateResult { + const labels = this.labels; + return html` +
+
+ + +
+
+ { + this.addLabel(); + }} + > +
+
+ + ${labels.map((element) => { + const value = element.textContent; + return html` + ${value} + label + { + this.removeLabel(element); + }} + > + `; + })} + + `; + } + + static styles = css` + oscd-textfield { + width: 100%; + } + + #labeldiv { + display: flex; + flex-direction: row; + } + + #labeltextdiv { + flex: auto; + } + + #labelicondiv { + display: flex; + align-items: center; + height: 56px; + } + + mwc-list-item { + --mdc-list-item-meta-size: 48px; + } + + mwc-icon-button { + color: var(--mdc-theme-on-surface); + } + `; +} diff --git a/components/compas-docops-components/src/compas-scltype-select.ts b/components/compas-docops-components/src/compas-scltype-select.ts new file mode 100644 index 0000000..d3087cd --- /dev/null +++ b/components/compas-docops-components/src/compas-scltype-select.ts @@ -0,0 +1,90 @@ +import { + css, + customElement, + html, + LitElement, + TemplateResult, + property, +} from "lit-element"; + +import "@material/mwc-list"; +import "@material/mwc-list/mwc-list-item"; +import "@material/mwc-select"; + +import { CompasSclDataService, SDS_NAMESPACE } from "@com-pas/compas-open-core"; +import type { Select } from "@material/mwc-select"; +import { repeat } from "lit-html/directives/repeat"; + +export class CompasSclTypeSelect extends LitElement { + @property({ type: String }) + value = ""; + + @property({ type: Element }) + sclTypes?: Element[]; + + firstUpdated(): void { + this.fetchData(); + } + + fetchData(): void { + CompasSclDataService() + .listOrderedSclTypes() + .then((types) => (this.sclTypes = types)); + } + + getSelectedValue(): string | null { + return ( + (