feat: Memberships (#1032)

* WIP

* feat: Add collection.memberships endpoint

* feat: Add ability to filter collection.memberships with query

* WIP

* Merge stashed work

* feat: Add ability to filter memberships by permission

* continued refactoring

* paginated list component

* Collection member management

* fix: Incorrect policy data sent down after collection.update

* Reduce duplication, add empty state

* cleanup

* fix: Modal close should be a real button

* fix: Allow opening edit from modal

* fix: remove unused methods

* test: fix

* Passing test suite

* Refactor

* fix: Flow UI errors

* test: Add collections.update tests

* lint

* test: moar tests

* fix: Missing scopes, more missing tests

* fix: Handle collection privacy change over socket

* fix: More membership scopes

* fix: view endpoint permissions

* fix: respond to privacy change on socket event

* policy driven menus

* fix: share endpoint policies

* chore: Use policies to drive documents UI

* alignment

* fix: Header height

* fix: Correct behavior when collection becomes private

* fix: Header height for read-only collection

* send id's over socket instead of serialized objects

* fix: Remote policy change

* fix: reduce collection fetching

* More websocket efficiencies

* fix: Document collection pinning

* fix: Restored ability to edit drafts
fix: Removed ability to star drafts

* fix: Require write permissions to pin doc to collection

* fix: Header title overlaying document actions at small screen sizes

* fix: Jank on load caused by previous commit

* fix: Double collection fetch post-publish

* fix: Hide publish button if draft is in no longer accessible collection

* fix: Always allow deleting drafts
fix: Improved handling of deleted documents

* feat: Show collections in drafts view
feat: Show more obvious 'draft' badge on documents

* fix: incorrect policies after publish to private collection

* fix: Duplicating a draft publishes it
This commit is contained in:
Tom Moor
2019-10-05 18:42:03 -07:00
committed by GitHub
parent 4164fc178c
commit b42e9737b6
72 changed files with 2360 additions and 765 deletions

View File

@@ -1,17 +1,14 @@
// @flow
import invariant from 'invariant';
import { map, without, pick, filter } from 'lodash';
import { pick } from 'lodash';
import { action, computed, observable } from 'mobx';
import BaseModel from 'models/BaseModel';
import Document from 'models/Document';
import User from 'models/User';
import { client } from 'utils/ApiClient';
import type { NavigationNode } from 'types';
export default class Collection extends BaseModel {
@observable isSaving: boolean;
@observable isLoadingUsers: boolean;
@observable userIds: string[] = [];
id: string;
name: string;
@@ -48,45 +45,6 @@ export default class Collection extends BaseModel {
return results;
}
@computed
get users(): User[] {
return filter(this.store.rootStore.users.active, user =>
this.userIds.includes(user.id)
);
}
@action
async fetchUsers() {
this.isLoadingUsers = true;
try {
const res = await client.post('/collections.users', { id: this.id });
invariant(res && res.data, 'User data should be available');
this.userIds = map(res.data, user => user.id);
res.data.forEach(this.store.rootStore.users.add);
} finally {
this.isLoadingUsers = false;
}
}
@action
async addUser(user: User) {
await client.post('/collections.add_user', {
id: this.id,
userId: user.id,
});
this.userIds = this.userIds.concat(user.id);
}
@action
async removeUser(user: User) {
await client.post('/collections.remove_user', {
id: this.id,
userId: user.id,
});
this.userIds = without(this.userIds, user.id);
}
@action
updateDocument(document: Document) {
const travelDocuments = (documentList, path) =>

View File

@@ -102,7 +102,9 @@ export default class Document extends BaseModel {
pin = async () => {
this.pinned = true;
try {
await this.store.pin(this);
const res = await this.store.pin(this);
invariant(res && res.data, 'Data should be available');
this.updateFromJson(res.data);
} catch (err) {
this.pinned = false;
throw err;
@@ -113,7 +115,9 @@ export default class Document extends BaseModel {
unpin = async () => {
this.pinned = false;
try {
await this.store.unpin(this);
const res = await this.store.unpin(this);
invariant(res && res.data, 'Data should be available');
this.updateFromJson(res.data);
} catch (err) {
this.pinned = true;
throw err;
@@ -147,7 +151,6 @@ export default class Document extends BaseModel {
if (this.isSaving) return this;
const isCreating = !this.id;
const wasDraft = !this.publishedAt;
this.isSaving = true;
this.updateTitle();
@@ -170,11 +173,6 @@ export default class Document extends BaseModel {
...options,
});
} finally {
if (wasDraft && options.publish) {
this.store.rootStore.collections.fetch(this.collectionId, {
force: true,
});
}
this.isSaving = false;
}
};

22
app/models/Membership.js Normal file
View File

@@ -0,0 +1,22 @@
// @flow
import { computed } from 'mobx';
import BaseModel from './BaseModel';
class Membership extends BaseModel {
id: string;
userId: string;
collectionId: string;
permission: string;
@computed
get isEditor(): boolean {
return this.permission === 'read_write';
}
@computed
get isMaintainer(): boolean {
return this.permission === 'maintainer';
}
}
export default Membership;