WIP MSW setup

This commit is contained in:
Jesper Møller Jensen
2022-10-04 15:15:45 +02:00
parent 4a1c7d7350
commit bdc4daa2a2
12 changed files with 1868 additions and 1474 deletions

View File

@@ -1,14 +1,8 @@
import { css, html, LitElement, nothing } from 'lit';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement, query, state } from 'lit/decorators.js';
import { customElement, state } from 'lit/decorators.js';
import { UmbContextConsumerMixin } from '../../../../../core/context';
import { Subscription } from 'rxjs';
import './list-view-layouts/table/editor-view-users-table.element';
import './editor-view-users-grid.element';
import './editor-view-users-selection.element';
import { IRoute } from 'router-slot';
import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element';
import { UUIPopoverElement } from '@umbraco-ui/uui';
import UmbEditorViewUsersElement from './editor-view-users.element';
export type UsersViewType = 'list' | 'grid';
@customElement('umb-editor-view-users-invite')

View File

@@ -4,7 +4,7 @@ import { customElement, state } from 'lit/decorators.js';
import { UmbContextConsumerMixin } from '../../../../../core/context';
import { Subscription } from 'rxjs';
import './list-view-layouts/table/editor-view-users-table.element';
import './editor-view-users-grid.element';
import './list-view-layouts/grid/editor-view-users-grid.element';
import './editor-view-users-selection.element';
import './editor-view-users-invite.element';
import { IRoute } from 'router-slot';
@@ -132,7 +132,7 @@ export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(L
private _routes: IRoute[] = [
{
path: 'grid',
component: () => import('./editor-view-users-grid.element'),
component: () => import('./list-view-layouts/grid/editor-view-users-grid.element'),
},
{
path: 'list',

View File

@@ -4,7 +4,6 @@ import { customElement, state } from 'lit/decorators.js';
import { UmbContextConsumerMixin } from '../../../../../core/context';
import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element';
import { Subscription } from 'rxjs';
import { tempData } from './tempData';
import '../../../../property-editors/content-picker/property-editor-content-picker.element';
@customElement('umb-editor-view-users-user-details')
@@ -86,20 +85,7 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi
protected _usersContext?: UmbEditorViewUsersElement;
protected _usersSubscription?: Subscription;
private _languages = tempData //TODO Get languages from API instead of fakeData
.reduce((acc, curr) => {
if (!acc.includes(curr.language)) {
acc.push(curr.language);
}
return acc;
}, [] as Array<string>)
.map((language) => {
return {
name: language,
value: language,
selected: false,
};
});
private _languages = []; //TODO Add languages
connectedCallback(): void {
super.connectedCallback();

View File

@@ -12,23 +12,7 @@ import './editor-view-users-selection.element';
import './editor-view-users-user-details.element';
import './editor-view-users-invite.element';
import { tempData } from './tempData';
export interface UserItem {
id: number;
key: string;
name: string;
email: string;
status: string;
language: string;
lastLoginDate?: string;
lastLockoutDate?: string;
lastPasswordChangeDate?: string;
updateDate: string;
createDate: string;
failedLoginAttempts: number;
userGroup?: string; //TODO Implement this
}
import type { UserDetails, UserEntity } from '../../../../../core/models';
@customElement('umb-editor-view-users')
export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElement) {
@@ -54,9 +38,6 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen
},
];
private _users: BehaviorSubject<Array<UserItem>> = new BehaviorSubject(tempData);
public readonly users: Observable<Array<UserItem>> = this._users.asObservable();
private _selection: BehaviorSubject<Array<string>> = new BehaviorSubject(<Array<string>>[]);
public readonly selection: Observable<Array<string>> = this._selection.asObservable();
@@ -84,45 +65,45 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen
this.requestUpdate('selection');
}
public updateUser(user: UserItem) {
const users = this._users.getValue();
const index = users.findIndex((u) => u.key === user.key);
if (index === -1) return;
users[index] = { ...users[index], ...user };
console.log('updateUser', user, users[index]);
this._users.next(users);
this.requestUpdate('users');
}
// public updateUser(user: UserEntity) {
// const users = this._users.getValue();
// const index = users.findIndex((u) => u.key === user.key);
// if (index === -1) return;
// users[index] = { ...users[index], ...user };
// console.log('updateUser', user, users[index]);
// this._users.next(users);
// this.requestUpdate('users');
// }
public inviteUser(name: string, email: string, userGroup: string, message: string): UserItem {
const users = this._users.getValue();
const user = {
id: this._users.getValue().length + 1,
key: uuidv4(),
name: name,
email: email,
status: 'invited',
language: 'en',
updateDate: new Date().toISOString(),
createDate: new Date().toISOString(),
failedLoginAttempts: 0,
userGroup: userGroup,
};
this._users.next([...users, user]);
this.requestUpdate('users');
// public inviteUser(name: string, email: string, userGroup: string, message: string): UserEntity {
// const users = this._users.getValue();
// const user = {
// id: this._users.getValue().length + 1,
// key: uuidv4(),
// name: name,
// email: email,
// status: 'invited',
// language: 'en',
// updateDate: new Date().toISOString(),
// createDate: new Date().toISOString(),
// failedLoginAttempts: 0,
// userGroup: userGroup,
// };
// this._users.next([...users, user]);
// this.requestUpdate('users');
//TODO: Send invite email with message
return user;
}
// //TODO: Send invite email with message
// return user;
// }
public deleteUser(key: string) {
const users = this._users.getValue();
const index = users.findIndex((u) => u.key === key);
if (index === -1) return;
users.splice(index, 1);
this._users.next(users);
this.requestUpdate('users');
}
// public deleteUser(key: string) {
// const users = this._users.getValue();
// const index = users.findIndex((u) => u.key === key);
// if (index === -1) return;
// users.splice(index, 1);
// this._users.next(users);
// this.requestUpdate('users');
// }
public getTagLookAndColor(status?: string): { color: InterfaceColor; look: InterfaceLook } {
switch ((status || '').toLowerCase()) {

View File

@@ -5,8 +5,9 @@ import { repeat } from 'lit/directives/repeat.js';
import { Subscription } from 'rxjs';
import { ifDefined } from 'lit-html/directives/if-defined.js';
import { UmbContextConsumerMixin } from '../../../../../../../core/context';
import UmbEditorViewUsersElement, { UserItem } from '../../editor-view-users.element';
import UmbEditorViewUsersElement from '../../editor-view-users.element';
import { UmbUserStore } from '../../../../../../../core/stores/user/user.store';
import type { UserEntity } from '../../../../../../../core/models';
@customElement('umb-editor-view-users-grid')
export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitElement) {
@@ -31,7 +32,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl
];
@state()
private _users: Array<UserItem> = [];
private _users: Array<UserEntity> = [];
@state()
private _selection: Array<string> = [];
@@ -85,15 +86,15 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl
history.pushState(null, '', '/section/users/view/users/details' + '/' + key); //TODO Change to a tag with href and make dynamic
}
private _selectRowHandler(user: UserItem) {
private _selectRowHandler(user: UserEntity) {
this._usersContext?.select(user.key);
}
private _deselectRowHandler(user: UserItem) {
private _deselectRowHandler(user: UserEntity) {
this._usersContext?.deselect(user.key);
}
private renderUserCard(user: UserItem) {
private renderUserCard(user: UserEntity) {
if (!this._userStore) return;
const statusLook = this._usersContext?.getTagLookAndColor(user.status ? user.status : '');

View File

@@ -4,12 +4,13 @@ import { customElement, state } from 'lit/decorators.js';
import { UmbContextConsumerMixin } from '../../../../../../../core/context';
import { repeat } from 'lit/directives/repeat.js';
import { Subscription } from 'rxjs';
import UmbEditorViewUsersElement, { UserItem } from '../../editor-view-users.element';
import UmbEditorViewUsersElement from '../../editor-view-users.element';
import { UmbUserStore } from '../../../../../../../core/stores/user/user.store';
import type { UserEntity } from '../../../../../../../core/models';
interface TableColumn {
name: string;
sort: (items: Array<UserItem>, desc: boolean) => Array<UserItem>;
sort: (items: Array<UserEntity>, desc: boolean) => Array<UserEntity>;
}
@customElement('umb-editor-view-users-table')
@@ -74,7 +75,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE
private _sortingDesc = false;
@state()
private _users: Array<UserItem> = [];
private _users: Array<UserEntity> = [];
private _userStore?: UmbUserStore;
private _usersContext?: UmbEditorViewUsersElement;
@@ -97,7 +98,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE
this._columns = [
{
name: 'Name',
sort: (items: Array<UserItem>, desc: boolean) => {
sort: (items: Array<UserEntity>, desc: boolean) => {
return desc
? [...items].sort((a, b) => b.name.localeCompare(a.name))
: [...items].sort((a, b) => a.name.localeCompare(b.name));
@@ -105,7 +106,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE
},
{
name: 'User group',
sort: (items: Array<UserItem>, desc: boolean) => {
sort: (items: Array<UserEntity>, desc: boolean) => {
return desc
? [...items].sort((a, b) => b.name.localeCompare(a.name))
: [...items].sort((a, b) => a.name.localeCompare(b.name));
@@ -113,7 +114,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE
},
{
name: 'Last login',
sort: (items: Array<UserItem>, desc: boolean) => {
sort: (items: Array<UserEntity>, desc: boolean) => {
return desc
? [...items].sort((a, b) => +new Date(b.lastLoginDate || 0) - +new Date(a.lastLoginDate || 0))
: [...items].sort((a, b) => +new Date(a.lastLoginDate || 0) - +new Date(b.lastLoginDate || 0));
@@ -121,7 +122,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE
},
{
name: 'status',
sort: (items: Array<UserItem>, desc: boolean) => {
sort: (items: Array<UserEntity>, desc: boolean) => {
return desc
? [...items].sort((a, b) =>
b.status && a.status ? b.status.localeCompare(a.status) : (a.status ? 1 : 0) - (b.status ? 1 : 0)
@@ -165,11 +166,11 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE
history.pushState(null, '', '/section/users/view/users/details' + '/' + key); //TODO: make a tag with href
}
private _selectRowHandler(user: UserItem) {
private _selectRowHandler(user: UserEntity) {
this._usersContext?.select(user.key);
}
private _deselectRowHandler(user: UserItem) {
private _deselectRowHandler(user: UserEntity) {
this._usersContext?.deselect(user.key);
}
@@ -195,7 +196,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE
`;
}
protected renderRowTemplate = (user: UserItem) => {
protected renderRowTemplate = (user: UserEntity) => {
if (!this._usersContext) return;
const statusLook = this._usersContext.getTagLookAndColor(user.status ? user.status : '');

View File

@@ -1,4 +1,5 @@
import type { components } from '../../../schemas/generated-schema';
import { Entity } from '../../mocks/data/entities';
export type PostInstallRequest = components['schemas']['InstallSetupRequest'];
export type StatusResponse = components['schemas']['StatusResponse'];
@@ -55,3 +56,21 @@ export type ManifestElementType =
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type HTMLElementConstructor<T = HTMLElement> = new (...args: any[]) => T;
// Users
export interface UserEntity extends Entity {
type: 'user';
}
export interface UserDetails extends UserEntity {
email: string;
status: string;
language: string;
lastLoginDate?: string;
lastLockoutDate?: string;
lastPasswordChangeDate?: string;
updateDate: string;
createDate: string;
failedLoginAttempts: number;
userGroup?: string; //TODO Implement this
}

View File

@@ -1,15 +1,15 @@
import { map, Observable } from 'rxjs';
import { UserItem } from '../../../backoffice/editors/users/views/users/editor-view-users.element';
import type { UserEntity } from '../../models';
import { UmbEntityStore } from '../entity.store';
import { UmbDataStoreBase } from '../store';
/**
* @export
* @class UmbUserStore
* @extends {UmbDataStoreBase<UserItem>}
* @extends {UmbDataStoreBase<UserEntity>}
* @description - Data Store for Users
*/
export class UmbUserStore extends UmbDataStoreBase<UserItem> {
export class UmbUserStore extends UmbDataStoreBase<UserEntity> {
private _entityStore: UmbEntityStore;
constructor(entityStore: UmbEntityStore) {
@@ -17,7 +17,7 @@ export class UmbUserStore extends UmbDataStoreBase<UserItem> {
this._entityStore = entityStore;
}
getAll(): Observable<Array<UserItem>> {
getAll(): Observable<Array<UserEntity>> {
// TODO: use Fetcher API.
// TODO: only fetch if the data type is not in the store?
fetch(`/umbraco/backoffice/users`)
@@ -35,7 +35,7 @@ export class UmbUserStore extends UmbDataStoreBase<UserItem> {
* @return {*} {(Observable<DataTypeDetails | null>)}
* @memberof UmbDataTypeStore
*/
getByKey(key: string): Observable<UserItem | null> {
getByKey(key: string): Observable<UserEntity | null> {
// TODO: use Fetcher API.
// TODO: only fetch if the data type is not in the store?
fetch(`/umbraco/backoffice/users/${key}`)
@@ -46,7 +46,7 @@ export class UmbUserStore extends UmbDataStoreBase<UserItem> {
});
return this.items.pipe(
map((dataTypes: Array<UserItem>) => dataTypes.find((node: UserItem) => node.key === key) || null)
map((dataTypes: Array<UserEntity>) => dataTypes.find((node: UserEntity) => node.key === key) || null)
);
}

View File

@@ -7,9 +7,9 @@ export class UmbEntityData<T extends Entity> extends UmbData<T> {
super(data);
}
getItems(type = '', parentKey = '') {
getItems(type: string, parentKey = '') {
if (!type) return [];
return entities.filter((item) => item.type === type && item.parentKey === parentKey);
return this.data.filter((item) => item.type === type && item.parentKey === parentKey);
}
getByKey(key: string) {

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,11 @@
import { rest } from 'msw';
import { tempData } from '../../backoffice/editors/users/views/users/tempData';
import { umbUsersData } from '../data/users.data';
// TODO: add schema
export const handlers = [
rest.get('/umbraco/backoffice/users', (req, res, ctx) => {
const response = {
items: tempData,
items: umbUsersData.getItems('user'),
};
return res(ctx.status(200), ctx.json(response));
@@ -15,7 +15,7 @@ export const handlers = [
const key = req.params.key as string;
if (!key) return;
const user = tempData.find((x) => x.key === key);
const user = umbUsersData.getByKey(key);
return res(ctx.status(200), ctx.json([user]));
}),