Merge pull request #860 from theseyi/ownership-deux

adds local type defs for ember concurrency. contraints the return typ…
This commit is contained in:
Seyi Adebajo 2017-11-13 18:35:39 -08:00 committed by GitHub
commit e3a87e02d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 159 additions and 41 deletions

View File

@ -7,8 +7,18 @@ import { assert } from '@ember/debug';
import UserLookup from 'wherehows-web/services/user-lookup';
import CurrentUser from 'wherehows-web/services/current-user';
import { IOwner } from 'wherehows-web/typings/api/datasets/owners';
import { ownerAlreadyExists, confirmOwner, updateOwner } from 'wherehows-web/constants/datasets/owner';
import { isRequiredMinOwnersNotConfirmed, OwnerSource, OwnerType } from 'wherehows-web/utils/api/datasets/owners';
import {
ownerAlreadyExists,
confirmOwner,
updateOwner,
minRequiredConfirmedOwners
} from 'wherehows-web/constants/datasets/owner';
import {
isRequiredMinOwnersNotConfirmed,
OwnerSource,
OwnerType,
validConfirmedOwners
} from 'wherehows-web/utils/api/datasets/owners';
import Notifications, { NotificationEvent } from 'wherehows-web/services/notifications';
/**
@ -79,6 +89,15 @@ export default class DatasetAuthors extends Component {
return isRequiredMinOwnersNotConfirmed(get(this, 'confirmedOwners'));
});
/**
* Counts the number of valid confirmed owners needed to make changes to the dataset
* @type {ComputedProperty<number>}
* @memberof DatasetAuthors
*/
ownersRequiredCount: ComputedProperty<number> = computed('confirmedOwners.[]', function(this: DatasetAuthors) {
return minRequiredConfirmedOwners - validConfirmedOwners(get(this, 'confirmedOwners')).length;
});
/**
* Lists the owners that have be confirmed view the client ui
* @type {ComputedProperty<Array<IOwner>>}

View File

@ -86,9 +86,9 @@ function updateOwner<K extends keyof IOwner>(
* Sets the `confirmedBy` attribute to the currently logged in user
* @param {IOwner} owner the owner to be updated
* @param {string} confirmedBy the userName of the confirming user
* @returns {(Array<IOwner> | void)}
* @returns {IOwner.confirmedBy}
*/
const confirmOwner = (owner: IOwner, confirmedBy: string): null | string =>
const confirmOwner = (owner: IOwner, confirmedBy: string): IOwner['confirmedBy'] =>
set(owner, 'confirmedBy', confirmedBy || null);
/**
* Defines the default properties for a newly created IOwner instance

View File

@ -8,6 +8,10 @@ $owner-list-issue-color: set-color(red, maroonflush);
font-size: 20px;
font-weight: fw(normal, 4);
}
&__required-count {
height: item-spacing(4);
}
}
.dataset-author-record {

View File

@ -10,14 +10,14 @@
</div>
</section>
{{#if requiredMinNotConfirmed}}
<p class="dataset-author__required-count">
{{#if requiredMinNotConfirmed}}
<p>
Add <strong>at least {{sub 2 confirmedOwners.length}}</strong> confirmed owner(s) with ID Type - <code>USER</code>
Add <strong>at least {{ownersRequiredCount}}</strong> owner(s) with ID Type - <code>USER</code>
and Owner Type - <code>Owner</code>
</p>
{{/if}}
{{/if}}
</p>
<section class="dataset-author">
<header>
@ -92,7 +92,7 @@
</h2>
<p class="dataset-author__byline">
These are dataset ownership records, suggested based information derived from the source metadata.
These are dataset ownership records, suggested based on information derived from the source metadata.
</p>
</header>

View File

@ -0,0 +1,91 @@
declare module 'ember-concurrency' {
export function timeout(delay: number): Promise<void>;
import ComputedProperty from '@ember/object/computed';
import RSVP from 'rsvp';
export enum TaskInstanceState {
Dropped = 'dropped',
Canceled = 'canceled',
Finished = 'finished',
Running = 'running',
Waiting = 'waiting'
}
export interface TaskProperty<T> extends ComputedProperty<T> {
cancelOn(eventNames: string[]): this;
debug(): this;
drop(): this;
enqueue(): this;
group(groupPath: string): this;
keepLatest(): this;
maxConcurrency(n: number): this;
on(eventNames: string[]): this;
restartable(): this;
}
export interface TaskInstance<T> extends PromiseLike<T> {
readonly error?: any;
readonly hasStarted: ComputedProperty<boolean>;
readonly isCanceled: ComputedProperty<boolean>;
readonly isDropped: ComputedProperty<boolean>;
readonly isError: ComputedProperty<boolean>;
readonly isFinished: ComputedProperty<boolean>;
readonly isRunning: ComputedProperty<boolean>;
readonly isSuccessful: ComputedProperty<boolean>;
readonly state: ComputedProperty<TaskInstanceState>;
readonly value?: T;
cancel(): void;
catch: () => RSVP.Promise<any>;
finally: () => RSVP.Promise<any>;
then<TResult1 = T, TResult2 = never>(
onfulfilled?: ((value: T) => TResult1 | RSVP.Promise<TResult1>) | undefined | null,
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null
): RSVP.Promise<TResult1 | TResult2>;
}
export enum TaskState {
Running = 'running',
Queued = 'queued',
Idle = 'idle'
}
type Task<T, P> = TaskProperty<T> &
ComputedProperty<{ perform: P }> & {
readonly isIdle: boolean;
readonly isQueued: boolean;
readonly isRunning: boolean;
readonly last?: TaskInstance<T>;
readonly lastCanceled?: TaskInstance<T>;
readonly lastComplete?: TaskInstance<T>;
readonly lastErrored?: TaskInstance<T>;
readonly lastIncomplete?: TaskInstance<T>;
readonly lastPerformed?: TaskInstance<T>;
readonly lastRunning?: TaskInstance<T>;
readonly lastSuccessful?: TaskInstance<T>;
readonly performCount: number;
readonly state: TaskState;
cancelAll(): void;
};
export function task<T, A>(generatorFn: (a: A) => Iterator<T>): Task<T, (a: A) => TaskInstance<T>>;
export function task<T, A1, A2>(
generatorFn: (a1: A1, a2: A2) => Iterator<T>
): Task<T, (a1: A1, a2: A2) => TaskInstance<T>>;
export function task<T, A1, A2, A3>(
generatorFn: (a1: A1, a2: A2, a3: A3) => Iterator<T>
): Task<T, (a1: A1, a2: A2, a3: A3) => TaskInstance<T>>;
export function task<T, A1, A2, A3, A4>(
generatorFn: (a1: A1, a2: A2, a3: A3, a4: A4) => Iterator<T>
): Task<T, (a1: A1, a2: A2, a3: A3, a4: A4) => TaskInstance<T>>;
export function task<T, A1, A2, A3, A4, A5>(
generatorFn: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5) => Iterator<T>
): Task<T, (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5) => TaskInstance<T>>;
export function task<T, A1, A2, A3, A4, A5, A6>(
generatorFn: (a1: A1, a2: A2, a3: A3, a4: A4, a6: A6) => Iterator<T>
): Task<T, (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6) => TaskInstance<T>>;
}

View File

@ -23,24 +23,6 @@ declare module 'wherehows-web/utils/datasets/compliance-policy';
declare module 'ember-cli-mirage';
declare module 'ember-concurrency' {
class TaskInstance {}
class TaskProperty {
perform(...args: Array<any>): TaskInstance;
on(): this;
cancelOn(eventNames: string): this;
debug(): this;
drop(): this;
restartable(): this;
enqueue(): this;
keepLatest(): this;
performs(): this;
maxConcurrency(n: number): this;
}
export function task(...args: Array<any>): TaskProperty;
export function timeout(delay: number): Promise<void>;
}
// https://github.com/ember-cli/ember-fetch/issues/72
// TS assumes the mapping btw ES modules and CJS modules is 1:1
// However, `ember-fetch` is the module name, but it's imported with `fetch`

View File

@ -12,7 +12,7 @@ import { getJSON, postJSON } from 'wherehows-web/utils/api/fetcher';
/**
* Defines a string enum for valid owner types
*/
export enum OwnerIdType {
enum OwnerIdType {
User = 'USER',
Group = 'GROUP'
}
@ -21,7 +21,7 @@ export enum OwnerIdType {
* Defines the string enum for the OwnerType attribute
* @type {string}
*/
export enum OwnerType {
enum OwnerType {
Owner = 'Owner',
Consumer = 'Consumer',
Delegate = 'Delegate',
@ -32,12 +32,12 @@ export enum OwnerType {
/**
* Accepted string values for the namespace of a user
*/
export enum OwnerUrnNamespace {
enum OwnerUrnNamespace {
corpUser = 'urn:li:corpuser',
groupUser = 'urn:li:corpGroup'
}
export enum OwnerSource {
enum OwnerSource {
Scm = 'SCM',
Nuage = 'NUAGE',
Sos = 'SOS',
@ -71,7 +71,7 @@ const partyEntitiesUrl = `${ApiRoot}/party/entities`;
* @param {number} id the dataset Id
* @return {Promise<Array<IOwner>>} the current list of dataset owners
*/
export const readDatasetOwners = async (id: number): Promise<Array<IOwner>> => {
const readDatasetOwners = async (id: number): Promise<Array<IOwner>> => {
const { owners = [], status, msg } = await getJSON<IOwnerResponse>({ url: datasetOwnersUrlById(id) });
if (status === ApiStatus.OK) {
return owners.map(owner => ({
@ -90,7 +90,7 @@ export const readDatasetOwners = async (id: number): Promise<Array<IOwner>> => {
* @param {Array<IOwner>} updatedOwners the updated list of owners for this dataset
* @return {Promise<IOwnerPostResponse>}
*/
export const updateDatasetOwners = async (
const updateDatasetOwners = async (
id: number,
csrfToken: string,
updatedOwners: Array<IOwner>
@ -115,7 +115,7 @@ export const updateDatasetOwners = async (
* Requests party entities and if the response status is OK, resolves with an array of entities
* @return {Promise<Array<IPartyEntity>>}
*/
export const readPartyEntities = async (): Promise<Array<IPartyEntity>> => {
const readPartyEntities = async (): Promise<Array<IPartyEntity>> => {
const { status, userEntities = [], msg } = await getJSON<IPartyEntityResponse>({ url: partyEntitiesUrl });
return status === ApiStatus.OK ? userEntities : Promise.reject(msg);
};
@ -127,7 +127,7 @@ export const readPartyEntities = async (): Promise<Array<IPartyEntity>> => {
* userEntitiesSource property is also lazy evaluated and cached for app lifetime.
* @type {() => Promise<IPartyProps>}
*/
export const getUserEntities: () => Promise<IPartyProps> = (() => {
const getUserEntities: () => Promise<IPartyProps> = (() => {
/**
* Memoized reference to the resolved value of a previous invocation to curried function in getUserEntities
* @type {{result: IPartyProps | null}}
@ -177,18 +177,40 @@ export const getUserEntities: () => Promise<IPartyProps> = (() => {
* @param {Array<IPartyEntity>} partyEntities
* @return {IUserEntityMap}
*/
export const readPartyEntitiesMap = (partyEntities: Array<IPartyEntity>): IUserEntityMap =>
const readPartyEntitiesMap = (partyEntities: Array<IPartyEntity>): IUserEntityMap =>
partyEntities.reduce(
(map: { [label: string]: string }, { label, displayName }: IPartyEntity) => ((map[label] = displayName), map),
{}
);
/**
* Filters out a list of valid confirmed owners in a list of owners
* @param {Array<IOwner>} [owners=[]] the owners to filter
* @returns {Array<IOwner>}
*/
const validConfirmedOwners = (owners: Array<IOwner> = []): Array<IOwner> =>
owners.filter(
({ confirmedBy, type, idType }) => confirmedBy && type === OwnerType.Owner && idType === OwnerIdType.User
);
/**
* Checks that the required minimum number of confirmed users is met with the type Owner and idType User
* @param {Array<IOwner>} owners the list of owners to check
* @return {boolean}
*/
export const isRequiredMinOwnersNotConfirmed = (owners: Array<IOwner> = []): boolean =>
owners.filter(
({ confirmedBy, type, idType }) => confirmedBy && type === OwnerType.Owner && idType === OwnerIdType.User
).length < minRequiredConfirmed;
const isRequiredMinOwnersNotConfirmed = (owners: Array<IOwner> = []): boolean =>
validConfirmedOwners(owners).length < minRequiredConfirmed;
export {
validConfirmedOwners,
isRequiredMinOwnersNotConfirmed,
readDatasetOwners,
readPartyEntities,
readPartyEntitiesMap,
getUserEntities,
updateDatasetOwners,
OwnerIdType,
OwnerType,
OwnerUrnNamespace,
OwnerSource
};