@frui.ts/screens
Advanced tools
Comparing version 1.0.0-alpha.13 to 1.0.0-alpha.14
@@ -1,16 +0,14 @@ | ||
export { default as HashNavigationAdapter } from "./navigation/hashNavigationAdapter"; | ||
export * from "./navigation/helpers"; | ||
export { default as NavigationConfiguration } from "./navigation/navigationConfiguration"; | ||
export * from "./navigation/navigationPath"; | ||
export { default as PathNavigationAdapter, NAVIGATE_EVENT_NAME } from "./navigation/pathNavigationAdapter"; | ||
export { default as Router } from "./navigation/router"; | ||
export * from "./models/findChildResult"; | ||
export * from "./models/navigationContext"; | ||
export * from "./models/pathElements"; | ||
export { default as ScreenBase, getNavigator } from "./screens/screenBase"; | ||
export * from "./navigation/types"; | ||
export { default as BusyWatcher, watchBusy } from "./structure/busyWatcher"; | ||
export { default as ConductorAllChildrenActive } from "./structure/conductorAllChildrenActive"; | ||
export { default as ConductorBase } from "./structure/conductorBase"; | ||
export { default as ConductorBaseWithActiveItem } from "./structure/conductorBaseWithActiveChild"; | ||
export { default as ConductorOneChildActive } from "./structure/conductorOneChildActive"; | ||
export { default as ConductorSingleChild } from "./structure/conductorSingleChild"; | ||
export * from "./structure/helpers"; | ||
export { default as ScreenBase } from "./structure/screenBase"; | ||
export * from "./structure/types"; | ||
export { default as SimpleScreenNavigator } from "./navigation/simpleScreenNavigator"; | ||
export { default as ActiveChildConductor, FindNavigationChildHandler } from "./navigation/conductors/activeChildConductor"; | ||
export { default as AllChildrenActiveConductor } from "./navigation/conductors/allChildrenActiveConductor"; | ||
export { default as OneOfListActiveConductor } from "./navigation/conductors/oneOfListActiveConductor"; | ||
export * from "./router/route"; | ||
export { default as Router } from "./router/router"; | ||
export { default as RouterBase } from "./router/routerBase"; | ||
export { default as UrlRouterBase } from "./router/urlRouterBase"; | ||
export { default as BusyWatcher, BusyWatcherKey, IBusyWatcher, watchBusy } from "./busyWatcher"; |
"use strict"; | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
} | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var hashNavigationAdapter_1 = require("./navigation/hashNavigationAdapter"); | ||
exports.HashNavigationAdapter = hashNavigationAdapter_1.default; | ||
__export(require("./navigation/helpers")); | ||
var navigationConfiguration_1 = require("./navigation/navigationConfiguration"); | ||
exports.NavigationConfiguration = navigationConfiguration_1.default; | ||
__export(require("./navigation/navigationPath")); | ||
var pathNavigationAdapter_1 = require("./navigation/pathNavigationAdapter"); | ||
exports.PathNavigationAdapter = pathNavigationAdapter_1.default; | ||
exports.NAVIGATE_EVENT_NAME = pathNavigationAdapter_1.NAVIGATE_EVENT_NAME; | ||
var router_1 = require("./navigation/router"); | ||
exports.Router = router_1.default; | ||
__export(require("./navigation/types")); | ||
var busyWatcher_1 = require("./structure/busyWatcher"); | ||
exports.BusyWatcher = busyWatcher_1.default; | ||
exports.watchBusy = busyWatcher_1.watchBusy; | ||
var conductorAllChildrenActive_1 = require("./structure/conductorAllChildrenActive"); | ||
exports.ConductorAllChildrenActive = conductorAllChildrenActive_1.default; | ||
var conductorBase_1 = require("./structure/conductorBase"); | ||
exports.ConductorBase = conductorBase_1.default; | ||
var conductorBaseWithActiveChild_1 = require("./structure/conductorBaseWithActiveChild"); | ||
exports.ConductorBaseWithActiveItem = conductorBaseWithActiveChild_1.default; | ||
var conductorOneChildActive_1 = require("./structure/conductorOneChildActive"); | ||
exports.ConductorOneChildActive = conductorOneChildActive_1.default; | ||
var conductorSingleChild_1 = require("./structure/conductorSingleChild"); | ||
exports.ConductorSingleChild = conductorSingleChild_1.default; | ||
__export(require("./structure/helpers")); | ||
var screenBase_1 = require("./structure/screenBase"); | ||
exports.ScreenBase = screenBase_1.default; | ||
exports.watchBusy = exports.BusyWatcher = exports.UrlRouterBase = exports.RouterBase = exports.OneOfListActiveConductor = exports.AllChildrenActiveConductor = exports.ActiveChildConductor = exports.SimpleScreenNavigator = exports.getNavigator = exports.ScreenBase = void 0; | ||
__exportStar(require("./models/findChildResult"), exports); | ||
__exportStar(require("./models/navigationContext"), exports); | ||
__exportStar(require("./models/pathElements"), exports); | ||
var screenBase_1 = require("./screens/screenBase"); | ||
Object.defineProperty(exports, "ScreenBase", { enumerable: true, get: function () { return __importDefault(screenBase_1).default; } }); | ||
Object.defineProperty(exports, "getNavigator", { enumerable: true, get: function () { return screenBase_1.getNavigator; } }); | ||
__exportStar(require("./navigation/types"), exports); | ||
var simpleScreenNavigator_1 = require("./navigation/simpleScreenNavigator"); | ||
Object.defineProperty(exports, "SimpleScreenNavigator", { enumerable: true, get: function () { return __importDefault(simpleScreenNavigator_1).default; } }); | ||
var activeChildConductor_1 = require("./navigation/conductors/activeChildConductor"); | ||
Object.defineProperty(exports, "ActiveChildConductor", { enumerable: true, get: function () { return __importDefault(activeChildConductor_1).default; } }); | ||
var allChildrenActiveConductor_1 = require("./navigation/conductors/allChildrenActiveConductor"); | ||
Object.defineProperty(exports, "AllChildrenActiveConductor", { enumerable: true, get: function () { return __importDefault(allChildrenActiveConductor_1).default; } }); | ||
var oneOfListActiveConductor_1 = require("./navigation/conductors/oneOfListActiveConductor"); | ||
Object.defineProperty(exports, "OneOfListActiveConductor", { enumerable: true, get: function () { return __importDefault(oneOfListActiveConductor_1).default; } }); | ||
__exportStar(require("./router/route"), exports); | ||
var routerBase_1 = require("./router/routerBase"); | ||
Object.defineProperty(exports, "RouterBase", { enumerable: true, get: function () { return __importDefault(routerBase_1).default; } }); | ||
var urlRouterBase_1 = require("./router/urlRouterBase"); | ||
Object.defineProperty(exports, "UrlRouterBase", { enumerable: true, get: function () { return __importDefault(urlRouterBase_1).default; } }); | ||
var busyWatcher_1 = require("./busyWatcher"); | ||
Object.defineProperty(exports, "BusyWatcher", { enumerable: true, get: function () { return __importDefault(busyWatcher_1).default; } }); | ||
Object.defineProperty(exports, "watchBusy", { enumerable: true, get: function () { return busyWatcher_1.watchBusy; } }); | ||
//# sourceMappingURL=index.js.map |
@@ -1,25 +0,16 @@ | ||
import { IScreen } from "../structure/types"; | ||
import { NavigationPath } from "./navigationPath"; | ||
export interface ICanNavigate { | ||
navigate(subPath: string | undefined, params: any): Promise<any> | void; | ||
getNavigationPath(): NavigationPath; | ||
import type { Awaitable } from "@frui.ts/helpers"; | ||
import type { PathElement } from "../models/pathElements"; | ||
export interface ScreenNavigator<TScreen = unknown> { | ||
readonly isActive: boolean; | ||
readonly screen?: TScreen; | ||
canNavigate(path: PathElement[]): Awaitable<boolean>; | ||
navigate(path: PathElement[]): Promise<void>; | ||
navigationName: string; | ||
getNavigationState(): PathElement[]; | ||
parent: ScreenNavigator | undefined; | ||
getPrimaryChild(): ScreenNavigator | undefined; | ||
} | ||
export interface INavigatedEvent { | ||
screenName: string; | ||
screen: IScreen; | ||
url: string; | ||
export interface LifecycleScreenNavigator<TScreen = unknown> extends ScreenNavigator<TScreen> { | ||
canDeactivate(isClosing: boolean): Awaitable<boolean>; | ||
deactivate(isClosing: boolean): Promise<void>; | ||
} | ||
export interface INavigationParent<TChild> { | ||
getChildNavigationPath(child: TChild | string | number, childParams?: any): NavigationPath; | ||
} | ||
export declare type Class = { | ||
new (...args: any[]): any; | ||
}; | ||
declare const SelfLink: unique symbol; | ||
export { SelfLink }; | ||
export declare type RouteName = string | symbol | Class; | ||
export interface RouteDefinition { | ||
name?: RouteName | typeof SelfLink; | ||
route: string; | ||
children?: Class[]; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var SelfLink = Symbol("Router.Self"); | ||
exports.SelfLink = SelfLink; | ||
//# sourceMappingURL=types.js.map |
@@ -6,3 +6,3 @@ { | ||
}, | ||
"version": "1.0.0-alpha.13", | ||
"version": "1.0.0-alpha.14", | ||
"description": "Frui.ts core classes for application structure and navigation", | ||
@@ -13,2 +13,3 @@ "keywords": [ | ||
"mvvm", | ||
"router", | ||
"mobx" | ||
@@ -39,8 +40,8 @@ ], | ||
"dependencies": { | ||
"@frui.ts/helpers": "^1.0.0-alpha.13", | ||
"query-string": "^6.9.0", | ||
"@frui.ts/helpers": "^1.0.0-alpha.14", | ||
"route-parser": "^0.0.5" | ||
}, | ||
"devDependencies": { | ||
"@types/route-parser": "^0.1.3" | ||
"@types/route-parser": "^0.1.3", | ||
"jest-mock-extended": "^2.0.4" | ||
}, | ||
@@ -50,3 +51,3 @@ "peerDependencies": { | ||
}, | ||
"gitHead": "5454d007244bb9cdd28be5207a9f125f04a9ac43" | ||
"gitHead": "ea59f02314805efcededd8a9b75b62b0e656cd4e" | ||
} |
290
README.md
@@ -1,290 +0,14 @@ | ||
# `@frui.ts/screens` | ||
Screens and navigation are separated. Each screen has a `navigator` property with a concrete implementation of navigator. Thus, we can easily combine screens with different navigation strategies. | ||
# Screens | ||
Since the application should be **ViewModel-driven**, we need to properly design the application structure within VMs. | ||
There is a simple base class for all view models - `ScreenBase`. It handles basic lifecycle such as `initialize`, `activate`, `deactivate`. These actions origin from the root `View` component and are passed to child view models by their parent conductors. | ||
# Screen lifecycle | ||
Hierarchical nesting of VMs is necessary to structure almost any application, and thus base classes for the task are supplied as well: | ||
- `ConductorSingleChild` - conductor with manually managed child VMs, e.g., a list with a detail page. | ||
- `ConductorOneChildActive` - conductor with a list of children and single active child. This is used when the parent has a static list of possible child VMs and only a single child can be active at a time. E.g., application module with list of pages. | ||
- `ConductorAllChildrenActive` - conductor with a list of children of which all are active. This is typical for multi-window screens or dashboards. | ||
We recommend to design the structure of VMs first and only after that start with views implementation. | ||
These components are heavily inspired by the Caliburn.Micro framework from .NET platform. | ||
![Interfaces cheatsheet](http://www.plantuml.com/plantuml/proxy?cache=no&src=https://raw.githubusercontent.com/eManPrague/frui.ts/develop/packages/screens/interfaces.puml) | ||
![Classes hierarchy](http://www.plantuml.com/plantuml/proxy?cache=no&src=https://raw.githubusercontent.com/eManPrague/frui.ts/develop/packages/screens/classes.puml) | ||
## `ScreenBase` | ||
### Useful functionality | ||
- `navigationName` - name used for navigation path (URL) | ||
- `isActive` - observable property indicating whether the screen is currently active/visible in the application | ||
- `onInitialize()`, `onActivate()`, `onDeactivate()` - override these functions in derived class if you need to react to the respective events. If overriding in conductors, don't forget to call the function from base class (`super`) as well. | ||
- `canDeactivate()` - use this function in views to enable/disable close button. You can override this function and implement custom logic. Conductors override this function and forward it to `canDeactivate()` from their children. | ||
- `requestClose()` - use this function to ask the screen's parent to close the screen. | ||
#### Example | ||
```html | ||
<button disabled="{!vm.canDeactivate()}" onClick="{vm.requestClose}">Close</button> | ||
``` | ||
## `ConductorSingleChild` | ||
### Useful functionality | ||
- `activeChild` - observable property with the currently selected child | ||
- `tryActivateChild(child)` - call this function to change the currently selected child. Automatically closes the old child if possible (calls `canDeactivate` on the child) and assigns `parent` to the new one. | ||
- `closeChild(child)` - use to properly close the child (calls `canDeactivate`) | ||
- `findNavigationChild(navigationName)` - implement this function to return proper child view model based on the navigation name provided. It is automatically called when navigating. However, you can reuse it in your logic as well (e.g., when creating a child for `tryActivateChild`). | ||
- `onChildNavigated(child)` - implement this function to do some actions after navigation is done | ||
## `ConductorOneChildActive` | ||
### Useful functionality | ||
- `activeChild` - observable property with the currently selected child | ||
- `children` - add all possible children here. Just adding a child to the list assigns its `parent` property. | ||
- `tryActivateChild(child)` - call this function to switch to another child | ||
- `closeChild(child)` - use to properly close the child (calls `canDeactivate`) and remove it from `children` | ||
## `ConductorAllChildrenActive` | ||
### Useful functionality | ||
- `children` - add all possible children here. Just adding a child to the list assigns its `parent` property. | ||
- `closeChild(child)` - use to properly close the child (calls `canDeactivate`) and remove it from `children` | ||
# Busywatcher | ||
`Busywatcher` is a simple counter of currently running processes that need to display loading progress. You can either manually increment and decrement the counter, get a disposable ticket with `getBusyTicket()`, or use its `watch()` function to watch over a promise. | ||
You can also use function decorator `@watchBusy`. It automates the use of `busyWatcher.watch()` - if the function the decorator is applied to is async or returns a promise, and the parent class also contains a property named `busyWatcher`, the function is automatically watched by the busyWatcher. | ||
```ts | ||
import { BusyWatcher, watchBusy } from "@frui.ts/screens"; | ||
class MyViewModel { | ||
busyWatcher = new BusyWatcher(); | ||
@watchBusy | ||
async doLongProcess() { | ||
// busyWatcher.isBusy == true | ||
await someAction(); | ||
await anotherAction(); | ||
} | ||
} | ||
``` | ||
# Navigation | ||
There are several use cases related to navigation: | ||
Each navigator builds its navigation state of its children. Router walks the path to the root and then gets the state providing overrides for the new path. | ||
### 1. Notify that application navigation has changed | ||
Every time the application needs to update the navigation state (usually resulting in changing the URL), it raises an event. In order to streamline the event issuing, there is a helper function on `NavigationConfiguration`. | ||
```ts | ||
import { NavigationConfiguration } from "@frui.ts/screens"; | ||
// is you call this from a view model, you will probably replace 'currentScreen' with 'this' | ||
NavigationConfiguration.onScreenChanged?.(currentScreen); | ||
``` | ||
There are two places where `onScreenChanged` is called by default: | ||
1. Whenever a `ScreenBase` is activated. | ||
2. When a `ConductorBaseWithActiveChild` does not have an active child. | ||
You might notice that point 1 would cause problems when activating a parent conductor with already present active child (because both get activated). To handle that, there is a property `canBeNavigationActiveScreen` in `ScreenBase`. The property is used as a flag if the actual `onScreenChanged` should be called. For example in `ConductorBaseWithActiveChild`, it is implemented as this: | ||
```ts | ||
get canBeNavigationActiveScreen() { | ||
return !this.activeChildValue; | ||
} | ||
``` | ||
So, if you are creating some kind of a conductor that contains children, you should implement the property similarly. | ||
Besides the automatic URL update when changing active VMs, you might also want to update URL on some actions within a VM (e.g., a filter is changed). For that, you just need to call `notifyNavigationChanged()` that is available from the base class `ScreenBase` whenever you want to update the navigation state. | ||
### 2. Get current navigation path | ||
When a call to `onScreenChanged` is issued, the simplest way to get the actual navigation path is to call `getNavigationPath` on the source view model. It is then its responsibility to get the proper path. The default implementation in `ScreenBase` recursively calls parent view models to get the full path. | ||
### 3. React when URL changes | ||
When the navigation path changes from outside of the application, we need the app to react. Because Frui.ts applications are composed as a hierarchical structure of view models, the navigation should start from the top-most level, i.e., the root view model. Simply call its `navigate()` function. And let it recursively activate its children along the new path. | ||
### 4. Generate local navigation links | ||
When you want to navigate between children of a conductor, you can use `conductor.tryActivateChild(child)`. This will work, properly update browser URL, and also react to any URL changes. However, the action will be bound to the respective user control such as a button via `onClick` handler, and thus some typical web actions such as opening the link in a new window will not work. If you need such functionality, we need to generate a navigation URL for the children. | ||
You can either manually call `child.getNavigationPath()`, use `conductor.getChildNavigationPath()`, or call a helper function `Router.getChildUrlFactory()`. This factory function is usefull especially when creating multiple URLs, because it caches the root path. | ||
```tsx | ||
import { Router } from "@frui.ts/screens"; | ||
... | ||
// somewhere inside a view | ||
const getUrl = Router.getChildUrlFactory(vm); | ||
<a href={getUrl("childId")}>Link</a> // creates <a href="#/foo/bar/parent/childId">Link</a> | ||
``` | ||
You can also use application-wide links as described below. | ||
### 5. Generate application-wide navigation links | ||
You can also use a navigation path for navigating to another part of the application. The hard part here is how to get the proper path. | ||
The first and obvious solution is to generate it manually. That is quite easy provided that you know the structure of your application and navigation names of the respective view models. | ||
```tsx | ||
<a href={`#/foo/bar/${id}`}>Link</a> | ||
``` | ||
```ts | ||
rootViewModel.navigate(`foo/bar/${id}`); | ||
``` | ||
You can also use a typical solution with centrally defined routes. What we don't like about this solution is that you still rely on knowing the proper path for each view model, and in case of any change, you have to remember to update the routes as well. We wanted to find a better solution and keep the knowledge about the application structure as close to the source as possible. | ||
The idea is that you always register only a single parent-child relationship. Then, during the application initialization, these parts are joined to get the full path from the root view model to the deepest child view models. | ||
```ts | ||
// rootViewModel.ts | ||
import { ConductorOneChildActive, Router, ScreenBase } from "@frui.ts/screens"; | ||
// we already need to reference the child VMs in the constructor, | ||
// so it is OK to mention it here as well | ||
@Router.registerRoute({ route: "", children: [OrdersViewModel, UsersViewModel] }) | ||
export default class RootViewModel extends ConductorOneChildActive<ScreenBase> { | ||
constructor(ordersVM: OrdersViewModel, usersVM: UsersViewModel) | ||
{ | ||
... | ||
} | ||
} | ||
``` | ||
```ts | ||
// usersViewModel.ts | ||
import { ConductorOneChildActive, Router, ScreenBase } from "@frui.ts/screens"; | ||
@Router.registerRoute({ name: "usersList", route: "users" }) | ||
@Router.registerRoute({ name: "userDetail", route: "users/:userId" }) | ||
@Router.registerRoute({ name: UserDetailViewModel, route: "users/:userId" }) // you can use a type or a symbol as route name as well | ||
export default class UsersViewModel extends ConductorSingleChild<UserDetailViewModel> { | ||
navigationName = "users"; | ||
constructor(private ordersModule: OrdersModuleViewModel, securityModule: SecurityModuleViewModel) | ||
{ | ||
... | ||
} | ||
} | ||
``` | ||
Please note that if you want to use a class' type as its own route name, this will not work: | ||
```ts | ||
@Router.registerRoute({ name: UsersViewModel, route: "users" }) // throws ReferenceError: Cannot access 'UsersViewModel' before initialization | ||
export default class UsersViewModel extends ConductorSingleChild<UserDetailViewModel> { | ||
... | ||
} | ||
``` | ||
However, you can use the `Router.Self` helper instead: | ||
```ts | ||
@Router.registerRoute({ name: Router.Self, route: "users" }) | ||
export default class UsersViewModel extends ConductorSingleChild<UserDetailViewModel> { | ||
... | ||
} | ||
``` | ||
```ts | ||
import { Router } from "@frui.ts/screens"; | ||
const router = new Router(); | ||
router.start(rootViewModel); | ||
... | ||
const url = router.getUrl("userDetail", { userId: 42 }); // "#/users/42" | ||
await router.navigate("userDetail", { userId: 42 }); // immediately navigates to the user detail | ||
await router.navigate(UserDetailViewModel, { userId: 42 }); // use type as route name | ||
``` | ||
## Navigation summary | ||
The chain of events when using `router.navigate` for application-wide navigation is as follows: | ||
1. Router generates target navigation path | ||
2. The navigation path is passed to `rootViewModel.navigate()` which recursively activates VMs through the VM hierarchy | ||
3. When the last VM is activated, it notifies that application navigation has changed which eventually updates URL in the browser's navigation bar. | ||
## `HashNavigationAdapter` | ||
This is a reference implementation for a navigation adapter that handles browser URL and history changes through URL hash. | ||
To initialize the adapter, you need to provide the root view model. It will automatically hook to the `onScreenChanged` handler. | ||
```ts | ||
// in your application initialization code | ||
import { HashNavigationAdapter } from "@frui.ts/screens"; | ||
... | ||
const urlAdapter = new HashNavigationAdapter(); | ||
urlAdapter.start(rootViewModel); | ||
``` | ||
Implement `ICanNavigate` if you want to control the navigation path for children and react to changes in the navigation path. Note that the conductors described above already implement `ICanNavigate`. | ||
## `PathNavigationAdapter` | ||
Similar to the HashNavigationAdapter, this adapter controls navigation and history, but using the URL path. | ||
In order to properly handle client routes on the server, please refer to the [Create React App documentation](https://create-react-app.dev/docs/deployment/#serving-apps-with-client-side-routing). | ||
### Links | ||
Since all links generated by Router (e.g., `router.getUrl()`) are just a relative URL links (e.g., `/users/list`), you need to explicitly handle clicks on such links in order to avoid server requests. This is usually done by adding `onClick` event handler. | ||
You can use `hrefParams()` helper function from `@frui.ts/views` to automatically set the `href` attribute as well as the respective `onClick` event handler: | ||
```jsx | ||
import { hrefParams } from "@frui.ts/views"; | ||
// instead of: | ||
<a href="/users/list" >Go to users</a> | ||
// use: | ||
<a {...hrefParams("/users/list")} >Click me!</a> | ||
``` | ||
### Navigated event | ||
Both navigation adapters, `PathNavigationAdapter` as well as `HashNavigationAdapter`, trigger `fruitsNavigated` event. | ||
You can listen for this event in your application, for example to report `pageView` to Google Analytics. | ||
```typescript | ||
interface INavigatedEvent { | ||
screenName: string; | ||
screen: IScreen; | ||
url: string; | ||
} | ||
window.addEventListener("fruitsNavigated", this.onNavigated); | ||
onNavigated(e: CustomEventInit<INavigatedEvent>) { | ||
console.log(e.detail?.url); | ||
} | ||
``` | ||
Use cases: | ||
1. Get current URL - call root and get current state with full primary path | ||
2. Get navigation URL to a child | ||
3. Get navigation URL to any place |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
3
63
123044
2
1224
14
- Removedquery-string@^6.9.0
- Removeddecode-uri-component@0.2.2(transitive)
- Removedfilter-obj@1.1.0(transitive)
- Removedquery-string@6.14.1(transitive)
- Removedsplit-on-first@1.1.0(transitive)
- Removedstrict-uri-encode@2.0.0(transitive)