Coder Social home page Coder Social logo

migtools / lib-ui Goto Github PK

View Code? Open in Web Editor NEW
1.0 7.0 9.0 22.19 MB

Reusable React components, hooks, and TypeScript modules shared between migration UI projects

Home Page: https://migtools.github.io/lib-ui/

License: Apache License 2.0

JavaScript 3.01% TypeScript 72.66% MDX 24.33%
hacktoberfest

lib-ui's Introduction

@migtools/lib-ui

Reusable React components, hooks, and TypeScript modules shared between migtools UI projects.

This library exists as a place to store and reuse abstractions that are useful for multiple UI projects, and are either not available in PatternFly yet or not covered by PatternFly's scope.

The React components in this library are compositions and extensions of patternfly-react components, and we should avoid duplicating components that are available there.

semantic-release

Documentation and examples (Storybook): http://migtools.github.io/lib-ui/

Usage

Install from npm

In your app repo, install the library as a normal npm dependency:

yarn add @migtools/lib-ui
# or:
npm install @migtools/lib-ui

Install peer dependencies

This package has React and PatternFly packages as peer dependencies, which are not included in the library bundle. That way, your app can also depend on them directly without bundling them twice.

When you install @migtools/lib-ui, you should get a warning from your package manager telling you which versions to install. Make sure you have compatible versions as dependencies in your app.

Note: The axios peer dependency is only required if you are using modules/kube-client.

Optional: Install from local source

If you need to use an unpublished branch (such as when developing an app PR and a lib-ui PR at the same time), you can reference the dependency directly from your local disk by using yarn link or npm link.

First, clone the lib-ui repo somewhere, cd to that clone, install and build the package, and run yarn link. Unfortunately, you then need to delete node_modules in the lib-ui directory so the app's builder doesn't pick it up.

git clone https://github.com/migtools/lib-ui.git migtools-lib-ui
cd migtools-lib-ui
yarn install
yarn build
yarn link
rm -rf node_modules

Then, cd to the app you're developing, and run yarn link @migtools/lib-ui to install the linked version instead of the npm version.

cd ../virt-ui
yarn link @migtools/lib-ui

If you make a change in your local lib-ui clone, reinstall its dependencies, rebuild, and remove them. Your app should then pick up the changes.

cd ../migtools-lib-ui
yarn install
yarn build
rm -rf node_modules

When you're done, in your app repo, unlink the package and force a reinstall of the npm version:

cd ../virt-ui
yarn unlink @migtools/lib-ui
yarn install --force

Then in the lib-ui directory, run yarn unlink if you no longer want it available for linking.

Use it!

In your JS/TS, Import named modules from the library, just like PatternFly:

import { MyComponent, useSomeHook } from '@migtools/lib-ui';

Development

Prerequisites

Quick-start

Clone and install dependencies:

git clone https://github.com/migtools/lib-ui.git migtools-lib-ui
cd migtools-lib-ui
yarn install

Run the Storybook dev server (examples and docs) at http://localhost:6006:

yarn storybook

Scripts

To run the type-checker, linter and unit tests:

yarn type-check
yarn lint [--fix]
yarn test [--watch]

