/node_modules/",
17 | ],
18 | };
19 |
--------------------------------------------------------------------------------
/src/declarations.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.html" {
2 | const rawHtmlFile: string;
3 | export = rawHtmlFile;
4 | }
5 |
6 | declare module "*.bmp" {
7 | const src: string;
8 | export default src;
9 | }
10 |
11 | declare module "*.gif" {
12 | const src: string;
13 | export default src;
14 | }
15 |
16 | declare module "*.jpg" {
17 | const src: string;
18 | export default src;
19 | }
20 |
21 | declare module "*.jpeg" {
22 | const src: string;
23 | export default src;
24 | }
25 |
26 | declare module "*.png" {
27 | const src: string;
28 | export default src;
29 | }
30 |
31 | declare module "*.webp" {
32 | const src: string;
33 | export default src;
34 | }
35 |
36 | declare module "*.svg" {
37 | const src: string;
38 | export default src;
39 | }
40 |
--------------------------------------------------------------------------------
/.github/workflows/widget-ci.yml:
--------------------------------------------------------------------------------
1 | name: Widget CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - main
10 | workflow_dispatch:
11 | inputs:
12 | node_version_override:
13 | description: "Override Node.js version for this run (e.g., 20)"
14 | required: false
15 | type: string
16 |
17 | jobs:
18 | run_minimal_ci:
19 | name: Widget CI
20 | uses: docusign/1fe-ci-cd/.github/workflows/ci-widgets.yml@main
21 | with:
22 | node-version: ${{ github.event.inputs.node_version_override || '22' }}
23 | secrets:
24 | AKAMAI_NS_SSH_PRIVATE_KEY: ${{ secrets.AKAMAI_NS_SSH_PRIVATE_KEY }}
25 | AZURE_APP_CONFIG_CONNECTION_STRING: ${{ secrets.AZURE_APP_CONFIG_CONNECTION_STRING }}
26 | PRIVATE_KEY_1FE_ADMIN_GITHUB_APP: ${{ secrets.PRIVATE_KEY_1FE_ADMIN_GITHUB_APP }}
27 |
--------------------------------------------------------------------------------
/playwright.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, devices } from "@playwright/test";
2 |
3 | export default defineConfig({
4 | testDir: "./tests",
5 | fullyParallel: true,
6 | forbidOnly: !!process.env.CI,
7 | retries: process.env.CI ? 2 : 0,
8 | workers: process.env.CI ? 1 : undefined,
9 | reporter: "html",
10 | use: {
11 | baseURL: "http://localhost:3000",
12 | trace: "on-first-retry",
13 | },
14 |
15 | projects: [
16 | {
17 | name: "chromium",
18 | use: { ...devices["Desktop Chrome"] },
19 | },
20 |
21 | {
22 | name: "firefox",
23 | use: { ...devices["Desktop Firefox"] },
24 | },
25 |
26 | {
27 | name: "webkit",
28 | use: { ...devices["Desktop Safari"] },
29 | },
30 | ],
31 |
32 | // Disable webServer for now due to Node version mismatch
33 | // webServer: {
34 | // command: 'yarn dev',
35 | // url: 'http://localhost:3000',
36 | // reuseExistingServer: !process.env.CI,
37 | // },
38 | });
39 |
--------------------------------------------------------------------------------
/.github/workflows/rollback-widget.yml:
--------------------------------------------------------------------------------
1 | name: Rollback Widget
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | target-version:
7 | description: "The specific version to roll back to (e.g., 1.0.3 or 1.0.3-PR-123.abcde12)"
8 | required: true
9 | type: string
10 | environment:
11 | description: "The environment to rollback (e.g., integration or production)"
12 | required: true
13 | type: choice
14 | options:
15 | - integration
16 | - production
17 |
18 | permissions:
19 | contents: read
20 | id-token: write
21 |
22 | jobs:
23 | rollback-widget:
24 | uses: docusign/1fe-ci-cd/.github/workflows/reusable-rollback-ci.yml@main
25 | with:
26 | target-version: ${{ github.event.inputs.target-version }}
27 | environment: ${{ github.event.inputs.environment }}
28 | caller-repo: ${{ github.repository }}
29 | caller-repo-ref: ${{ github.ref }}
30 | secrets:
31 | AZURE_APP_CONFIG_CONNECTION_STRING: ${{ secrets.AZURE_APP_CONFIG_CONNECTION_STRING }}
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Docusign Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/tests/widget.spec.ts:
--------------------------------------------------------------------------------
1 | import { test, expect } from "@playwright/test";
2 |
3 | test.describe("Widget Tests", () => {
4 | test("playwright configuration is working", async ({ page }) => {
5 | // Simple test to verify Playwright is set up correctly
6 | await page.goto(
7 | "data:text/html,Test PageHello World
",
8 | );
9 | await expect(page).toHaveTitle("Test Page");
10 | await expect(page.locator("h1")).toHaveText("Hello World");
11 | });
12 |
13 | test("should validate basic browser functionality", async ({ page }) => {
14 | // Test basic browser functionality with inline HTML
15 | await page.goto(
16 | 'data:text/html,Browser TestPlaywright is working!
',
17 | );
18 | await expect(page.locator("#test")).toBeVisible();
19 | await expect(page.locator("#test")).toHaveText("Playwright is working!");
20 | });
21 |
22 | // TODO: Add widget-specific tests once dev server Node version is resolved
23 | test.skip("should load the widget", async ({ page }) => {
24 | await page.goto("/");
25 |
26 | // Wait for the widget to be mounted
27 | await expect(
28 | page.locator("text=My amazing component from app2 is mounted!"),
29 | ).toBeVisible();
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = /** @type {import("eslint").Linter.Config} */ {
2 | extends: [
3 | "eslint:recommended",
4 | "plugin:react/recommended",
5 | "plugin:@typescript-eslint/recommended",
6 | "plugin:prettier/recommended",
7 | "eslint-config-prettier",
8 | ],
9 | ignorePatterns: ["node_modules/", "dist/"],
10 | parser: "@typescript-eslint/parser", // Use the TypeScript parser
11 | parserOptions: {
12 | ecmaVersion: 2022, // Support the latest ECMAScript features
13 | sourceType: "module", // Enable ECMAScript modules
14 | ecmaFeatures: {
15 | jsx: true,
16 | },
17 | },
18 | plugins: ["@typescript-eslint", "prettier"],
19 | env: {
20 | browser: true, // Enable browser global variables
21 | node: true, // Enable Node.js global variables
22 | es6: true, // Enable ECMAScript 6 features
23 | },
24 | settings: {
25 | react: {
26 | version: "detect", // Automatically detect the React version
27 | },
28 | },
29 | rules: {
30 | "prettier/prettier": "error", // Treat Prettier violations as errors
31 | "@typescript-eslint/explicit-module-boundary-types": "off", // Optional: Disables enforcing explicit return types on function signatures
32 | "react/no-unknown-property": ["error", { ignore: ["css"] }], // Required for emotion css prop
33 | "react/react-in-jsx-scope": "off",
34 | "react/jsx-uses-react": "off",
35 | },
36 | };
37 |
--------------------------------------------------------------------------------
/src/app2.tsx:
--------------------------------------------------------------------------------
1 | import { platformProps } from "@1fe/shell";
2 | import { useState, useCallback, useEffect } from "react";
3 | import { Button } from "antd";
4 | import { /* WidgetProps , */ WidgetEvents } from "./contract";
5 |
6 | export default function Root(/* props: WidgetProps */) {
7 | useEffect(() => {
8 | platformProps.utils.appLoadTime.end();
9 | }, []);
10 |
11 | const [eventBusResult, setEventBusResult] = useState("unchanged");
12 | const [unsubscribeFn, setUnsubscribeFn] = useState(() => () => {});
13 |
14 | const listener = useCallback(
15 | (event: unknown) => {
16 | setEventBusResult(JSON.stringify(event));
17 | },
18 | [setEventBusResult],
19 | );
20 |
21 | return (
22 | <>
23 | My component from app2 is mounted!
24 |
40 |
49 | {eventBusResult}
50 | >
51 | );
52 | }
53 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # generateds files
30 | reports
31 |
32 | # node-waf configuration
33 | .lock-wscript
34 |
35 | # Compiled binary addons (https://nodejs.org/api/addons.html)
36 | build/Release
37 |
38 | # Dependency directories
39 | node_modules/
40 | jspm_packages/
41 |
42 | # TypeScript v1 declaration files
43 | typings/
44 |
45 | # Optional npm cache directory
46 | .npm
47 |
48 | # Optional eslint cache
49 | .eslintcache
50 |
51 | # Optional REPL history
52 | .node_repl_history
53 |
54 | # Output of 'npm pack'
55 | *.tgz
56 |
57 | # Yarn Integrity file
58 | .yarn-integrity
59 |
60 | # dotenv environment variables file
61 | .env
62 |
63 | # next.js build output
64 | .next
65 | dist
66 |
67 | # Editor directories and files
68 | .idea
69 | .vscode
70 | *.suo
71 | *.ntvs*
72 | *.njsproj
73 | *.sln
74 | *.sw?
75 | .DS_Store
76 |
77 | # transient types
78 | src/types/widgets
79 |
80 | # Yarn
81 | .pnp.*
82 | .yarn/*
83 | !.yarn/patches
84 | !.yarn/plugins
85 | !.yarn/releases
86 | !.yarn/sdks
87 | !.yarn/versions
88 |
89 | # Playwright
90 | /test-results/
91 | /playwright-report/
92 | /blob-report/
93 | /playwright/.cache/
94 |
95 | .cache
96 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@1fe/sample-widget",
3 | "version": "0.1.3",
4 | "license": "MIT",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "1fe-cli --trace --environment integration dev",
8 | "build:widget": "1fe-cli --trace --environment integration build",
9 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10 | "format": "prettier --write .",
11 | "check-format": "prettier --check .",
12 | "prepack": "yarn build",
13 | "test": "yarn jest",
14 | "test:e2e": "playwright test",
15 | "test:e2e:ui": "playwright test --ui",
16 | "test:all": "yarn test && yarn test:e2e"
17 | },
18 | "devDependencies": {
19 | "@1fe/cli": "0.0.1",
20 | "@1fe/sample-widget-base-config": "0.0.1",
21 | "@babel/core": "^7.28.0",
22 | "@babel/preset-env": "^7.28.0",
23 | "@babel/preset-react": "^7.27.1",
24 | "@babel/preset-typescript": "^7.27.1",
25 | "@playwright/test": "^1.53.1",
26 | "@testing-library/dom": "^10.4.0",
27 | "@testing-library/jest-dom": "^6.6.3",
28 | "@testing-library/react": "^16.3.0",
29 | "@types/jest": "^29",
30 | "@types/react": "^18.2.62",
31 | "@types/react-dom": "^18.2.19",
32 | "@typescript-eslint/eslint-plugin": "^8.35.0",
33 | "@typescript-eslint/parser": "^8.35.0",
34 | "babel-jest": "^29",
35 | "cross-env": "^7.0.3",
36 | "eslint": "8.57.1",
37 | "eslint-config-prettier": "^10.1.1",
38 | "eslint-config-ts-react-important-stuff": "^3.0.0",
39 | "eslint-plugin-prettier": "^5.2.4",
40 | "eslint-plugin-react": "^7.37.5",
41 | "identity-obj-proxy": "^3.0.0",
42 | "jest": "^29",
43 | "jest-environment-jsdom": "^29",
44 | "prettier": "^3.5.3",
45 | "pretty-quick": "^3.1.1",
46 | "ts-config-single-spa": "^3.0.0",
47 | "ts-jest": "^29",
48 | "typescript": "5.8.2"
49 | },
50 | "dependencies": {
51 | "@1fe/shell": "0.0.1",
52 | "@emotion/react": "^11.14.0",
53 | "@emotion/styled": "^11.14.0",
54 | "@mui/material": "^7.1.0",
55 | "@reduxjs/toolkit": "1.9.1",
56 | "@textea/json-viewer": "^4.0.1",
57 | "@types/systemjs": "^6.15.1",
58 | "antd": "^5.22.4",
59 | "react": "^18.3.1",
60 | "react-dom": "^18.3.1",
61 | "react-redux": "^8.1.3",
62 | "react-router-dom": "6.30.0",
63 | "reselect": "^4.1.7",
64 | "single-spa": "^5.9.3",
65 | "single-spa-react": "^6.0.2"
66 | },
67 | "packageManager": "yarn@4.9.1"
68 | }
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 1fe Sample Widget
2 |
3 | A basic sample widget demonstrating core 1fe platform integration patterns. This widget showcases essential platform utilities and serves as a reference implementation for building widgets within the 1fe ecosystem.
4 |
5 | ## What's in this repository
6 |
7 | This sample widget demonstrates:
8 |
9 | - **Platform integration** using `@1fe/shell` utilities
10 | - **Event bus communication** between widgets and platform
11 | - **App load time tracking** for performance monitoring
12 | - **Basic widget lifecycle** and contract implementation
13 | - **Antd UI components** integration
14 | - **TypeScript configuration** for widget development
15 |
16 | ## Prerequisites
17 |
18 | - **Node.js** `>= 22`
19 | - **Yarn** (package manager)
20 |
21 | ## Getting Started
22 |
23 | ### Development Setup
24 |
25 | ```bash
26 | # Clone this repository
27 | git clone
28 | cd 1fe-sample-widget
29 |
30 | # Install dependencies
31 | yarn install
32 |
33 | # Start development server
34 | yarn dev
35 | ```
36 |
37 | ### Project Structure
38 |
39 | ```text
40 | src/
41 | ├── app2.tsx # Main application component
42 | ├── contract.ts # Widget contract definition
43 | ├── declarations.d.ts # TypeScript declarations
44 | ├── root.component.tsx # Root component wrapper
45 | ├── root.component.test.tsx # Component tests
46 | └── widget.ts # Widget entry point
47 | ```
48 |
49 | ## Development Commands
50 |
51 | ```bash
52 | # Start development server with hot reloading
53 | yarn dev
54 |
55 | # Build widget for production
56 | yarn build:widget
57 |
58 | # Lint code
59 | yarn lint
60 |
61 | # Format code
62 | yarn format
63 |
64 | # Check code formatting
65 | yarn check-format
66 | ```
67 |
68 | ## Widget Features
69 |
70 | ### Platform Integration
71 |
72 | - **App Load Time**: Tracks and reports widget loading performance
73 | - **Event Bus**: Demonstrates inter-widget communication
74 | - **Platform Props**: Access to 1fe platform utilities
75 |
76 | ### UI Components
77 |
78 | - Uses Antd components for consistent UI
79 | - Demonstrates button interactions and state management
80 | - Event handling and user feedback
81 |
82 | ## Widget Contract
83 |
84 | The widget defines its interface in `src/contract.ts`:
85 |
86 | ```typescript
87 | export interface WidgetEvents {
88 | // Event definitions for widget communication
89 | }
90 | ```
91 |
92 | ## Configuration
93 |
94 | The widget uses the base configuration from `@1fe/sample-widget-base-config` for:
95 |
96 | - Environment settings
97 | - Build configurations
98 | - Platform integration setup
99 |
100 | ## Testing
101 |
102 | Unit tests are included for components:
103 |
104 | - Test files: `*.test.tsx`
105 | - Uses React Testing Library patterns
106 |
107 | ## Contributing
108 |
109 | ### Development Workflow
110 |
111 | 1. Fork the repository
112 | 2. Create a feature branch (`git checkout -b feature/your-feature`)
113 | 3. Make your changes
114 | 4. Run tests and linting (`yarn lint`)
115 | 5. Format your code (`yarn format`)
116 | 6. Commit your changes (`git commit -m 'Add feature'`)
117 | 7. Push to your branch (`git push origin feature/your-feature`)
118 | 8. Open a Pull Request
119 |
120 | ## Troubleshooting
121 |
122 | ### Common Issues
123 |
124 | - **Build failures**: Ensure Node.js version is >= 22 and dependencies are installed
125 | - **Platform utilities not available**: Check that `@1fe/shell` is properly imported
126 | - **Event bus issues**: Verify event listeners are properly set up and cleaned up
127 |
128 | ## Getting Help
129 |
130 | - **[1fe Documentation](https://1fe.com/getting-started/installation/)** - Complete platform documentation
131 | - **[GitHub Issues](https://github.com/docusign/1fe/issues)** - Report bugs or request features
132 | - **[GitHub Discussions](https://github.com/docusign/1fe/discussions)** - Ask questions and share ideas
133 |
134 | ## License
135 |
136 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
137 |
--------------------------------------------------------------------------------