Skip to content

Commit

Permalink
Change design of lists in web UI (mastodon#32881)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gargron authored Nov 21, 2024
1 parent 7385016 commit 6260350
Show file tree
Hide file tree
Showing 39 changed files with 1,395 additions and 1,350 deletions.
285 changes: 0 additions & 285 deletions app/javascript/mastodon/actions/lists.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import api from '../api';

import { showAlertForError } from './alerts';
import { importFetchedAccounts } from './importer';

export const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST';
export const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS';
export const LIST_FETCH_FAIL = 'LIST_FETCH_FAIL';
Expand All @@ -11,45 +8,10 @@ export const LISTS_FETCH_REQUEST = 'LISTS_FETCH_REQUEST';
export const LISTS_FETCH_SUCCESS = 'LISTS_FETCH_SUCCESS';
export const LISTS_FETCH_FAIL = 'LISTS_FETCH_FAIL';

export const LIST_EDITOR_TITLE_CHANGE = 'LIST_EDITOR_TITLE_CHANGE';
export const LIST_EDITOR_RESET = 'LIST_EDITOR_RESET';
export const LIST_EDITOR_SETUP = 'LIST_EDITOR_SETUP';

export const LIST_CREATE_REQUEST = 'LIST_CREATE_REQUEST';
export const LIST_CREATE_SUCCESS = 'LIST_CREATE_SUCCESS';
export const LIST_CREATE_FAIL = 'LIST_CREATE_FAIL';

export const LIST_UPDATE_REQUEST = 'LIST_UPDATE_REQUEST';
export const LIST_UPDATE_SUCCESS = 'LIST_UPDATE_SUCCESS';
export const LIST_UPDATE_FAIL = 'LIST_UPDATE_FAIL';

export const LIST_DELETE_REQUEST = 'LIST_DELETE_REQUEST';
export const LIST_DELETE_SUCCESS = 'LIST_DELETE_SUCCESS';
export const LIST_DELETE_FAIL = 'LIST_DELETE_FAIL';

export const LIST_ACCOUNTS_FETCH_REQUEST = 'LIST_ACCOUNTS_FETCH_REQUEST';
export const LIST_ACCOUNTS_FETCH_SUCCESS = 'LIST_ACCOUNTS_FETCH_SUCCESS';
export const LIST_ACCOUNTS_FETCH_FAIL = 'LIST_ACCOUNTS_FETCH_FAIL';

export const LIST_EDITOR_SUGGESTIONS_CHANGE = 'LIST_EDITOR_SUGGESTIONS_CHANGE';
export const LIST_EDITOR_SUGGESTIONS_READY = 'LIST_EDITOR_SUGGESTIONS_READY';
export const LIST_EDITOR_SUGGESTIONS_CLEAR = 'LIST_EDITOR_SUGGESTIONS_CLEAR';

export const LIST_EDITOR_ADD_REQUEST = 'LIST_EDITOR_ADD_REQUEST';
export const LIST_EDITOR_ADD_SUCCESS = 'LIST_EDITOR_ADD_SUCCESS';
export const LIST_EDITOR_ADD_FAIL = 'LIST_EDITOR_ADD_FAIL';

export const LIST_EDITOR_REMOVE_REQUEST = 'LIST_EDITOR_REMOVE_REQUEST';
export const LIST_EDITOR_REMOVE_SUCCESS = 'LIST_EDITOR_REMOVE_SUCCESS';
export const LIST_EDITOR_REMOVE_FAIL = 'LIST_EDITOR_REMOVE_FAIL';

export const LIST_ADDER_RESET = 'LIST_ADDER_RESET';
export const LIST_ADDER_SETUP = 'LIST_ADDER_SETUP';

export const LIST_ADDER_LISTS_FETCH_REQUEST = 'LIST_ADDER_LISTS_FETCH_REQUEST';
export const LIST_ADDER_LISTS_FETCH_SUCCESS = 'LIST_ADDER_LISTS_FETCH_SUCCESS';
export const LIST_ADDER_LISTS_FETCH_FAIL = 'LIST_ADDER_LISTS_FETCH_FAIL';

export const fetchList = id => (dispatch, getState) => {
if (getState().getIn(['lists', id])) {
return;
Expand Down Expand Up @@ -100,89 +62,6 @@ export const fetchListsFail = error => ({
error,
});

export const submitListEditor = shouldReset => (dispatch, getState) => {
const listId = getState().getIn(['listEditor', 'listId']);
const title = getState().getIn(['listEditor', 'title']);

if (listId === null) {
dispatch(createList(title, shouldReset));
} else {
dispatch(updateList(listId, title, shouldReset));
}
};

export const setupListEditor = listId => (dispatch, getState) => {
dispatch({
type: LIST_EDITOR_SETUP,
list: getState().getIn(['lists', listId]),
});

dispatch(fetchListAccounts(listId));
};

export const changeListEditorTitle = value => ({
type: LIST_EDITOR_TITLE_CHANGE,
value,
});

export const createList = (title, shouldReset) => (dispatch) => {
dispatch(createListRequest());

api().post('/api/v1/lists', { title }).then(({ data }) => {
dispatch(createListSuccess(data));

if (shouldReset) {
dispatch(resetListEditor());
}
}).catch(err => dispatch(createListFail(err)));
};

export const createListRequest = () => ({
type: LIST_CREATE_REQUEST,
});

export const createListSuccess = list => ({
type: LIST_CREATE_SUCCESS,
list,
});

export const createListFail = error => ({
type: LIST_CREATE_FAIL,
error,
});

export const updateList = (id, title, shouldReset, isExclusive, replies_policy) => (dispatch) => {
dispatch(updateListRequest(id));

api().put(`/api/v1/lists/${id}`, { title, replies_policy, exclusive: typeof isExclusive === 'undefined' ? undefined : !!isExclusive }).then(({ data }) => {
dispatch(updateListSuccess(data));

if (shouldReset) {
dispatch(resetListEditor());
}
}).catch(err => dispatch(updateListFail(id, err)));
};

export const updateListRequest = id => ({
type: LIST_UPDATE_REQUEST,
id,
});

export const updateListSuccess = list => ({
type: LIST_UPDATE_SUCCESS,
list,
});

export const updateListFail = (id, error) => ({
type: LIST_UPDATE_FAIL,
id,
error,
});

export const resetListEditor = () => ({
type: LIST_EDITOR_RESET,
});

export const deleteList = id => (dispatch) => {
dispatch(deleteListRequest(id));

Expand All @@ -206,167 +85,3 @@ export const deleteListFail = (id, error) => ({
id,
error,
});

export const fetchListAccounts = listId => (dispatch) => {
dispatch(fetchListAccountsRequest(listId));

api().get(`/api/v1/lists/${listId}/accounts`, { params: { limit: 0 } }).then(({ data }) => {
dispatch(importFetchedAccounts(data));
dispatch(fetchListAccountsSuccess(listId, data));
}).catch(err => dispatch(fetchListAccountsFail(listId, err)));
};

export const fetchListAccountsRequest = id => ({
type: LIST_ACCOUNTS_FETCH_REQUEST,
id,
});

export const fetchListAccountsSuccess = (id, accounts, next) => ({
type: LIST_ACCOUNTS_FETCH_SUCCESS,
id,
accounts,
next,
});

export const fetchListAccountsFail = (id, error) => ({
type: LIST_ACCOUNTS_FETCH_FAIL,
id,
error,
});

export const fetchListSuggestions = q => (dispatch) => {
const params = {
q,
resolve: false,
limit: 4,
following: true,
};

api().get('/api/v1/accounts/search', { params }).then(({ data }) => {
dispatch(importFetchedAccounts(data));
dispatch(fetchListSuggestionsReady(q, data));
}).catch(error => dispatch(showAlertForError(error)));
};

export const fetchListSuggestionsReady = (query, accounts) => ({
type: LIST_EDITOR_SUGGESTIONS_READY,
query,
accounts,
});

export const clearListSuggestions = () => ({
type: LIST_EDITOR_SUGGESTIONS_CLEAR,
});

export const changeListSuggestions = value => ({
type: LIST_EDITOR_SUGGESTIONS_CHANGE,
value,
});

export const addToListEditor = accountId => (dispatch, getState) => {
dispatch(addToList(getState().getIn(['listEditor', 'listId']), accountId));
};

export const addToList = (listId, accountId) => (dispatch) => {
dispatch(addToListRequest(listId, accountId));

api().post(`/api/v1/lists/${listId}/accounts`, { account_ids: [accountId] })
.then(() => dispatch(addToListSuccess(listId, accountId)))
.catch(err => dispatch(addToListFail(listId, accountId, err)));
};

export const addToListRequest = (listId, accountId) => ({
type: LIST_EDITOR_ADD_REQUEST,
listId,
accountId,
});

export const addToListSuccess = (listId, accountId) => ({
type: LIST_EDITOR_ADD_SUCCESS,
listId,
accountId,
});

export const addToListFail = (listId, accountId, error) => ({
type: LIST_EDITOR_ADD_FAIL,
listId,
accountId,
error,
});

export const removeFromListEditor = accountId => (dispatch, getState) => {
dispatch(removeFromList(getState().getIn(['listEditor', 'listId']), accountId));
};

export const removeFromList = (listId, accountId) => (dispatch) => {
dispatch(removeFromListRequest(listId, accountId));

api().delete(`/api/v1/lists/${listId}/accounts`, { params: { account_ids: [accountId] } })
.then(() => dispatch(removeFromListSuccess(listId, accountId)))
.catch(err => dispatch(removeFromListFail(listId, accountId, err)));
};

export const removeFromListRequest = (listId, accountId) => ({
type: LIST_EDITOR_REMOVE_REQUEST,
listId,
accountId,
});

export const removeFromListSuccess = (listId, accountId) => ({
type: LIST_EDITOR_REMOVE_SUCCESS,
listId,
accountId,
});

export const removeFromListFail = (listId, accountId, error) => ({
type: LIST_EDITOR_REMOVE_FAIL,
listId,
accountId,
error,
});

export const resetListAdder = () => ({
type: LIST_ADDER_RESET,
});

export const setupListAdder = accountId => (dispatch, getState) => {
dispatch({
type: LIST_ADDER_SETUP,
account: getState().getIn(['accounts', accountId]),
});
dispatch(fetchLists());
dispatch(fetchAccountLists(accountId));
};

export const fetchAccountLists = accountId => (dispatch) => {
dispatch(fetchAccountListsRequest(accountId));

api().get(`/api/v1/accounts/${accountId}/lists`)
.then(({ data }) => dispatch(fetchAccountListsSuccess(accountId, data)))
.catch(err => dispatch(fetchAccountListsFail(accountId, err)));
};

export const fetchAccountListsRequest = id => ({
type:LIST_ADDER_LISTS_FETCH_REQUEST,
id,
});

export const fetchAccountListsSuccess = (id, lists) => ({
type: LIST_ADDER_LISTS_FETCH_SUCCESS,
id,
lists,
});

export const fetchAccountListsFail = (id, err) => ({
type: LIST_ADDER_LISTS_FETCH_FAIL,
id,
err,
});

export const addToListAdder = listId => (dispatch, getState) => {
dispatch(addToList(listId, getState().getIn(['listAdder', 'accountId'])));
};

export const removeFromListAdder = listId => (dispatch, getState) => {
dispatch(removeFromList(listId, getState().getIn(['listAdder', 'accountId'])));
};
13 changes: 13 additions & 0 deletions app/javascript/mastodon/actions/lists_typed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { apiCreate, apiUpdate } from 'mastodon/api/lists';
import type { List } from 'mastodon/models/list';
import { createDataLoadingThunk } from 'mastodon/store/typed_functions';

export const createList = createDataLoadingThunk(
'list/create',
(list: Partial<List>) => apiCreate(list),
);

export const updateList = createDataLoadingThunk(
'list/update',
(list: Partial<List>) => apiUpdate(list),
);
1 change: 1 addition & 0 deletions app/javascript/mastodon/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export async function apiRequest<ApiResponse = unknown>(
method: Method,
url: string,
args: {
signal?: AbortSignal;
params?: RequestParamsOrData;
data?: RequestParamsOrData;
timeout?: number;
Expand Down
32 changes: 32 additions & 0 deletions app/javascript/mastodon/api/lists.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {
apiRequestPost,
apiRequestPut,
apiRequestGet,
apiRequestDelete,
} from 'mastodon/api';
import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
import type { ApiListJSON } from 'mastodon/api_types/lists';

export const apiCreate = (list: Partial<ApiListJSON>) =>
apiRequestPost<ApiListJSON>('v1/lists', list);

export const apiUpdate = (list: Partial<ApiListJSON>) =>
apiRequestPut<ApiListJSON>(`v1/lists/${list.id}`, list);

export const apiGetAccounts = (listId: string) =>
apiRequestGet<ApiAccountJSON[]>(`v1/lists/${listId}/accounts`, {
limit: 0,
});

export const apiGetAccountLists = (accountId: string) =>
apiRequestGet<ApiListJSON[]>(`v1/accounts/${accountId}/lists`);

export const apiAddAccountToList = (listId: string, accountId: string) =>
apiRequestPost(`v1/lists/${listId}/accounts`, {
account_ids: [accountId],
});

export const apiRemoveAccountFromList = (listId: string, accountId: string) =>
apiRequestDelete(`v1/lists/${listId}/accounts`, {
account_ids: [accountId],
});
10 changes: 10 additions & 0 deletions app/javascript/mastodon/api_types/lists.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// See app/serializers/rest/list_serializer.rb

export type RepliesPolicyType = 'list' | 'followed' | 'none';

export interface ApiListJSON {
id: string;
title: string;
exclusive: boolean;
replies_policy: RepliesPolicyType;
}
Loading

0 comments on commit 6260350

Please sign in to comment.