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 UserLookup from 'wherehows-web/services/user-lookup';
import CurrentUser from 'wherehows-web/services/current-user'; import CurrentUser from 'wherehows-web/services/current-user';
import { IOwner } from 'wherehows-web/typings/api/datasets/owners'; import { IOwner } from 'wherehows-web/typings/api/datasets/owners';
import { ownerAlreadyExists, confirmOwner, updateOwner } from 'wherehows-web/constants/datasets/owner'; import {
import { isRequiredMinOwnersNotConfirmed, OwnerSource, OwnerType } from 'wherehows-web/utils/api/datasets/owners'; 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'; import Notifications, { NotificationEvent } from 'wherehows-web/services/notifications';
/** /**
@ -79,6 +89,15 @@ export default class DatasetAuthors extends Component {
return isRequiredMinOwnersNotConfirmed(get(this, 'confirmedOwners')); 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 * Lists the owners that have be confirmed view the client ui
* @type {ComputedProperty<Array<IOwner>>} * @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 * Sets the `confirmedBy` attribute to the currently logged in user
* @param {IOwner} owner the owner to be updated * @param {IOwner} owner the owner to be updated
* @param {string} confirmedBy the userName of the confirming user * @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); set(owner, 'confirmedBy', confirmedBy || null);
/** /**
* Defines the default properties for a newly created IOwner instance * 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-size: 20px;
font-weight: fw(normal, 4); font-weight: fw(normal, 4);
} }
&__required-count {
height: item-spacing(4);
}
} }
.dataset-author-record { .dataset-author-record {

View File

@ -10,14 +10,14 @@
</div> </div>
</section> </section>
<p class="dataset-author__required-count">
{{#if requiredMinNotConfirmed}} {{#if requiredMinNotConfirmed}}
<p> Add <strong>at least {{ownersRequiredCount}}</strong> owner(s) with ID Type - <code>USER</code>
Add <strong>at least {{sub 2 confirmedOwners.length}}</strong> confirmed owner(s) with ID Type - <code>USER</code>
and Owner Type - <code>Owner</code> and Owner Type - <code>Owner</code>
</p>
{{/if}} {{/if}}
</p>
<section class="dataset-author"> <section class="dataset-author">
<header> <header>
@ -92,7 +92,7 @@
</h2> </h2>
<p class="dataset-author__byline"> <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> </p>
</header> </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-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 // https://github.com/ember-cli/ember-fetch/issues/72
// TS assumes the mapping btw ES modules and CJS modules is 1:1 // 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` // 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 * Defines a string enum for valid owner types
*/ */
export enum OwnerIdType { enum OwnerIdType {
User = 'USER', User = 'USER',
Group = 'GROUP' Group = 'GROUP'
} }
@ -21,7 +21,7 @@ export enum OwnerIdType {
* Defines the string enum for the OwnerType attribute * Defines the string enum for the OwnerType attribute
* @type {string} * @type {string}
*/ */
export enum OwnerType { enum OwnerType {
Owner = 'Owner', Owner = 'Owner',
Consumer = 'Consumer', Consumer = 'Consumer',
Delegate = 'Delegate', Delegate = 'Delegate',
@ -32,12 +32,12 @@ export enum OwnerType {
/** /**
* Accepted string values for the namespace of a user * Accepted string values for the namespace of a user
*/ */
export enum OwnerUrnNamespace { enum OwnerUrnNamespace {
corpUser = 'urn:li:corpuser', corpUser = 'urn:li:corpuser',
groupUser = 'urn:li:corpGroup' groupUser = 'urn:li:corpGroup'
} }
export enum OwnerSource { enum OwnerSource {
Scm = 'SCM', Scm = 'SCM',
Nuage = 'NUAGE', Nuage = 'NUAGE',
Sos = 'SOS', Sos = 'SOS',
@ -71,7 +71,7 @@ const partyEntitiesUrl = `${ApiRoot}/party/entities`;
* @param {number} id the dataset Id * @param {number} id the dataset Id
* @return {Promise<Array<IOwner>>} the current list of dataset owners * @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) }); const { owners = [], status, msg } = await getJSON<IOwnerResponse>({ url: datasetOwnersUrlById(id) });
if (status === ApiStatus.OK) { if (status === ApiStatus.OK) {
return owners.map(owner => ({ 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 * @param {Array<IOwner>} updatedOwners the updated list of owners for this dataset
* @return {Promise<IOwnerPostResponse>} * @return {Promise<IOwnerPostResponse>}
*/ */
export const updateDatasetOwners = async ( const updateDatasetOwners = async (
id: number, id: number,
csrfToken: string, csrfToken: string,
updatedOwners: Array<IOwner> 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 * Requests party entities and if the response status is OK, resolves with an array of entities
* @return {Promise<Array<IPartyEntity>>} * @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 }); const { status, userEntities = [], msg } = await getJSON<IPartyEntityResponse>({ url: partyEntitiesUrl });
return status === ApiStatus.OK ? userEntities : Promise.reject(msg); 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. * userEntitiesSource property is also lazy evaluated and cached for app lifetime.
* @type {() => Promise<IPartyProps>} * @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 * Memoized reference to the resolved value of a previous invocation to curried function in getUserEntities
* @type {{result: IPartyProps | null}} * @type {{result: IPartyProps | null}}
@ -177,18 +177,40 @@ export const getUserEntities: () => Promise<IPartyProps> = (() => {
* @param {Array<IPartyEntity>} partyEntities * @param {Array<IPartyEntity>} partyEntities
* @return {IUserEntityMap} * @return {IUserEntityMap}
*/ */
export const readPartyEntitiesMap = (partyEntities: Array<IPartyEntity>): IUserEntityMap => const readPartyEntitiesMap = (partyEntities: Array<IPartyEntity>): IUserEntityMap =>
partyEntities.reduce( partyEntities.reduce(
(map: { [label: string]: string }, { label, displayName }: IPartyEntity) => ((map[label] = displayName), map), (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 * 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 * @param {Array<IOwner>} owners the list of owners to check
* @return {boolean} * @return {boolean}
*/ */
export const isRequiredMinOwnersNotConfirmed = (owners: Array<IOwner> = []): boolean => const isRequiredMinOwnersNotConfirmed = (owners: Array<IOwner> = []): boolean =>
owners.filter( validConfirmedOwners(owners).length < minRequiredConfirmed;
({ confirmedBy, type, idType }) => confirmedBy && type === OwnerType.Owner && idType === OwnerIdType.User
).length < minRequiredConfirmed; export {
validConfirmedOwners,
isRequiredMinOwnersNotConfirmed,
readDatasetOwners,
readPartyEntities,
readPartyEntitiesMap,
getUserEntities,
updateDatasetOwners,
OwnerIdType,
OwnerType,
OwnerUrnNamespace,
OwnerSource
};