Prettier code formatting is enforced by ESLint. To run Prettier and format your code (do this before committing if you don't run Prettier in your editor):

yarn format

To run a production build using Rollup (outputs to ./dist):

yarn build

To export the Storybook docs as a static site (outputs to ./storybook-static):

yarn storybook:export

Triggering an npm release

This project uses semantic-release via GitHub Actions to automate its npm releases. When a commit is pushed to main, it is checked for specific key words in the commit message to decide whether a release needs to be made, and whether it will be a minor or major version bump. Your commit message will also be added and categorized in the release notes.

To assist in formatting commit messages correctly for this purpose, the repo is set up for use with Commitizen, which provides a CLI for guided commit messages.

To make a commit that should trigger a release:

First, git add any changes you want to commit, then:

yarn commit

Follow the prompts based on the scope of your commit. Note: This will generate a message for an individual commit, but since we use squash-and-merge, what matters is your PR title. If your PR contains multiple commits, please make sure the PR title itself matches the expected format. See our PR template for more details.

File Structure

Components live in src/components/MyComponent/ directories, which should each contain:

  • MyComponent.tsx - component source and type interfaces (types can be their own file if they are verbose enough)
  • MyComponent.scss - any custom styles not covered by PatternFly, we should avoid these when possible
  • MyComponent.stories.mdx - define your Storybook stories (examples and docs) for your component. We are using the MDX story format. The title prop of your story's <Meta> defines where it appears in the Storybook nav.
  • Optional: MyComponent.stories.tsx - if you need to use TypeScript in the body of your MDX stories, you'll need to define them in a TypeScript file and import them into your MDX file. See existing stories for examples.
  • MyComponent.test.tsx - unit tests using jest and react-testing-library
  • index.ts - define your exports for the component directory

When you add a new component, be sure to also export it at the top level (src/index.ts).

Hooks follow the same structure, but they live under src/hooks/.

lib-ui's People

Contributors

dependabot[bot] avatar gildub avatar ibolton336 avatar mturley avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

lib-ui's Issues

Remove mig-ui specific code from kube-client

I noticed in #67 that there's some stuff in the kube-client module that is specific to mig-ui, and not needed in e.g. forklift-ui. For example, the discovery service stuff. We should figure out how to make kube-client more generic without breaking mig-ui.

Add support for InputGroup contents to ValidatedTextInput

For kubev2v/forklift-ui#468, we needed to add a show/hide button attached to the password input fields by wrapping the TextInput in an InputGroup. Because ValidatedTextInput renders its own FormGroup internally, it doesn't give us the ability to customize the JSX around the inner TextInput, so I'm having to duplicate a version of ValidatedTextInput in forklift-ui temporarily.

After this issue is addressed, we should refactor forklift-ui's ValidatedPasswordInput component to use the new functionality, and possibly bring that component in to lib-ui as well.

Archive/retire the `@migtools/lib-ui` package and repo

Nicole from PF reached out to ask about the lib-ui package and how it will impact efforts to upgrade apps using it to PF5/PF6/etc. We determined that lib-ui has outlived its usefulness now that Konveyor is focused on a single UI, and all of the non-tackle2-related usage is legacy code that either does not matter or could easily remove/replace lib-ui.

To close this issue we need to archive the repo and deprecate the package, evaluate the effort required to remove it from all projects currently using it and do so. In some cases it may be as simple as removing unused code, and in others we may need to temporarily copy-paste some of the lib-ui code into product repos. Note that a good chunk of the lib-ui exports are being moved to https://github.com/patternfly-labs/react-table-batteries as well.

Move StatusConditions component from forklift-ui for reuse in MTC

The StatusCondition component in forklift-ui (https://github.com/konveyor/forklift-ui/blob/main/src/app/common/components/StatusCondition.tsx) should be cleaned up and moved here. It's almost generic enough already, but some of the helper function logic is a little redundant and arbitrary in places. If we make it truly be able to handle a generic set of status conditions on any CR, it could be a very useful component.

I think the main pain point is the mapping of condition severities/types to colors/icons. In forklift, there isn't a perfect mapping and we need to make some assumptions that may not match the behavior of other apps. We could improve that default logic but maybe also add a way of passing your own getStatusType function (given a condition object, which icon should we use) in case apps need to override it.

Screen Shot 2021-01-19 at 11 47 27 AM

useFormState: `isValid` should be false when fields first render instead of being true until first blur

There is a strange behavior of form fields in useFormState that was implemented to ease the display of validation errors, but has been causing some strange issues when writing logic based on the isValid property.

Currently, when fields first render, the field-level isValid properties are true even if the value is blank/invalid. Only the form-level isValid is false. When the fields are blurred, only then are they validated and isValid becomes false if errors need to be shown. This is done so that errors won't appear right away (we don't want to bombard the user with errors right when they open the form, only when they blur a field with an invalid value) without the consumer having to write logic based on isTouched for the display of errors.

I am reconsidering that decision, and I think we should instead have isValid always be accurate (validate fields on first render) and rely on the consumer to use isTouched to determine if they should show errors. This is slightly more boilerplate, but everything is more explicit and properties more clearly mean what they say.

THIS IS A BREAKING CHANGE. Apps consuming useFormState will have to add isTouched conditions in places they display validation errors, or errors will start appearing on first load of the forms.

ValidatedTextInput: automatically default label to the label in the field's yup schema

Currently, to get nice-looking validation errors we have to repeat all our field labels in two places: in the schema and on the form field itself.

Looking at the TS types for yup, we should be able to grab the label set in the schema's label() method by looking at schema.spec.label: https://github.com/jquense/yup/blob/master/src/schema.ts#L42

We can probably use this in ValidatedTextInput to automatically provide a default for the label prop so it will render the schema's label if the consumer doesn't pass one in.

useTableSortState: add support for identifying columns by string keys instead of numeric indexes?

In #73, the new useTableSortState relies on columnIndex to identify which column is being sorted on. This is fine for now because it's what the PatternFly table expects, but there is an upcoming feature in PF to support dragging/reordering table columns. When that lands, it will be annoying for the consumer to have to shift around their numeric indexes to keep the sort state accurate. If we instead track the active column by a string id (which will still need to be mapped to a numeric order to support the legacy table) the hook will be more future-proof.

I made a few attempts at this in 44f47c6 and 04eeb24 but I couldn't get the TS types quite right. It's a little awkward because we already support alternate signatures requiring either getSortValues or compareFn, and this will require a columnKeys param that when present changes the signature of setSortColumnIndex to take a key, getSortValues to return a key/value pair instead of an array, and compareFn to take a key instead of an index for the active column.

Incidentally, in this attempt I learned something interesting about TypeScript: an array is assignable to Record<number, T>! So if we have a generic type param ColumnKey that can either be a union of strings or a number, we can have getSortValues require a return of Record<ColumnKey, number | string | boolean> and it will accept either an object or an array happily depending on what ColumnKey resolves to. Pretty neat, although maybe overkill.

An alternate solution to this crazy hybrid approach would be to always require columnKeys even if we are using numeric column indexes everywhere else, and then the consumer just needs to translate indexes to keys whenever updating the sort. We could do this automatically in PF usage with tableSortProps though.

I may be overthinking all of this.

Replace enums in props with union types

This will be a breaking change, and it's just a code cleanliness thing, but I think it'd be better to get it in sooner rather than later. Based on a discussion with @gildub a while back where he shared this article with me: https://blog.logrocket.com/put-the-typescript-enums-and-booleans-away/

It is a pain to have to import the enums used in props for certain components rather than just be able to let IntelliSense tell yo which strings are valid. TS can prevent invalid values of string types if the valid values are provided in a union type.

We should also consider watching out for the advice against booleans for state, but I'm not sure that's as important.

konveyor.io/lib-ui URL stopped working

The default GitHub Pages deployment for this repo is used for the Storybook component previews. It was originally accessible at konveyor.github.io/lib-ui, which now redirects to konveyor.io/lib-ui. That was working for a while but now is a 404.

@fdupont-redhat do you know what the deal is there, or who would know about the konveyor.io DNS stuff?

Possibly rename `useSelectionState` to something more generic like `useToggleList` or `useArraySubset`

In forklift-ui, we use useSelectionState for both checkbox selections and row expansions in tables because the state requirements are exactly the same. However, the functions returned from this hook are named very specifically for selection, so it might be nice to make them more generic (toggleItem, isItemToggled, toggleAll etc) and avoid confusing renames in destructuring like this one:

  const {
    toggleItemSelected: toggleVMExpanded,
    isItemSelected: isVMExpanded,
    selectAll: expandAll,
  } = useSelectionState<SourceVM>({
    items: sortedItems,
    isEqual: (a, b) => a.selfLink === b.selfLink,
  });

We could then create thin wrappers with specific naming if we want, like useSelectionState, useExpansionState, etc. Or we could have these functions returned in an array so they can be named on the fly, but there are so many...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.