From 7a32a1a3c650257a125acb297a4b0d1b3eefed71 Mon Sep 17 00:00:00 2001 From: Christopher Byrd Date: Wed, 23 Apr 2025 16:28:24 -0500 Subject: [PATCH 01/11] adds Vue styleguide #481 --- docs/developing/vue/arches-vue-styleguide.rst | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 docs/developing/vue/arches-vue-styleguide.rst diff --git a/docs/developing/vue/arches-vue-styleguide.rst b/docs/developing/vue/arches-vue-styleguide.rst new file mode 100644 index 0000000..e19b553 --- /dev/null +++ b/docs/developing/vue/arches-vue-styleguide.rst @@ -0,0 +1,88 @@ +###################### +Arches Vue Style Guide +###################### + +This document extends the official Vue style guide with additional conventions and best practices tailored for our projects. + +Project Structure +================= + +Naming Convention +~~~~~~~~~~~~~~~~~ + +- **Arches entity directories** + Use plural, lowercase names (e.g., `cards/`, `widgets/`, `reports/`) + +- **Vue component directories** + `PascalCase/` (e.g., `CustomComponent/`) + +- **Non-Vue component directories** + `kebab-case/` (e.g., `custom-utility/`, `custom-type/`) + +- **Vue components** + `PascalCase.vue` (e.g., `CustomComponent.vue`) + +- **Utilities** + `kebab-case.js` or `kebab-case.ts` (e.g., `custom-utility.js`) + +- **Type files** + `kebab-case.ts` (e.g., `custom-type.ts`) + + +Top-Level Structure +~~~~~~~~~~~~~~~~~~~ + +Top-level directories **must** align with Arches concepts (e.g., cards, widgets, reports) when such delineation is required. Otherwise, consolidate everything under a single app-level directory. + + +.. code-block:: shell + + # good + + src/ + └── project_name/ + ├── plugins + ├── reports/ + │ └── CustomReport/ + │ ├── components + │ └── CustomReport.vue + ├── widgets + └── types + └── utils + + # good + + src/ + └── project_name/ + ├── components/ + │ └── CustomComponent.vue + ├── CustomApplication.vue + ├── types + └── utils + + +Component Folder Hierarchy +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +At every level: + +- **Component files with sub-components** **must** reside in a folder named after the component. +- **Dependent components** **must** live in a `components/` subdirectory within their **parent component's** folder. +- **Shared components** (used by more than one parent) **must** be elevated to the `components/` directory at the level of the **highest parent component** that uses them. + +.. code-block:: shell + + # good + + src/project_name/ + ├── CustomApplication.vue + └── components/ + └── CustomDashboard/ + ├── CustomDashboard.vue + └── components/ + └── DashboardTable/ + └── DashboardTable.vue/ + └── components/ + ├── CustomHeader.vue + ├── TableSection.vue + └── UpdatedFooter.vue \ No newline at end of file From bcae1d73f9053b6845e14ac8e0026f5e23f6e959 Mon Sep 17 00:00:00 2001 From: Christopher Byrd Date: Thu, 24 Apr 2025 15:42:09 -0500 Subject: [PATCH 02/11] cbyrd update vue styleguide and arches vue integration #481 --- docs/developing/vue/arches-vue-integration.md | 425 ---------- .../developing/vue/arches-vue-integration.rst | 104 +++ docs/developing/vue/arches-vue-styleguide.rst | 761 +++++++++++++++++- 3 files changed, 841 insertions(+), 449 deletions(-) delete mode 100644 docs/developing/vue/arches-vue-integration.md create mode 100644 docs/developing/vue/arches-vue-integration.rst diff --git a/docs/developing/vue/arches-vue-integration.md b/docs/developing/vue/arches-vue-integration.md deleted file mode 100644 index 47e08e8..0000000 --- a/docs/developing/vue/arches-vue-integration.md +++ /dev/null @@ -1,425 +0,0 @@ -# Arches Vue Integration Styleguide - -## Table of Contents - -- [Purpose](#purpose) -- [Audience](#audience) -- [Basis for this Style Guide](#basis-for-this-style-guide) -- [Contributions](#contributions) -- [Integrating a Vue Component](#integrating-a-vue-component) -- [Single-Responsibility Principle and Component Decomposition](#single-responsibility-principle-and-component-decomposition) -- [Directory Structure](#directory-structure) -- [Cascading Style Sheets (CSS)](#cascading-style-sheets-css) -- [Importing Components and Component Pathing Shorthand](#importing-components-and-component-pathing-shorthand) -- [TypeScript and ESLint](#typescript-and-eslint) -- [Internationalization (i18n)](#internationalization-i18n) -- [Composition API and Single-file Components](#composition-api-and-single-file-components) -- [Testing](#testing) -- [Example Arches Vue Component Integration](#example-arches-vue-component-integration) - ---- - -## Purpose - -The purpose of this style guide is to establish a unified coding style and set of conventions that all contributors should adhere to when writing code for Arches. By following these guidelines, we aim to: - -- Improve code readability and maintainability -- Facilitate collaboration among developers -- Enhance the overall quality and consistency of Arches software, Arches projects, and Arches applications - -## Audience - -This style guide is intended for developers of all levels who contribute to Arches. Whether you are a seasoned developer or a newcomer to the project, this document will provide you with the necessary guidance to write clean, consistent, and high-quality code. - -## Basis for this Style Guide - -This style guide for Arches is built on top of the standard Vue.js and TypeScript style guides. As such, it inherits and extends the conventions and best practices outlined in those guides. - -Any coding style, formatting, or conventions not explicitly covered in this document should be referenced from the official Vue.js and TypeScript style guides. It's important to maintain consistency with these standard guidelines to ensure compatibility and familiarity for developers working with Vue.js and TypeScript projects. - -For Vue.js, you can refer to the official style guide [here](https://vuejs.org/style-guide/). Similarly, for TypeScript, you can refer to the official TypeScript style guide [here](https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html). - -Please consult these references for any conventions or guidelines not addressed in this style guide. - -## Contributions - -This style guide is a living document that evolves over time. We welcome contributions from the community to improve and expand this guide further. If you have suggestions, feedback, or would like to contribute to the style guide, please reach out to us via the [Arches Forum](https://community.archesproject.org/). - ---- - -## Integrating a Vue Component - -When integrating Vue-based views, plugins, or reports into the Arches framework, developers should utilize the `createVueApplication` function provided at `utils/create-vue-application`. This function is specifically designed to facilitate the integration of Vue components within the Arches environment, ensuring seamless compatibility and optimal performance by abstracting interactions with the i18n API and various current and future Vue plugins, such as PrimeVue. - -However, it's important to note that while the `createVueApplication` function is suitable for integrating most Vue-based components, widgets require different render states and are not yet supported. As such, developers should exercise caution when attempting to integrate widgets using this function. We hope to resolve this in the near future. - -Example: - -```js -import createVueApplication from 'utils/create-vue-application'; -import MyVueApplication from '@/MyVueApplication.vue'; - -createVueApplication(MyVueApplication).then(vueApp => { - vueApp.mount('#my-vue-application-mounting-point'); -}); -``` - -In the provided example, the createVueApplication function, imported from `utils/create-vue-application`, streamlines the integration process by handling the necessary setup and configuration steps, allowing developers to focus on building the core functionality of their Vue application. - -The `createVueApplication` function takes a Vue component (`MyVueApplication` in this case) as its argument, representing the root component of the Vue application. This component encapsulates the entire application logic and user interface. - -Once the Vue application is created using `createVueApplication`, it returns a Vue application instance (`vueApp`), which can then be further manipulated or customized as needed. In the example, the `vueApp` instance is mounted to a specific element in the DOM with the mount method, using the CSS selector `#my-vue-application-mounting-point` to identify the mounting point. - ---- - -## Single-Responsibility Principle and Component Decomposition - -In Vue development, it's crucial to adhere to the Single Responsibility Principle (SRP) and practice component decomposition to ensure that Vue components remain maintainable and scalable. The SRP dictates that each Vue component should have a single responsibility or purpose. By focusing on doing one thing and doing it well, components become easier to understand, modify, and maintain. Following the SRP leads to more modular, reusable, and testable code. - -Component decomposition involves breaking down complex Vue components into smaller, more focused units, with each unit responsible for a specific task or feature. This practice aligns with the SRP and promotes clean, maintainable codebases. - -Example: - -```vue - - - -``` - -In this example: - -- The `UserProfile` component is decomposed into three smaller components: `UserProfileHeader`, `UserProfileBio`, and `UserProfileActions`. -- Each smaller component has a specific responsibility: - - `UserProfileHeader`: Renders the user's name and email. - - `UserProfileBio`: Renders the user's bio. - - `UserProfileActions`: Renders user actions (e.g., buttons for editing the profile). -- The user reactive reference is defined using ref() within the ` - - -``` - -In this example, we import the `useGettext` function from vue3-gettext and destructure the `$gettext` method from the returned object. We then use `$gettext` to translate strings within our template, such as "Foo!" and "Bar!". The translations are managed by vue3-gettext and the `create-vue-application` component, and are dynamically loaded based on the selected locale. - -Before using internationalization features, it's important to run the following commands to extract and compile translations: - -Extract Translations: Run `npm run gettext:extract` to extract translations from the source code and generate template .pot files. -Compile Translations: Run `npm run gettext:compile` to compile translated .po files into machine-readable .json files that can be used by the application. - -For further information, please reference the [vue3-gettext documentation](https://github.com/jshmrtn/vue3-gettext) - ---- - -## Composition API and Single-file Components - -We strongly suggest utilizing the Composition API and Single-file Components for building new features or rewriting existing components into Vue. - -### Composition API - -The Composition API is a way of organizing and reusing logic within Vue components. It allows developers to encapsulate related logic into reusable composition functions, making it easier to manage complex component logic and share code between components. - - -### Single-file Components - -Single-file Components are a feature of Vue that allows developers to define templates, script, and styles in a single `.vue` file. This approach promotes a more modular and cohesive structure for Vue components, making it easier to manage component-specific logic, styles, and templates in a single file. - -### Example -Here's an example of a Single-file Component that uses the Composition API, notice the - - - - - -``` - ---- - -## Testing - -To ensure the reliability and functionality of our Vue components, we use `vitest` for our testing framework. `vitest` is a fast, modern testing framework that provides a comprehensive suite of tools for writing, running, and debugging tests. - -### Why Vitest? - -- **Speed**: `vitest` is designed to be fast, reducing the time it takes to run tests and increasing productivity. -- **Integration**: We plan on eventually migrating our frontend bundler to `vite`, and already having `vitest` in-place will ensure a smooth transition. -- **Modern Features**: `vitest` supports the latest JavaScript features, ensuring compatibility with contemporary development practices. - -### Writing Tests -**Ensure your tests are placed alongside your components, and have a `.spec.ts` suffix.** - -When writing tests for your Vue components, consider the following best practices: - -- **Isolation**: Test each component in isolation to ensure that issues can be traced back to specific units of code. -- **Coverage**: Aim for high test coverage to ensure all paths, including edge cases, are tested. -- **Readability**: Write clear and concise tests that are easy to understand and maintain. - -Here is an example of how to write your tests: - -```vue - - - - - - - -``` - -```js -// src/ExampleComponent.spec.ts - -import { describe, it, expect } from 'vitest'; -import { mount } from '@vue/test-utils'; - -import ExampleComponent from '@/ExampleComponent.vue'; - -describe('ExampleComponent', () => { - it('renders correctly', () => { - const wrapper = mount(ExampleComponent); - expect(wrapper.exists()).toBeTruthy(); - }); - - it('renders h1 element with correct text', () => { - const wrapper = mount(ExampleComponent); - expect(wrapper.find('h1').text()).toBe('Hello from the template!'); - }); - - it('applies scoped styles to h1 element', () => { - const wrapper = mount(ExampleComponent); - const h1 = wrapper.find('h1'); - expect(h1.classes()).toContain('header'); - }); -}); - -``` - -### Running tests - -To run your tests, use the vitest command in your terminal: - -```bash -npm run vitest -``` - -**By following this documentation, you can set up and maintain comprehensive unit and component testing that catches bugs early and improves code quality. For further details, refer to the [Vitest documentation](https://vitest.dev/).** - ---- - -## Example Arches Vue Component Integration - -Below is an example of creating a new plugin for Arches. This example includes import patterns, TypeScript patterns, internationalization, the composition API, single-file components, and Vue/Knockout integration - -```js -// media/js/views/components/plugins/my-plugin.js - -import ko from 'knockout'; -import MyPlugin from '@/plugins/MyPlugin.vue'; -import createVueApplication from 'utils/create-vue-application'; -import MyPluginTemplate from 'templates/views/components/plugins/my-plugin.htm'; - - -ko.components.register('my-plugin', { - viewModel: function() { - createVueApplication(MyPlugin).then(vueApp => { - vueApp.mount('#my-plugin-mounting-point'); - }); - }, - template: MyPluginTemplate, -}); - -``` - -```htm -// templates/views/components/plugins/my-plugin.htm - -
-``` - -```vue -// src/plugins/MyPlugin.vue - - - - - - -``` diff --git a/docs/developing/vue/arches-vue-integration.rst b/docs/developing/vue/arches-vue-integration.rst new file mode 100644 index 0000000..296901e --- /dev/null +++ b/docs/developing/vue/arches-vue-integration.rst @@ -0,0 +1,104 @@ +Arches Vue Integration Guide +============================ + +This guide explains how to embed a Vue 3 application into Arches using the +``createVueApplication`` helper. This function bootstraps your app with: + +- Arches i18n (via vue3-gettext) +- PrimeVue + default theme +- Common services (confirmation, dialogs, toasts) +- Shared directives (tooltips, focus trap, scroll animations) +- Automatic dark-mode theme switching + +Supported Use Cases +~~~~~~~~~~~~~~~~~~~ + +- **Full-page views** (reports, dashboards) +- **Standalone plugins** +- **Knockout-embedded components** + +Not yet supported: Arches “widgets” that require specialized render context. + +Quick Start +~~~~~~~~~~~ + +1. **Import** your root component and the helper: + + .. code-block:: js + + import createVueApplication from 'utils/create-vue-application' + import MyVueApp from '@/my_project/MyVueApp.vue' + +2. **Initialize** and **mount**: + + .. code-block:: js + + createVueApplication(MyVueApp) + .then(app => { + // Optional: register extra plugins or globalProperties here + app.mount('#my-vue-mount-point'); + }) + .catch(err => { + console.error('Vue integration failed:', err); + }) + +3. **Ensure** your Arches template contains the mount point: + + .. code-block:: html + + +
+ +Knockout Integration Example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: js + + // src/my_project/MyPlugin.vue + + + + + + + +.. code-block:: js + + // media/js/views/components/plugins/my-plugin.js + + import ko from 'knockout'; + import createVueApplication from 'utils/create-vue-application'; + import MyPlugin from '@/my_project/MyPlugin.vue'; + import template from 'templates/views/components/plugins/my-plugin.htm'; + + ko.components.register('my-plugin', { + viewModel: function() { + createVueApplication(MyPlugin) + .then(vueApp => vueApp.mount('#my-plugin-mount')) + .catch(console.error) + }, + template: template + }); + +.. code-block:: html + + + +
\ No newline at end of file diff --git a/docs/developing/vue/arches-vue-styleguide.rst b/docs/developing/vue/arches-vue-styleguide.rst index e19b553..c9084ac 100644 --- a/docs/developing/vue/arches-vue-styleguide.rst +++ b/docs/developing/vue/arches-vue-styleguide.rst @@ -2,32 +2,64 @@ Arches Vue Style Guide ###################### -This document extends the official Vue style guide with additional conventions and best practices tailored for our projects. +This document extends and enhances the official Vue style guide, providing additional conventions and best practices tailored specifically for our Arches projects. + +Refer to the `official Vue style guide `_ for baseline standards. + +Purpose +======= + +The purpose of this style guide is to establish a unified coding style and set of conventions that all contributors should adhere to when writing code for Arches. By following these guidelines, we aim to: + +- Improve code readability and maintainability +- Facilitate collaboration among developers +- Enhance the overall quality and consistency of Arches software, Arches projects, and Arches applications + +Basis for Style Guide +===================== + +This style guide for Arches is built on top of the standard Vue.js and TypeScript style guides. As such, it inherits and extends the conventions and best practices outlined in those guides. + +Any coding style, formatting, or conventions not explicitly covered in this document should be referenced from the official Vue.js and TypeScript style guides. It's important to maintain consistency with these standard guidelines to ensure compatibility and familiarity for developers working with Vue.js and TypeScript projects. + +For Vue.js, you can refer to the `official Vue style guide `_. + +Similarly, for TypeScript, you can refer to the `official TypeScript style guide `_. + +Contributions +============= + +This style guide is a living document that evolves over time. We welcome contributions from the community to improve and expand this guide further. If you have suggestions, feedback, or would like to contribute to the style guide, please reach out to us via the `Arches Forum `_. Project Structure ================= -Naming Convention -~~~~~~~~~~~~~~~~~ - -- **Arches entity directories** - Use plural, lowercase names (e.g., `cards/`, `widgets/`, `reports/`) +Naming Conventions +~~~~~~~~~~~~~~~~~~ -- **Vue component directories** - `PascalCase/` (e.g., `CustomComponent/`) +- **Arches entity directories**: + Use plural, lowercase names to reflect domain concepts. + e.g. ``cards/``, ``widgets/``, ``reports/`` -- **Non-Vue component directories** - `kebab-case/` (e.g., `custom-utility/`, `custom-type/`) +- **Vue component directories**: + One folder per component, named in PascalCase. + e.g. ``CustomComponent/`` -- **Vue components** - `PascalCase.vue` (e.g., `CustomComponent.vue`) +- **Non-Vue component directories**: + Utility or helper folders in kebab-case. + e.g. ``custom-utility/``, ``date-utils/`` -- **Utilities** - `kebab-case.js` or `kebab-case.ts` (e.g., `custom-utility.js`) +- **Vue components**: + File names in PascalCase with a ``.vue`` extension. + e.g. ``UserCard.vue``, ``MapViewer.vue`` -- **Type files** - `kebab-case.ts` (e.g., `custom-type.ts`) +- **Utilities & helpers**: + Use kebab-case, file extension ``.js`` or ``.ts``. + e.g. ``fetch-api.ts``, ``format-date.js`` +- **Type files**: + Single-purpose type definitions in kebab-case, ``.ts``. + e.g. ``user-profile.ts``, ``map-types.ts`` Top-Level Structure ~~~~~~~~~~~~~~~~~~~ @@ -37,8 +69,6 @@ Top-level directories **must** align with Arches concepts (e.g., cards, widgets, .. code-block:: shell - # good - src/ └── project_name/ ├── plugins @@ -48,9 +78,9 @@ Top-level directories **must** align with Arches concepts (e.g., cards, widgets, │ └── CustomReport.vue ├── widgets └── types - └── utils + └── utils.ts - # good +.. code-block:: shell src/ └── project_name/ @@ -58,7 +88,7 @@ Top-level directories **must** align with Arches concepts (e.g., cards, widgets, │ └── CustomComponent.vue ├── CustomApplication.vue ├── types - └── utils + └── utils.ts Component Folder Hierarchy @@ -72,8 +102,6 @@ At every level: .. code-block:: shell - # good - src/project_name/ ├── CustomApplication.vue └── components/ @@ -85,4 +113,689 @@ At every level: └── components/ ├── CustomHeader.vue ├── TableSection.vue - └── UpdatedFooter.vue \ No newline at end of file + └── UpdatedFooter.vue + + +Component Structure +=================== + +Single-File Components +~~~~~~~~~~~~~~~~~~~~~~ + +Single-File Components (SFCs) are the preferred way to define Vue components. They encapsulate the template, script, and style in a single file, making it easier to manage and understand the component's structure. + +.. code-block:: js + + + + + + + +Component Decomposition +~~~~~~~~~~~~~~~~~~~~~~~ + +Components should be decomposed into smaller, reusable components whenever possible. This promotes reusability and maintainability. Aim for a single responsibility per component. + +.. code-block:: shell + + widgets/ + └── CustomWidget/ + ├── components/ + │ ├── CustomWidgetEditor.vue + │ └── CustomWidgetViewer.vue + └── CustomWidget.vue + +Passing Data +~~~~~~~~~~~~ + +- **Fetch Proximity**: + Fetch data in the component that actually renders it—don't lift network calls higher than needed. + +.. code-block:: js + + + + + + + + + + + + + + + + + + + + + + +- **Primitives First**: + Pass simple values (strings, numbers, booleans, small arrays/objects) instead of entire model objects whenever possible. + +.. code-block:: html + + + + + + + +- **Derived State**: + Compute any summaries or transformations in the consumer component and pass those primitives down. + +.. code-block:: js + + + + + + + + + + + +- **Event Emission**: + Emit semantic events (kebab-case) with typed payloads: + +.. code-block:: js + + + +- **Slots**: + Use scoped slots for maximum flexibility; name them clearly + +.. code-block:: html + + + + + + + +The ` + +Declaration Order +~~~~~~~~~~~~~~~~~ + +Within your ` + + +The `