{"id":39497553,"url":"https://github.com/sndcds/uranus-dashboard","last_synced_at":"2026-04-17T11:01:57.084Z","repository":{"id":319329061,"uuid":"1078231789","full_name":"sndcds/uranus-dashboard","owner":"sndcds","description":"A web dashboard for managing and visualizing event data from the Uranus API.","archived":false,"fork":false,"pushed_at":"2026-04-10T11:12:17.000Z","size":7770,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-10T12:25:45.339Z","etag":null,"topics":["admin-panel","api-integration","dashboard","events","frontend","javascript","uranus","visualization","vue"],"latest_commit_sha":null,"homepage":"https://uranus.oklabflensburg.de","language":"Vue","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sndcds.png","metadata":{"files":{"readme":"README.md","changelog":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-17T12:09:26.000Z","updated_at":"2026-03-25T14:36:31.000Z","dependencies_parsed_at":"2025-12-31T17:08:43.517Z","dependency_job_id":null,"html_url":"https://github.com/sndcds/uranus-dashboard","commit_stats":null,"previous_names":["sndcds/uranus-dashboard"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sndcds/uranus-dashboard","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sndcds%2Furanus-dashboard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sndcds%2Furanus-dashboard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sndcds%2Furanus-dashboard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sndcds%2Furanus-dashboard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sndcds","download_url":"https://codeload.github.com/sndcds/uranus-dashboard/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sndcds%2Furanus-dashboard/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31926260,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-17T10:35:34.458Z","status":"ssl_error","status_checked_at":"2026-04-17T10:35:09.472Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["admin-panel","api-integration","dashboard","events","frontend","javascript","uranus","visualization","vue"],"created_at":"2026-01-18T05:43:41.436Z","updated_at":"2026-04-17T11:01:57.078Z","avatar_url":"https://github.com/sndcds.png","language":"Vue","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Uranus Dashboard\n\n[![Lighthouse CI](https://github.com/sndcds/uranus-dashboard/actions/workflows/lighthouse.yml/badge.svg)](https://github.com/sndcds/uranus-dashboard/actions/workflows/lighthouse.yml)\n[![Run codeql](https://github.com/sndcds/uranus-dashboard/actions/workflows/codeql.yml/badge.svg)](https://github.com/sndcds/uranus-dashboard/actions/workflows/codeql.yml)\n[![Frontend Tests](https://github.com/sndcds/uranus-dashboard/actions/workflows/tests.yml/badge.svg)](https://github.com/sndcds/uranus-dashboard/actions/workflows/tests.yml)\n\nUranus Dashboard is a Vue 3 single-page application that helps cultural organisations run their events, venues, and spaces. The app offers a visitor-facing calendar as well as an authenticated workspace where editors can manage organisers, venues, event metadata, translations, and personal settings.\n\n\u003e **Good to know**  \n\u003e The UI expects a Uranus API server that exposes the `/api` endpoints used throughout the codebase (for example `/api/admin/login`, `/api/admin/organization/:id`, `/api/admin/event/create`, …). You can still explore the UI without a backend, but data loads and mutations will fail.\n\n## Feature Highlights\n\n- **Authentication flow** with login, signup, forgotten-password, and reset-password screens, token refresh, and local storage persistence.\n- **Dashboard workspace** for logged-in users featuring organiser, venue, space, and event management, including split create/update flows.\n- **Rich form experiences** such as Markdown-enabled descriptions, Leaflet-powered maps for picking coordinates, and dependent selects for legal forms, countries, and states.\n- **Event builder** with a two-stage tag selector, availability calendar, language selector backed by live API data, and validation before submission.\n- **Visitor layout** that exposes the public event calendar, language selector, theme switcher, and legal links without requiring an account.\n- **Internationalisation** with German, English, and Danish translations wired through Vue I18n and ready for extension.\n- **Personalisation** with light/dark themes, profile editing, avatar upload, and user permissions quick links.\n\n## Tech Stack\n\n- [Vue 3](https://vuejs.org/) with the `\u003cscript setup\u003e` syntax\n- [TypeScript](https://www.typescriptlang.org/)\n- [Vite](https://vite.dev/) for development and bundling\n- [Pinia](https://pinia.vuejs.org/) for state management\n- [Vue Router](https://router.vuejs.org/) navigation guards and layouts\n- [Vue I18n](https://vue-i18n.intlify.dev/) internationalisation\n- [Leaflet](https://leafletjs.com/) for interactive maps in address forms\n- [Quill](https://quilljs.com/) (via `MarkdownEditorComponent.vue`) for enhanced text editing\n\n## Quick Start\n\n### Prerequisites\n\n- Node.js 20 LTS or newer (use [nvm](https://github.com/nvm-sh/nvm) or a similar tool to manage versions).\n- npm 10 (bundled with Node 20).\n- Access to a Uranus API instance (development or staging) with credentials you can use.\n\n### Installation\n\n1. **Clone the repository**\n   ```bash\n   git clone https://github.com/sndcds/uranus-dashboard.git\n   cd uranus-dashboard\n   ```\n2. **Install dependencies**\n   ```bash\n   npm install\n   ```\n\n### Configure environment variables\n\nCreate a `.env.local` (or `.env`) file in the project root and set the API base URL:\n\n```ini\n# .env.local\nVITE_API_URL=https://uranus-api.example.org\n```\n\nThe value can point at `http://localhost:8000` when running a local backend. During development the Vite dev server proxies `/api/*` requests to the URL defined here (see `vite.config.ts`).\n\n### Run the application\n\n- **Development server**\n  ```bash\n  npm run dev\n  ```\n  Vite prints a local and network URL (default: `http://localhost:5173`). Hot Module Replacement is enabled out of the box.\n\n- **Type checking \u0026 linting**\n  \n  The project relies on TypeScript’s compiler diagnostics and ESLint. Run `npm run build` or `vue-tsc --noEmit` manually if you need a dedicated type check step.\n\n- **Production build**\n  ```bash\n  npm run build\n  ```\n  Bundled assets are emitted into `dist/`.\n\n- **Preview a production build**\n  ```bash\n  npm run preview\n  ```\n\n## Testing\n\nUranus Dashboard ships with a [Vitest](https://vitest.dev/) suite that exercises components, views, Pinia stores, and high-level authentication flows. Run the commands below from the project root:\n\n```bash\n# Run the full suite (default happy-dom environment)\nnpm run test\n\n# Launch the Vitest UI runner\nnpm run test:ui\n\n# Collect coverage information\nnpm run test:coverage\n```\n\nTest helpers, mocks, and specs live inside the `tests/` directory—see `tests/README.md` for a full breakdown of available specs and coverage focus areas.\n\n## Project Layout\n\n```\n├─ public/                    # Static assets copied as-is\n├─ src/\n│  ├─ api.ts                  # apiFetch helper with token refresh logic\n│  ├─ components/             # Reusable UI units (forms, layout, editors, maps)\n│  ├─ i18n/                   # Vue I18n setup and translation catalogue\n│  ├─ models/                 # Shared TypeScript interfaces (event models, …)\n│  ├─ router/                 # Route definitions and navigation guards\n│  ├─ store/                  # Pinia stores (token, theme, app, user)\n│  ├─ styles/                 # Global SCSS theme tokens and mixins\n│  ├─ utils/                  # Helpers (e.g. theme application)\n│  └─ views/                  # Page-level components registered in the router\n├─ vite.config.ts             # Vite build and dev-server configuration\n└─ tsconfig.json              # TypeScript project settings\n```\n\n## User Guide\n\n### Authentication \u0026 Account Access\n\n- **Login \u0026 Signup:** Accessed via `/login` and `/signup` under the visitor layout. Successful login stores access and refresh tokens in `localStorage` (`useTokenStore`) and redirects to the dashboard.\n- **Forgot / Reset password:** `/forgot-password` sends a reset link, `/reset-password?token=…` lets users choose a new password with double entry and eye icons for toggling visibility.\n- **Session refresh:** `apiFetch` transparently refreshes JWTs when a 401 response comes back, using the stored refresh token and reattempting the failed request.\n\n### Dashboard Workspace (authenticated)\n\n- **Dashboard home (`/`):** A welcome hero reminding users of key tasks.\n- **Organisers (`/organizations`):** List fetched from `/api/admin/organization/list`, with cards linking to create/update flows.\n- **Create \u0026 edit organiser (`/organization/create`, `/organization/:id/edit`):**\n  - Forms capture legal form, country/state via live dropdowns (`/api/choosable-legal-forms`, `/api/choosable-countries`, `/api/choosable-states`).\n  - Use the integrated Markdown editor for rich descriptions and the Leaflet map to refine coordinates.\n  - Non-profit status is toggled via an accessible checkbox.\n- **Venues (`/organization/:id/venues` and `/organization/:id/venue/:venueId/edit`):**\n  - Reuses the shared `VenueForm.vue`, ensuring consistent layout between create and update flows.\n  - Supports optional Markdown descriptions, opened/closed dates, website URLs without protocol prefixes, and geocoding.\n- **Spaces (`/organization/:id/venue/:venueId/space/...`):**\n  - `FormSpaceView.vue` loads existing spaces when editing and submits updates through the admin API.\n- **Events:**\n  - `EventDashboardView.vue` aggregates an organiser’s events.\n  - `FormEventView.vue` guides editors through basic info, scheduling (including multiple time slots), and content details, blocking submission until all sections validate.\n  - `EventDetailsComponent.vue` fetches choosable languages from `/api/choosable-languages?lang=de` and records selections as language codes.\n- **User profile \u0026 permissions:** Accessed via `/user/profile` and `/user/permissions`, linked from the sidebar user menu. Avatar uploads hit `/api/user/:id/avatar/256` and bump a cache-busting version.\n\n### Visitor-Facing Experience\n\n- **Default layout:** `DefaultVisitorLayout.vue` provides a responsive mobile menu that slides in from the left, language and theme dropdowns, and hides login/signup buttons when a session exists.\n- **Events calendar (`/events`):**\n  - Fetches events, categories, and filters via the public API.\n  - Offers search, date range selection, type filtering, and tag shortcuts.\n  - Shows “View details” links for authenticated users.\n\n### Personalisation \u0026 Persistence\n\n- **Theme switcher:** Stored via `useThemeStore`; selections persist in `localStorage` and update the DOM `data-theme` attribute (`light`/`dark`).\n- **Organization selection memory:** `useAppStore` keeps the last chosen organiser ID to streamline event/venue creation.\n- **Locale persistence:** Vue I18n syncs with user preferences returned by the API after login.\n\n## Internationalisation\n\n- Supported locales live in `src/i18n/uranus-i18n-index.ts` with German (`de`), English (`en`), and Danish (`da`) catalogues.\n- Shared translation groups (e.g., authentication copy) are centralised for consistency.\n- Use `te('key')` in components when you must guard against missing translations.\n- To add a new language:\n  1. Extend the `LocaleKey` union.\n  2. Update the `messages` object with the new locale.\n  3. Add the locale to the `localeOptions` array in `DefaultVisitorLayout.vue`.\n\n## Theming \u0026 Styling\n\n- Global tokens and mixins reside in `src/styles/global.scss` and `src/styles/_mixins.scss`.\n- Components adopt mixins like `form-page`, `form-card`, and `form-grid` to keep layout consistent.\n- Theme switching updates CSS custom properties on the root element, allowing you to customise colours or spacing globally.\n\n## API Integration Notes\n\n- `apiFetch` (in `src/api.ts`) wraps `fetch` to:\n  - Prefix all paths with `VITE_API_URL`.\n  - Automatically set `Content-Type: application/json` unless the body is `FormData`.\n  - Inject `Authorization` headers when tokens exist.\n  - Parse JSON/text responses and throw an `ApiError` with the HTTP status.\n  - Handle 401s by posting to `/api/admin/refresh` and retrying the original request.\n- `fetchCoordinatesForAddress` leverages the OSM Nominatim service at `https://nominatim.oklabflensburg.de` to locate coordinates for map components.\n- When building new features, prefer `apiFetch` to keep token handling and error surfacing consistent across the app.\n\n## Accessibility Considerations\n\n- Forms use labelled inputs, `aria-*` attributes, and focus outlines by default. Password fields include eye toggles with appropriate labels.\n- Important feedback messages (`auth-feedback`, calendar errors, etc.) use `role=\"alert\"` / `aria-live` for screen readers.\n- The visitor layout provides an accessible mobile menu with `aria-expanded` and `aria-controls` hooks.\n\n## Troubleshooting\n\n- **Blank data / 401 errors:** Ensure `VITE_API_URL` points to a reachable API and that your credentials are valid.\n- **CORS issues in development:** Verify the backend allows the Vite dev origin or rely on the proxy specified in `vite.config.ts`.\n- **“Module 'node:test' has been externalized” error:** Importing Node-only modules inside Vue components causes Vite to externalise them. Remove those imports or wrap test helpers in environment checks.\n- **Translations missing:** Add the key to all supported locales; `te('key')` allows you to fall back gracefully while you build out translations.\n- **Leaflet map tiles not loading:** Confirm outbound network access to `nominatim.oklabflensburg.de` and the tile provider, or configure your own tile URL within `LocationMapComponent.vue`.\n\n## Next Steps\n\n- Connect the dashboard to your Uranus backend and seed sample data for organisers, venues, and events.\n- Extend the translation catalogue if you serve additional languages.\n- Add automated tests (`vitest`, `cypress`, …) to cover critical flows—no test suite ships with the repo yet.\n\nHappy organising! 🎉\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsndcds%2Furanus-dashboard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsndcds%2Furanus-dashboard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsndcds%2Furanus-dashboard/lists"}