{"id":28562878,"url":"https://github.com/nuvla/ui","last_synced_at":"2025-06-10T12:11:56.411Z","repository":{"id":37788799,"uuid":"169089379","full_name":"nuvla/ui","owner":"nuvla","description":"Nuvla's browser-based user interface packaged as a Docker container","archived":false,"fork":false,"pushed_at":"2025-06-04T14:49:03.000Z","size":30208,"stargazers_count":6,"open_issues_count":126,"forks_count":5,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-06-04T17:55:42.316Z","etag":null,"topics":["clojurescript","docker","re-frame","semantic-ui-react"],"latest_commit_sha":null,"homepage":"https://sixsq.com","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nuvla.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-04T14:18:56.000Z","updated_at":"2025-02-19T13:48:50.000Z","dependencies_parsed_at":"2023-10-14T23:04:08.814Z","dependency_job_id":"afd81e43-4b8b-4e48-a372-fda8b0b5ce59","html_url":"https://github.com/nuvla/ui","commit_stats":null,"previous_names":[],"tags_count":135,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nuvla%2Fui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nuvla%2Fui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nuvla%2Fui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nuvla%2Fui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nuvla","download_url":"https://codeload.github.com/nuvla/ui/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nuvla%2Fui/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259073025,"owners_count":22801094,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojurescript","docker","re-frame","semantic-ui-react"],"created_at":"2025-06-10T12:11:53.599Z","updated_at":"2025-06-10T12:11:56.395Z","avatar_url":"https://github.com/nuvla.png","language":"Clojure","readme":"# Nuvla Web UI\n\n[![Dev](https://github.com/nuvla/ui/actions/workflows/dev.yml/badge.svg)](https://github.com/nuvla/ui/actions/workflows/dev.yml)\n[![Release](https://github.com/nuvla/ui/actions/workflows/release.yml/badge.svg)](https://github.com/nuvla/ui/actions/workflows/release.yml)\n[![End to End Tests](https://github.com/nuvla/ui/actions/workflows/e2e_test.yml/badge.svg)](https://github.com/nuvla/ui/actions/workflows/e2e_test.yml)\n[![Unit Tests](https://github.com/nuvla/ui/actions/workflows/unit_tests.yml/badge.svg)](https://github.com/nuvla/ui/actions/workflows/unit_tests.yml)\n[![Docker Image Version (latest semver)](https://img.shields.io/docker/v/nuvla/ui?label=Latest%20release\u0026sort=semver)](https://hub.docker.com/repository/docker/nuvla/ui/tags)\n![Docker Image Size](https://img.shields.io/docker/image-size/nuvla/ui?label=Image%20size)\n\nThis repository contains the web user interface of the Nuvla solution. It is built as a modern\nsingle page application.\n\nThe ui is built entirely in Clojurescript (that's cool), using [re-frame](https://github.com/Day8/re-frame)\nand [reagent](https://github.com/reagent-project/reagent) as foundation, and\n[Semantic UI](https://semantic-ui.com) for basic widgets and styling.\n\nOur aim is to build a user experience such that users can start capturing, deploying and managing\ncontainers on any virtualised environments (e.g. public cloud, private cloud and infrastructure,\nas well as [NuvlaEdge](https://github.com/nuvlaedge) devices). And all this with no or minimum training.\n\nMore details on the overall Nuvla eco-system is available [here](https://github.com/nuvla/nuvla).\n\n## Artifacts\n\n- `nuvla/ui` - A Docker container containing the static content of\n  the UI served by nginx. Available from the [nuvla/ui\n  repository](https://hub.docker.com/r/nuvla/ui) on Docker Hub.\n\n## Development Environment\n\n### Installation\n\nFor development you need [nodejs](https://nodejs.org/), [leiningen](https://leiningen.org/)\nand [caddy](https://caddyserver.com/)\n\nOn Mac OS, the `npm` command comes with the Node.js distribution of\nHomebrew. Just run the command `brew install node`.\n\n```bash\nbrew install node\nbrew install leiningen\nbrew install caddy\n```\n\nFor other distributions or for direct installation on Mac OS, take a look at tools website for instructions.\n\nThe ui can be installed on its own or as part of a full Nuvla stack. Stand alone installations\nmust be configured to point to an existing Nuvla server.\n\nYou can also run your own Nuvla test server locally, which is great for testing. You'll find instructions\n[here](https://github.com/nuvla/deployment/test).\n\n### Choose or deploy a Nuvla server\n\nYou will need to point your development ui environment to a Nuvla server. For that\nyou have a few choices:\n\n1. [Deploy a test server](https://github.com/nuvla/deployment/tree/master/test)\n2. Point to an already deployed server (e.g. https://nuvla.io)\n\nYou then need to configure your local Nuvla ui to point to the Nuvla server (next section).\n\n### Configure caddy for the right server\n\nTo run your UI dev server and your backend server from the same host address we use [Caddy](https://caddyserver.com/) as\na reverse-proxy during development. Caddy installs local certificates automatically, so we can run the development\nenvironment on a \"real\" URL.\n\nFirst, create a new file called `Caddyfile` with this content:\n\n```\n# this is a comment\n\n{\n    local_certs\n}\n\nnui.localhost {\n    reverse_proxy localhost:8280\n    reverse_proxy /api/* {\n        to https://nuvla.io   # this points to a server of your chosing\n        \n        # uncomment following lines if your api server is using an untrusted certificate\n        # transport http {\n        #    tls_insecure_skip_verify \n        # }\n    }\n}\n```\n\nFrom the same directory where the `Caddyfile` is located, you run the command `caddy run` (or `caddy start` to run it in\nthe background).\n\nIf you want to point the API somewhere else, you can change your `Caddyfile`\nfrom `reverse_proxy /api/* https://nuvla.io` to e.g. `reverse_proxy /api/* localhost:8200` and run the\ncommand `caddy reload` (no need to restart anything else).\n\n\n### Start development ui\n\nRun `npm ci --legacy-peer-deps` inside `code` folder of the cloned repository. This only needs to be done once at the beginning and\nthen whenever dependencies change.\nWhen you now run `lein dev` from the `code` folder, you can visit the Nuvla-Ui at https://nui.localhost.\n\n\n## Testing\n\n### Component testing\n\nWe use [`Portfolio`](https://github.com/cjohansen/portfolio) for component showcasing and\n[`playwright`](https://playwright.dev/) for component testing.\n\nBy running `lein dev` a Porfolio server is started automatically on port 8281.\n\nTo execute all component tests run the following command (Portfolio needs to be running for this command to work):\n\n`npm run test:components`\n\nor for headed mode:\n\n`npm run test:components:headed`\n\n### End to end testing\n\nWe use [`playwright`](https://playwright.dev/) for e2e-testing.\nTo run playwright locally, inside the code directory, you `cp .env.e2e.TEMPLATE .env.e2e` and set the environment\nvariables specified in that file.\nTests are located in the `code/test/e2e/` directory.\n\n#### Create tests\n\n1. Run\n\n```bash\nnpm run test:e2e:gen\n```\n\nyou open the [playwright Test Generator](https://playwright.dev/docs/codegen).\nIt allows you to visit a website, record all interactions and let `playwright` generate all code necessary to replay\nthose interactions.\n\n2. Copy the generated code into a new file.\n   You can remove the code used to log in, as all tests run with a logged-in user (you can change the user in\n   the `.env.e2e` file).\n   Adjust the code to suit your needs, e.g., writing assertions using `expect`.\n\n   As an alternative, you can save the output of the code generation directly to a file:\n```bash\nnpm run test:e2e:gen -- -o test.spec.js\n```\n\n3. Put new tests inside the `code/test/e2e/loggedin` directory.\n   The file has to end with `.spec.js` (`.ts` for typescript files is possible).\n\n#### Run tests\n\nFour additional commands are configured in `package.json` to run the tests (all starting with `test:e2e`).\n\nRun all tests:\n\n```bash\nnpm run test:e2e\n```\n\nRun a single file by specifying a path, treated as a regex:\n\n```bash\nnpm run test:e2e logout\n```\n\nWatch the test folder and run a test if the test file changes:\n\n```bash\nnpm run test:e2e:watch\n```\n\nRun tests in headed mode, i.e. a browser window opens and you can see the test run.\n\nYou have to specify a path; this example runs all tests:\n\n```bash\nnpm run test:e2e:headed\n```\n\nThe headed test runs are also available in watch mode.\nYou do not have to provide a path regex: the path is provided by the watching process.\n\n```bash\nnpm run test:e2e:headed:watch\n```\n\n#### Run in parallel\n\nIt is possible to run the tests in parallel.\nBecause they share the same logged in session (through `global-setup.js`), it could be that tests fail if\nthe `logout.spec.js` tests runs first.\nTo prevent this, only run tests inside the loggedin folder.\n\n```bash\nnpm run test:e2e loggedin -- --workers 5\n```\n\n#### Debug tests\n\nBy adding a `page.pause()` inside a test file and running in `headed` mode, you can stop and open an inspector view.\n\nWhen a test fails, you find a `trace.zip` file inside the respective directory in the `code/test-report` folder. You can\nopen it by\n\n```bash\nnpx playwright show-trace test-results/\u003cpath-to-test-file\u003e-\u003ctest-name\u003e-retry\u003cretrynumber\u003e/trace.zip\n```\n\n#### Find additional playwright settings\n\n```bash\nnpx playwright --help\n```\n\nand\n\n```bash\nnpx playwright test --help\n```\n\n### Unit tests\n\n#### Run all unit tests\n\n```bash\nnpm run test:unit\n```\n\n#### Run unit tests in cursive REPL\n\n1. Shadow-clj build project:\n    ```bash\n    lein dev\n    ```\n2. Get nREPL server port from file or from console:\n   - console: `shadow-cljs - nREPL server started on port 60325`\n   - file: `code/.shadow-cljs/nrepl.port`\n3. Wait until shadow-cljs finish compilation\n4. Browse to UI page in web browser to load javascript runtime\n5. Connect with nRepl client\n6. Select project in nRepl, load test file and run-tests\n   ```repl\n   (shadow/repl :nuvla-ui)\n   (load-file \"test/cljs/sixsq/nuvla/ui/edges/utils_test.cljs\")\n   (cljs.test/run-tests 'sixsq.nuvla.ui.edges.utils-test)\n   ```\n\n## Bundle size analyze\n\nshadow-cljs can create a bundle size report.\n\n```bash\nnpx shadow-cljs run shadow.cljs.build-report nuvla-ui report.html\n```\n\nThis saves the report as `report.html` in `resources/public/ui/js`.\n\n## Contributing\n\n### Source Code Changes\n\nTo contribute code to this repository, please follow these steps:\n\n1. Create a branch from master with a descriptive, kebab-cased name\n   to hold all your changes.\n\n2. Follow the developer guidelines concerning formatting, etc. when\n   modifying the code.\n\n3. Once the changes are ready to be reviewed, create a GitHub pull\n   request. With the pull request, provide a description of the\n   changes and links to any relevant issues (in this repository or\n   others).\n\n4. Ensure that the triggered CI checks all pass. These are triggered\n   automatically with the results shown directly in the pull request.\n\n5. Once the checks pass, assign the pull request to the repository\n   coordinator (who may then assign it to someone else).\n\n6. Interact with the reviewer to address any comments.\n\nWhen the reviewer is happy with the pull request, he/she will \"squash\n\u0026 merge\" the pull request and delete the corresponding branch.\n\n### Code Formatting\n\nThe bulk of the code in this repository is written in Clojurescript.\n\nThe formatting follows the standard formatting provided by the Cursive\nIntelliJ plugin with all the default settings **except that map\nand let entries should be aligned**.\n\nAdditional, formatting guidelines, not handled by the Cursive plugin:\n\n- Use a new line after the `:require` and `:import` keys in namespace\n  declarations.\n\n- Alphabetize the required namespaces. This can be automated with\n  `lein nsorg --replace`.\n\n- Use 2 blank lines between top-level forms.\n\n- Use a single blank line between a block comment and the following\n  code.\n\nIntelliJ (with Cursive) can format easily whole directories of source\ncode. Do not hesitate to use this feature to keep the source code\nformatting standardized.\n\n## Integration with IntelliJ\n\nYou can import the repository through IntelliJ, using the \"leiningen\"\nmethod in the dialog.\n\nIf you have the IntelliJ command line installed, the shadow-cljs\nheads-up display, should open files in the IntelliJ editor.\n\nThe command for opening Chrome with the security disabled, can be\nconfigured as an \"external tool\" in IntelliJ. In \"Preferences\", go to\nthe \"Tools\" -\u003e \"External Tools\" panel.\n\n### Logging\n\nYou can reset the logging level for kvlt from the REPL when running\nin development mode. From the REPL do:\n\n```\n=\u003e (require '[taoensso.timbre :as timbre])\n=\u003e (timbre/set-level! :info)\n```\n\nThe default value is `:debug` which will log all the HTTP requests\nand responses. This is useful when debugging interactions with\nNuvla, but annoying otherwise.\n\n## Release Process\n\nRelease process instructions are available [here](RELEASE.md).\n\n## Copyright\n\nCopyright \u0026copy; 2019-2024, SixSq SA\n\n## License\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you\nmay not use this file except in compliance with the License. You may\nobtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\nimplied. See the License for the specific language governing\npermissions and limitations under the License.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnuvla%2Fui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnuvla%2Fui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnuvla%2Fui/lists"}