Skip to content

Commit

Permalink
pkp/pkp-lib#9527 Add ActivityIndicatorPopup, refine guide (#321)
Browse files Browse the repository at this point in the history
* pkp/pkp-lib#9527 Add ActivityIndicatorPopup, refine guide

* pkp/pkp-lib#9527 Another attempt to stabilize StatsPage

* pkp/pkp-lib#9527 Fix ActivityIndicatorPopup story
  • Loading branch information
jardakotesovec authored Feb 1, 2024
1 parent a6a3856 commit 92ed3c1
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 41 deletions.
21 changes: 21 additions & 0 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,27 @@ const preview = {
},
direction: 'ltr',
options: {
storySort: {
order: [
'Guide',
[
'Page Architecture',
'API Interactions',
'Style',
['Introduction'],
'Vue Composition API',
'Pinia Store',
'Translation',
'Technical Roadmap',
],
'Composables',
'Components',
'Forms',
'ListPanel',
'Pages',
],
},

/*storySort: (a, b) => {
if (a.id.includes('introduction--docs')) {
return -1;
Expand Down
11 changes: 11 additions & 0 deletions src/components/ActivityIndicatorPopup/ActivityIndicatorPopup.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {Primary, Controls, Stories, Meta, Description} from '@storybook/blocks';

import * as ActivityIndicatorPopupStories from './ActivityIndicatorPopup.stories.js';

<Meta of={ActivityIndicatorPopupStories} />

# ActivityIndicatorPopup

<Primary />
<Controls />
<Stories />
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import ActivityIndicatorPopup from './ActivityIndicatorPopup.vue';

export default {
title: 'Components/ActivityIndicatorPopup',
component: ActivityIndicatorPopup,
render: (args) => ({
components: {ActivityIndicatorPopup},
setup() {
return {args};
},
template:
'<ActivityIndicatorPopup v-bind="args">{{args.slot}}</ActivityIndicatorPopup>',
}),
decorators: [
() => ({
template:
'<div style="text-align:center; width: 400px; height: 300px"><story/></div>',
}),
],
};

export const Default = {
args: {},
};
2 changes: 1 addition & 1 deletion src/components/Container/StatsPage.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ const PublicationStatsPageWithDataAndTemplate = {
data() {
const fakeToday = 'Tue Dec 19 2023 16:00:27 GMT+0100';
const dateEndMax = new Date(
new Date().setDate(new Date(fakeToday).getDate() - 1),
new Date(fakeToday).setDate(new Date(fakeToday).getDate() - 1),
);

const startDate = new Date(fakeToday);
Expand Down
6 changes: 3 additions & 3 deletions src/docs/guide/APIInteractions.mdx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {Meta} from '@storybook/blocks';

<Meta title="Guide/API interactions" />
<Meta title="Guide/API Interactions" />

# API Interactions

OJS/OMP/OPS already have substantial [Rest API interface](https://docs.pkp.sfu.ca/dev/api/ojs/3.4) well covered with documentation.
OJS/OMP/OPS already have substantial [Rest API interface](https://docs.pkp.sfu.ca/dev/api/ojs/3.4), well covered with documentation.

To interact with the API there are handy composables to simplify the process.
To interact with the API there are handy composables available to simplify the process.

## Compose URL

Expand Down
12 changes: 5 additions & 7 deletions src/docs/guide/CompositionAPI.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@ In version 3.5 we migrated our ui-library to new Vue3 version, which introduces

## Composition API

Composition API builds on exactly same principles as the Options API that we are used to from Vue 2. State management still consist of **state** , **computed** properties and **methods** that are updating the **state**. Only the syntax is different.
Composition API builds on exactly same principles as the Options API that we are used to from Vue 2. State management still consist of **state** , **computed** properties and **methods** that are updating the **state**. Only the syntax is more flexible.

It might take bit getting used to to new syntax, but it will reward us is with significantly better flexibility compared to mixins, which comes very handy in complex application like OJS/OPS/OMP.
It might take bit getting used to to new syntax, but it will reward us is with significantly better flexibility compared to mixins, which comes very handy in complex application like we have.

Best learning source is Vue.js [documentation](https://vuejs.org/guide/introduction.html), where you can easily explore syntax differences between options API and composition API.

We follow Vue.js [recommendation](https://vuejs.org/guide/essentials/reactivity-fundamentals#limitations-of-reactive) to use exclusively `ref` to define reactive state and avoiding `reactive` API due its limits.
Best learning source is Vue.js [documentation](https://vuejs.org/guide/introduction.html), where you can easily explore syntax differences between Options API and Composition API.

## Composables

Expand All @@ -24,13 +22,13 @@ Composables are replacements for mixins. More details to come about the composab

Even though it seems that Composition API is lacking organizational structure, it actually gives possibility of organise the code by individual features. Every feature usually consist of some state, computed properties and methods. Good example is `SubmissionsPageStore.js`.

Also it should be easy to quickly understand how the Page works when reading the business logic in store. If its too long or/and contains long functions its indication that some of the features should be moved to individual feature composables. These than can be imported to the store and connected with rest of the features in the store. This helps to get good understanding how things works together and its always possible to dive in into details in individual composables if needed.
Also it should be easy to quickly understand how the Page works when reading the business logic in store. If its too long or/and contains long functions its indication that some of the features should be moved to individual feature composables. These can be imported to the store and connected with rest of the features in the store. This helps to get good understanding how things works together and its always possible to dive in into details in individual composables if needed.

## Refs vs reactive

If you want to dive deep and understand all details between using `ref()` vs `reactive()` when creating reactive state in Composable API, you can check out [official documentation](https://vuejs.org/guide/essentials/reactivity-fundamentals) or detailed [blog post](https://mokkapps.de/blog/ref-vs-reactive-what-to-choose-using-vue-3-composition-api).

But its not really necessary, as we follow [official recommendation](https://vuejs.org/guide/essentials/reactivity-fundamentals#limitations-of-reactive), which aligns with my personal experience as well, which is just always use `ref()` when defining state..
But its not really necessary, as we follow [official recommendation](https://vuejs.org/guide/essentials/reactivity-fundamentals#limitations-of-reactive), which aligns with my personal experience as well, which is just always use `ref()` when defining state.

```javascript
import {ref} from 'vue';
Expand Down
17 changes: 6 additions & 11 deletions src/docs/guide/DesignSystem/Introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,13 @@ import {Meta} from '@storybook/blocks';

Going forward we are adopting [tailwindcss](https://tailwindcss.com) framework for styling our Admin interface.

For **migration path** and **motivation** details checkout [Technical Roadmap](../?path=/docs/guide-technical-roadmap--docs#tailwindcss-35).

Example component where TailwindCSS is used is `ActivityIndicatorPopup.vue`.

## Recomendations

- Highly recommend to use [tailwindcss cheatsheet](https://nerdcave.com/tailwind-cheat-sheet) to quickly find classes you need, especially if you are already familiar with css.
- If you don't have much experience with writing CSS - tailwind should easy out that experience.
- If you don't have much experience with writing CSS - tailwind should easy out that experience. As it provides useful subset of styling primitives, which is easier to choose from.
- Check following pages for properties that are we hand-picked to fit our styling - [colors](../?path=/docs/guide-style-colors--docs), [fonts](../?path=/docs/guide-style-fonts--docs), [shadows](../?path=/docs/guide-style-shadows--docs) and [radiuses](../?path=/docs/guide-style-radius--docs).
- All other properties comes from tailwind defaults. Therefore you can directly use the values you find in [cheatsheet](https://nerdcave.com/tailwind-cheat-sheet) or in [tailwind documentation](https://tailwindcss.com/docs/utility-first).

## Migration path

- Using tailwindCSS make sense for building new components or when doing significant changes of existing components.

## Motivation

- Main motivation is to have good primitives to create consistent design, without creating own solution. TailwindCSS does that for us.
- TailwindCSS is easy to configure to adjust to our design (fonts, colors), while providing great defaults in other areas (margins, paddings)
- All other properties comes from TailwindCSS defaults. Therefore you can directly use the values you find in [cheatsheet](https://nerdcave.com/tailwind-cheat-sheet) or in [tailwind documentation](https://tailwindcss.com/docs/utility-first).
8 changes: 4 additions & 4 deletions src/docs/guide/PageArchitecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ To [simplify](?path=/docs/guide-technical-roadmap--docs#vuejs--smarty---vuejs-35

## State management

For managing Page business logic we are leveraging Pinia store. Main reason why we want to use Pinia stores instead of just managing state directly in the Page component, is that behind the scene its very extensible and plugin friendly. You can check out more detailed break down in our [Technical Roadmap](?path=/docs/guide-technical-roadmap--docs#pinia-stores-35). General UI components still contains interaction logic directly in component.
For managing Page business logic we are leveraging [Pinia store](../?path=/docs/guide-pinia-store--docs). Main reason why we want to use Pinia stores instead of just managing state directly in the Page component, is that behind the scene its very extensible and plugin friendly. You can check out more detailed break down in our [Technical Roadmap](?path=/docs/guide-technical-roadmap--docs#pinia-stores-35). General UI components still contains interaction logic directly in component.

To understand how the Components should interact with the **Component Pinia Store**, which is our simple extension of the Pinia Store, check out dedicated [page](http://localhost:6006/?path=/docs/guide-pinia-store--docs#component-pinia-store) for Pinia store.

Expand All @@ -30,12 +30,12 @@ To understand how the Components should interact with the **Component Pinia Stor

## Server side configuration

On initial page load, there is still opportunity to pass JS object from PHP to the Vue.js. Best is to express individual items as props, so it can be easily displayed in storybook and its well documented.
On initial page load, there is still opportunity to pass JSON object from PHP to the Vue.js. Best is to express individual items as props, so it can be easily displayed in storybook and its well documented.

This might include things like:

- Form structure configuration, as we do configure forms on PHP side
- Any configuration which needs to be passed just once on page load
- Form structure configuration, as we do configure forms on PHP side.
- Any configuration, which needs to be passed just once on page load.

## Styling

Expand Down
4 changes: 2 additions & 2 deletions src/docs/guide/PiniaStores.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ For more details, why Pinia store is being adopted from 3.5, check out our [Tech

## Pinia Store Gotchas

Intentional as first chapter to safe you some time.
Intentionally as first chapter to safe you some time.

When destructing state from pinia store, it requires to use helpers to not loose reactivity. Alternatively using the store directly without destructing is also good practice. Check example in [Pinia documentation](https://pinia.vuejs.org/core-concepts/#Destructuring-from-a-Store).

Expand All @@ -21,7 +21,7 @@ Compared to general pinia store, its extended with following features:
- **Passing initial data**: It allows to pass inititial data when needed. That often might be configuration passed to the **Page** from PHP backend. Or some props being passed to **Complex Modal** or **Self-Contained Component**. Important to note that only the first component (its top in hirearchy) is passing the configuration. Any other child component thats connecting to the store connects to it without passing the init state as its already been initialised.
- **Following Component Lifecycle**: It gets initialised when its called in first component. It tracks mount/unmount events and when all components using the store are unmounted it deletes its state. This is particularly useful when managing **Complex Modal** as anytime its closed - its state will be removed and it gets initialised next time the modal is opened with new props.

These improvements are intended to make the developer experience very much the same as if we would define the business logic directly in the component. But still getting [benefits](<(?path=/docs/guide-technical-roadmap--docs#pinia-stores-35)>) that comes from using Pinia store.
These improvements are intended to make the developer experience very much the same as if we would define the business logic directly in the component. But still getting [benefits](../?path=/docs/guide-technical-roadmap--docs#pinia-stores-35) that comes from using Pinia store.

Lets look at example how the component interacts with the store. More advanced example can be found in [ExamplePage](?path=/docs/pages-example--docs).

Expand Down
25 changes: 12 additions & 13 deletions src/docs/guide/TechnicalRoadmap.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import {Meta} from '@storybook/blocks';

<Meta title="Guide/Technical Roadmap" />

# Admin Frontend Technical Roadmap
# Admin UI Technical Roadmap

## Introduction

Modern web is evolving rapidly. And long term projects like OJS/OPS/OMP has to be creative in tackling technical debt, so it can keep delivering new/improved functionality, while modernising underneath.

As title suggests, goal is to cover technical roadmap for the admin interface. Later it will be expanded also by plans for reader interface, where the considerations might differ.
As title suggests, goal is to cover technical roadmap for the admin user interface. Later it will be expanded also by plans for reader interface, where the considerations might differ.

## Smarty

Expand All @@ -18,7 +18,7 @@ It all started as typical server side rendered Smarty templates with custom cont

And there are still significant portion of the interface driven by this stack.

## Smarty -> Vue.js + Smarty (3.3??)
## Smarty -> Vue.js + Smarty (3.3)

Around year 2018 team decided to start leveraging Vue.js framework. At that time it was clear that frameworks like React or Vue.js are much more capable in handling complex user interactions compared to jQuery.

Expand All @@ -34,10 +34,9 @@ Even though it was significant benefit to keep Smarty around at first. It also c

- Combining Smarty and Vue.js syntax requires to be familiar with both of them and some Vue.js syntax needs to be escaped to work within Smarty template.
- Different content escaping mechanism, which makes easier to make mistake (XSS attacks).
- Developer has to decide what to render in Smarty and what in Vue.js.
- Developer has to decide, what to render in Smarty and what in Vue.js.
- Difficult to develop and test pages in separation (Storybook).
- Sometime difficult to identify, which Smarty template is interpreted by which Vue.js Page component, as these lives in different folder structure.
- Security risk with injecting Vue.js syntax to Smarty template.
- There is relatively small performance penalty, when Vue.js is compiling the template runtime in browser (which was required to be able to consume smarty output), rather than in build time.

Overall idea is that embracing client side rendering and exchanging only JSON data with backend should make overall architecture easier to grasp and maintain.
Expand All @@ -46,13 +45,13 @@ There is only couple of things, where Vue.js was lacking compared to Smarty, mai

### Migration path

Having consistent Page architecture would make significantly easier to orient everyone and migrating from smarty templates that are used for Pages should be relatively low effort. We will aim to execute some migrations during 3.5 and 3.6 dev cycle.
Having consistent Page architecture would make significantly easier to orient everyone. Migrating from smarty templates that are used for Pages should be relatively low effort. We will aim to execute some migrations during 3.5 and 3.6 dev cycle.

## Translation (3.5)

We are moving from passing translations via Props to individual components to system, where all uses of translation keys are automatically identified and needed translations are exposed to Vue.js components.
We are moving from passing translations via Props to individual components to mechanism, where all uses of translation keys are automatically identified and needed translations are exposed to Vue.js components.

For more details check Translation guide.
For more details check [Translation guide](../?path=/docs/guide-translation--docs).

### Migration path

Expand All @@ -64,11 +63,11 @@ Details are being worked out and will be covered in detail bit later in 3.5 deve

## Vue3 Composition API (3.5)

Upgrading our ui library to Vue3 opened new posibilities. Vue3 introduced composition API, which is now recommended API. Even though its very much the same as Option API under the hood the syntax is significantly different and might be intimidating first. Eventually we decided to adopt it and here are some factors that encouraged that decision.
Upgrading our ui library to Vue3 opened new posibilities. Vue3 introduced [composition API](../?path=/docs/guide-vue-composition-api--docs), which is now recommended API. Even though its very much the same as Option API under the hood the syntax is significantly different and might be intimidating first. Eventually we decided to adopt it and here are some factors that encouraged that decision.

- Some of our admin interfaces are quite complex and composition API makes easier to split these to smaller features and than combine them as needed.
- Composition API works lot better with type systems, like Typescript is. We have not decided to adopt such type system, but its good to have these doors opened in future.
- Even though Options API will be supported long term, Vue.js community is leaning towards new composition API. As result in future there likely will be stronger ecosystem and documentation for composition API.
- Composition API works lot better with type systems, like Typescript. We have not decided to adopt such type system, but its good to have these doors opened in future.
- Even though Options API will be supported long term, Vue.js community is leaning towards new composition API. As result in future there likely will be stronger ecosystem and documentation for composition API. We can see evidence of that in big projects like [Nuxt 3](https://nuxt.com/docs/api/composables/use-app-config) or [vueuse.org](https://vueuse.org/)
- Composition API introduced composables as replacement for mixins that are lot more flexible and easier to test. You can find several composables in our storybook already that should make easier to build new functionality.

### Migration path
Expand All @@ -77,7 +76,7 @@ Options API should be supported very long term therefore migrating individual co

## Pinia stores (3.5)

Business logic has been mostly placed within top component, which we usually refer as **Page** component. And that works great, only difference we want to do is that we now connect the **Page** component to its own [Pinia store](https://pinia.vuejs.org) and use the same Composition API as we would use directly in component.
Business logic has been mostly placed within top component, which we usually refer as **Page** component. And that works great, only difference we want to do is that we now connect the **Page** component to its own [Pinia store](http://localhost:6007/?path=/docs/guide-pinia-store--docs#component-pinia-store) and use the same Composition API as we would use directly in component.

And just from moving the business logic from page component to its store we get some important benefits:

Expand All @@ -93,7 +92,7 @@ Given that there are some limitations when using Options API in Pinia (like miss

## TailwindCSS (3.5)

We have been also revisiting our approach to CSS styling. Having now UI/UX designer on the team is pushing our interfaces to new hights. And having CSS framework which is good in capturing design system became essential.
We have been also revisiting our approach to CSS styling. Having now UI/UX designer on the team is pushing our interfaces to new hights. And having CSS framework which is good in capturing design system became important.

Here are the factors that encouraged us to adopt TailwindCSS at the end:

Expand Down

0 comments on commit 92ed3c1

Please sign in to comment.