Wip: アンテナ編集画面周辺
This commit is contained in:
parent
041b05b15f
commit
946f5bce3e
51 changed files with 1006 additions and 3665 deletions
|
@ -1,51 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AntennasController < ApplicationController
|
||||
layout 'admin'
|
||||
|
||||
before_action :authenticate_user!
|
||||
before_action :set_antenna, only: [:edit, :update, :destroy]
|
||||
before_action :set_body_classes
|
||||
before_action :set_cache_headers
|
||||
|
||||
def index
|
||||
@antennas = current_account.antennas.includes(:antenna_domains).includes(:antenna_tags).includes(:antenna_accounts)
|
||||
end
|
||||
|
||||
def edit; end
|
||||
|
||||
def update
|
||||
if @antenna.update(resource_params)
|
||||
redirect_to antennas_path
|
||||
else
|
||||
render action: :edit
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@antenna.destroy
|
||||
redirect_to antennas_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_antenna
|
||||
@antenna = current_account.antennas.find(params[:id])
|
||||
end
|
||||
|
||||
def resource_params
|
||||
params.require(:antenna).permit(:title, :available, :expires_in)
|
||||
end
|
||||
|
||||
def thin_resource_params
|
||||
params.require(:antenna).permit(:title)
|
||||
end
|
||||
|
||||
def set_body_classes
|
||||
@body_classes = 'admin'
|
||||
end
|
||||
|
||||
def set_cache_headers
|
||||
response.cache_control.replace(private: true, no_store: true)
|
||||
end
|
||||
end
|
|
@ -1,8 +1,5 @@
|
|||
import api from '../api';
|
||||
|
||||
import { showAlertForError } from './alerts';
|
||||
import { importFetchedAccounts } from './importer';
|
||||
|
||||
export const ANTENNA_FETCH_REQUEST = 'ANTENNA_FETCH_REQUEST';
|
||||
export const ANTENNA_FETCH_SUCCESS = 'ANTENNA_FETCH_SUCCESS';
|
||||
export const ANTENNA_FETCH_FAIL = 'ANTENNA_FETCH_FAIL';
|
||||
|
@ -11,121 +8,10 @@ export const ANTENNAS_FETCH_REQUEST = 'ANTENNAS_FETCH_REQUEST';
|
|||
export const ANTENNAS_FETCH_SUCCESS = 'ANTENNAS_FETCH_SUCCESS';
|
||||
export const ANTENNAS_FETCH_FAIL = 'ANTENNAS_FETCH_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_TITLE_CHANGE = 'ANTENNA_EDITOR_TITLE_CHANGE';
|
||||
export const ANTENNA_EDITOR_RESET = 'ANTENNA_EDITOR_RESET';
|
||||
export const ANTENNA_EDITOR_SETUP = 'ANTENNA_EDITOR_SETUP';
|
||||
|
||||
export const ANTENNA_CREATE_REQUEST = 'ANTENNA_CREATE_REQUEST';
|
||||
export const ANTENNA_CREATE_SUCCESS = 'ANTENNA_CREATE_SUCCESS';
|
||||
export const ANTENNA_CREATE_FAIL = 'ANTENNA_CREATE_FAIL';
|
||||
|
||||
export const ANTENNA_UPDATE_REQUEST = 'ANTENNA_UPDATE_REQUEST';
|
||||
export const ANTENNA_UPDATE_SUCCESS = 'ANTENNA_UPDATE_SUCCESS';
|
||||
export const ANTENNA_UPDATE_FAIL = 'ANTENNA_UPDATE_FAIL';
|
||||
|
||||
export const ANTENNA_DELETE_REQUEST = 'ANTENNA_DELETE_REQUEST';
|
||||
export const ANTENNA_DELETE_SUCCESS = 'ANTENNA_DELETE_SUCCESS';
|
||||
export const ANTENNA_DELETE_FAIL = 'ANTENNA_DELETE_FAIL';
|
||||
|
||||
export const ANTENNA_ACCOUNTS_FETCH_REQUEST = 'ANTENNA_ACCOUNTS_FETCH_REQUEST';
|
||||
export const ANTENNA_ACCOUNTS_FETCH_SUCCESS = 'ANTENNA_ACCOUNTS_FETCH_SUCCESS';
|
||||
export const ANTENNA_ACCOUNTS_FETCH_FAIL = 'ANTENNA_ACCOUNTS_FETCH_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_SUGGESTIONS_CHANGE = 'ANTENNA_EDITOR_SUGGESTIONS_CHANGE';
|
||||
export const ANTENNA_EDITOR_SUGGESTIONS_READY = 'ANTENNA_EDITOR_SUGGESTIONS_READY';
|
||||
export const ANTENNA_EDITOR_SUGGESTIONS_CLEAR = 'ANTENNA_EDITOR_SUGGESTIONS_CLEAR';
|
||||
|
||||
export const ANTENNA_EDITOR_ADD_REQUEST = 'ANTENNA_EDITOR_ADD_REQUEST';
|
||||
export const ANTENNA_EDITOR_ADD_SUCCESS = 'ANTENNA_EDITOR_ADD_SUCCESS';
|
||||
export const ANTENNA_EDITOR_ADD_FAIL = 'ANTENNA_EDITOR_ADD_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_REMOVE_REQUEST = 'ANTENNA_EDITOR_REMOVE_REQUEST';
|
||||
export const ANTENNA_EDITOR_REMOVE_SUCCESS = 'ANTENNA_EDITOR_REMOVE_SUCCESS';
|
||||
export const ANTENNA_EDITOR_REMOVE_FAIL = 'ANTENNA_EDITOR_REMOVE_FAIL';
|
||||
|
||||
export const ANTENNA_EXCLUDE_ACCOUNTS_FETCH_REQUEST = 'ANTENNA_EXCLUDE_ACCOUNTS_FETCH_REQUEST';
|
||||
export const ANTENNA_EXCLUDE_ACCOUNTS_FETCH_SUCCESS = 'ANTENNA_EXCLUDE_ACCOUNTS_FETCH_SUCCESS';
|
||||
export const ANTENNA_EXCLUDE_ACCOUNTS_FETCH_FAIL = 'ANTENNA_EXCLUDE_ACCOUNTS_FETCH_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_ADD_EXCLUDE_REQUEST = 'ANTENNA_EDITOR_ADD_EXCLUDE_REQUEST';
|
||||
export const ANTENNA_EDITOR_ADD_EXCLUDE_SUCCESS = 'ANTENNA_EDITOR_ADD_EXCLUDE_SUCCESS';
|
||||
export const ANTENNA_EDITOR_ADD_EXCLUDE_FAIL = 'ANTENNA_EDITOR_ADD_EXCLUDE_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_REMOVE_EXCLUDE_REQUEST = 'ANTENNA_EDITOR_REMOVE_EXCLUDE_REQUEST';
|
||||
export const ANTENNA_EDITOR_REMOVE_EXCLUDE_SUCCESS = 'ANTENNA_EDITOR_REMOVE_EXCLUDE_SUCCESS';
|
||||
export const ANTENNA_EDITOR_REMOVE_EXCLUDE_FAIL = 'ANTENNA_EDITOR_REMOVE_EXCLUDE_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_FETCH_DOMAINS_REQUEST = 'ANTENNA_EDITOR_FETCH_DOMAINS_REQUEST';
|
||||
export const ANTENNA_EDITOR_FETCH_DOMAINS_SUCCESS = 'ANTENNA_EDITOR_FETCH_DOMAINS_SUCCESS';
|
||||
export const ANTENNA_EDITOR_FETCH_DOMAINS_FAIL = 'ANTENNA_EDITOR_FETCH_DOMAINS_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_ADD_DOMAIN_REQUEST = 'ANTENNA_EDITOR_ADD_DOMAIN_REQUEST';
|
||||
export const ANTENNA_EDITOR_ADD_DOMAIN_SUCCESS = 'ANTENNA_EDITOR_ADD_DOMAIN_SUCCESS';
|
||||
export const ANTENNA_EDITOR_ADD_DOMAIN_FAIL = 'ANTENNA_EDITOR_ADD_DOMAIN_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_ADD_EXCLUDE_DOMAIN_REQUEST = 'ANTENNA_EDITOR_ADD_EXCLUDEDOMAIN_REQUEST';
|
||||
export const ANTENNA_EDITOR_ADD_EXCLUDE_DOMAIN_SUCCESS = 'ANTENNA_EDITOR_ADD_EXCLUDE_DOMAIN_SUCCESS';
|
||||
export const ANTENNA_EDITOR_ADD_EXCLUDE_DOMAIN_FAIL = 'ANTENNA_EDITOR_ADD_EXCLUDE_DOMAIN_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_REMOVE_DOMAIN_REQUEST = 'ANTENNA_EDITOR_REMOVE_DOMAIN_REQUEST';
|
||||
export const ANTENNA_EDITOR_REMOVE_DOMAIN_SUCCESS = 'ANTENNA_EDITOR_REMOVE_DOMAIN_SUCCESS';
|
||||
export const ANTENNA_EDITOR_REMOVE_DOMAIN_FAIL = 'ANTENNA_EDITOR_REMOVE_DOMAIN_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_REMOVE_EXCLUDE_DOMAIN_REQUEST = 'ANTENNA_EDITOR_REMOVE_EXCLUDE_DOMAIN_REQUEST';
|
||||
export const ANTENNA_EDITOR_REMOVE_EXCLUDE_DOMAIN_SUCCESS = 'ANTENNA_EDITOR_REMOVE_EXCLUDE_DOMAIN_SUCCESS';
|
||||
export const ANTENNA_EDITOR_REMOVE_EXCLUDE_DOMAIN_FAIL = 'ANTENNA_EDITOR_REMOVE_EXCLUDE_DOMAIN_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_FETCH_KEYWORDS_REQUEST = 'ANTENNA_EDITOR_FETCH_KEYWORDS_REQUEST';
|
||||
export const ANTENNA_EDITOR_FETCH_KEYWORDS_SUCCESS = 'ANTENNA_EDITOR_FETCH_KEYWORDS_SUCCESS';
|
||||
export const ANTENNA_EDITOR_FETCH_KEYWORDS_FAIL = 'ANTENNA_EDITOR_FETCH_KEYWORDS_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_ADD_KEYWORD_REQUEST = 'ANTENNA_EDITOR_ADD_KEYWORD_REQUEST';
|
||||
export const ANTENNA_EDITOR_ADD_KEYWORD_SUCCESS = 'ANTENNA_EDITOR_ADD_KEYWORD_SUCCESS';
|
||||
export const ANTENNA_EDITOR_ADD_KEYWORD_FAIL = 'ANTENNA_EDITOR_ADD_KEYWORD_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_ADD_EXCLUDE_KEYWORD_REQUEST = 'ANTENNA_EDITOR_ADD_EXCLUDE_KEYWORD_REQUEST';
|
||||
export const ANTENNA_EDITOR_ADD_EXCLUDE_KEYWORD_SUCCESS = 'ANTENNA_EDITOR_ADD_EXCLUDE_KEYWORD_SUCCESS';
|
||||
export const ANTENNA_EDITOR_ADD_EXCLUDE_KEYWORD_FAIL = 'ANTENNA_EDITOR_ADD_EXCLUDE_KEYWORD_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_REMOVE_KEYWORD_REQUEST = 'ANTENNA_EDITOR_REMOVE_KEYWORD_REQUEST';
|
||||
export const ANTENNA_EDITOR_REMOVE_KEYWORD_SUCCESS = 'ANTENNA_EDITOR_REMOVE_KEYWORD_SUCCESS';
|
||||
export const ANTENNA_EDITOR_REMOVE_KEYWORD_FAIL = 'ANTENNA_EDITOR_REMOVE_KEYWORD_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_REMOVE_EXCLUDE_KEYWORD_REQUEST = 'ANTENNA_EDITOR_REMOVE_EXCLUDE_KEYWORD_REQUEST';
|
||||
export const ANTENNA_EDITOR_REMOVE_EXCLUDE_KEYWORD_SUCCESS = 'ANTENNA_EDITOR_REMOVE_EXCLUDE_KEYWORD_SUCCESS';
|
||||
export const ANTENNA_EDITOR_REMOVE_EXCLUDE_KEYWORD_FAIL = 'ANTENNA_EDITOR_REMOVE_EXCLUDE_KEYWORD_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_FETCH_TAGS_REQUEST = 'ANTENNA_EDITOR_FETCH_TAGS_REQUEST';
|
||||
export const ANTENNA_EDITOR_FETCH_TAGS_SUCCESS = 'ANTENNA_EDITOR_FETCH_TAGS_SUCCESS';
|
||||
export const ANTENNA_EDITOR_FETCH_TAGS_FAIL = 'ANTENNA_EDITOR_FETCH_TAGS_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_ADD_TAG_REQUEST = 'ANTENNA_EDITOR_ADD_TAG_REQUEST';
|
||||
export const ANTENNA_EDITOR_ADD_TAG_SUCCESS = 'ANTENNA_EDITOR_ADD_TAG_SUCCESS';
|
||||
export const ANTENNA_EDITOR_ADD_TAG_FAIL = 'ANTENNA_EDITOR_ADD_TAG_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_ADD_EXCLUDE_TAG_REQUEST = 'ANTENNA_EDITOR_ADD_EXCLUDE_TAG_REQUEST';
|
||||
export const ANTENNA_EDITOR_ADD_EXCLUDE_TAG_SUCCESS = 'ANTENNA_EDITOR_ADD_EXCLUDE_TAG_SUCCESS';
|
||||
export const ANTENNA_EDITOR_ADD_EXCLUDE_TAG_FAIL = 'ANTENNA_EDITOR_ADD_EXCLUDE_TAG_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_REMOVE_TAG_REQUEST = 'ANTENNA_EDITOR_REMOVE_TAG_REQUEST';
|
||||
export const ANTENNA_EDITOR_REMOVE_TAG_SUCCESS = 'ANTENNA_EDITOR_REMOVE_TAG_SUCCESS';
|
||||
export const ANTENNA_EDITOR_REMOVE_TAG_FAIL = 'ANTENNA_EDITOR_REMOVE_TAG_FAIL';
|
||||
|
||||
export const ANTENNA_EDITOR_REMOVE_EXCLUDE_TAG_REQUEST = 'ANTENNA_EDITOR_REMOVE_EXCLUDE_TAG_REQUEST';
|
||||
export const ANTENNA_EDITOR_REMOVE_EXCLUDE_TAG_SUCCESS = 'ANTENNA_EDITOR_REMOVE_EXCLUDE_TAG_SUCCESS';
|
||||
export const ANTENNA_EDITOR_REMOVE_EXCLUDE_TAG_FAIL = 'ANTENNA_EDITOR_REMOVE_EXCLUDE_TAG_FAIL';
|
||||
|
||||
export const ANTENNA_ADDER_RESET = 'ANTENNA_ADDER_RESET';
|
||||
export const ANTENNA_ADDER_SETUP = 'ANTENNA_ADDER_SETUP';
|
||||
|
||||
export const ANTENNA_ADDER_ANTENNAS_FETCH_REQUEST = 'ANTENNA_ADDER_ANTENNAS_FETCH_REQUEST';
|
||||
export const ANTENNA_ADDER_ANTENNAS_FETCH_SUCCESS = 'ANTENNA_ADDER_ANTENNAS_FETCH_SUCCESS';
|
||||
export const ANTENNA_ADDER_ANTENNAS_FETCH_FAIL = 'ANTENNA_ADDER_ANTENNAS_FETCH_FAIL';
|
||||
|
||||
export const ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_REQUEST = 'ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_REQUEST';
|
||||
export const ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_SUCCESS = 'ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_SUCCESS';
|
||||
export const ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_FAIL = 'ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_FAIL';
|
||||
|
||||
export const fetchAntenna = id => (dispatch, getState) => {
|
||||
if (getState().getIn(['antennas', id])) {
|
||||
return;
|
||||
|
@ -176,98 +62,6 @@ export const fetchAntennasFail = error => ({
|
|||
error,
|
||||
});
|
||||
|
||||
export const submitAntennaEditor = shouldReset => (dispatch, getState) => {
|
||||
const antennaId = getState().getIn(['antennaEditor', 'antennaId']);
|
||||
const title = getState().getIn(['antennaEditor', 'title']);
|
||||
|
||||
if (antennaId === null) {
|
||||
dispatch(createAntenna(title, shouldReset));
|
||||
} else {
|
||||
dispatch(updateAntenna(antennaId, title, shouldReset));
|
||||
}
|
||||
};
|
||||
|
||||
export const setupAntennaEditor = antennaId => (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: ANTENNA_EDITOR_SETUP,
|
||||
antenna: getState().getIn(['antennas', antennaId]),
|
||||
});
|
||||
|
||||
dispatch(fetchAntennaAccounts(antennaId));
|
||||
};
|
||||
|
||||
export const setupExcludeAntennaEditor = antennaId => (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: ANTENNA_EDITOR_SETUP,
|
||||
antenna: getState().getIn(['antennas', antennaId]),
|
||||
});
|
||||
|
||||
dispatch(fetchAntennaExcludeAccounts(antennaId));
|
||||
};
|
||||
|
||||
export const changeAntennaEditorTitle = value => ({
|
||||
type: ANTENNA_EDITOR_TITLE_CHANGE,
|
||||
value,
|
||||
});
|
||||
|
||||
export const createAntenna = (title, shouldReset) => (dispatch, getState) => {
|
||||
dispatch(createAntennaRequest());
|
||||
|
||||
api(getState).post('/api/v1/antennas', { title }).then(({ data }) => {
|
||||
dispatch(createAntennaSuccess(data));
|
||||
|
||||
if (shouldReset) {
|
||||
dispatch(resetAntennaEditor());
|
||||
}
|
||||
}).catch(err => dispatch(createAntennaFail(err)));
|
||||
};
|
||||
|
||||
export const createAntennaRequest = () => ({
|
||||
type: ANTENNA_CREATE_REQUEST,
|
||||
});
|
||||
|
||||
export const createAntennaSuccess = antenna => ({
|
||||
type: ANTENNA_CREATE_SUCCESS,
|
||||
antenna,
|
||||
});
|
||||
|
||||
export const createAntennaFail = error => ({
|
||||
type: ANTENNA_CREATE_FAIL,
|
||||
error,
|
||||
});
|
||||
|
||||
export const updateAntenna = (id, title, shouldReset, list_id, stl, ltl, with_media_only, ignore_reblog, insert_feeds) => (dispatch, getState) => {
|
||||
dispatch(updateAntennaRequest(id));
|
||||
|
||||
api(getState).put(`/api/v1/antennas/${id}`, { title, list_id, stl, ltl, with_media_only, ignore_reblog, insert_feeds }).then(({ data }) => {
|
||||
dispatch(updateAntennaSuccess(data));
|
||||
|
||||
if (shouldReset) {
|
||||
dispatch(resetAntennaEditor());
|
||||
}
|
||||
}).catch(err => dispatch(updateAntennaFail(id, err)));
|
||||
};
|
||||
|
||||
export const updateAntennaRequest = id => ({
|
||||
type: ANTENNA_UPDATE_REQUEST,
|
||||
id,
|
||||
});
|
||||
|
||||
export const updateAntennaSuccess = antenna => ({
|
||||
type: ANTENNA_UPDATE_SUCCESS,
|
||||
antenna,
|
||||
});
|
||||
|
||||
export const updateAntennaFail = (id, error) => ({
|
||||
type: ANTENNA_UPDATE_FAIL,
|
||||
id,
|
||||
error,
|
||||
});
|
||||
|
||||
export const resetAntennaEditor = () => ({
|
||||
type: ANTENNA_EDITOR_RESET,
|
||||
});
|
||||
|
||||
export const deleteAntenna = id => (dispatch, getState) => {
|
||||
dispatch(deleteAntennaRequest(id));
|
||||
|
||||
|
@ -291,696 +85,3 @@ export const deleteAntennaFail = (id, error) => ({
|
|||
id,
|
||||
error,
|
||||
});
|
||||
|
||||
export const fetchAntennaAccounts = antennaId => (dispatch, getState) => {
|
||||
dispatch(fetchAntennaAccountsRequest(antennaId));
|
||||
|
||||
api(getState).get(`/api/v1/antennas/${antennaId}/accounts`, { params: { limit: 0 } }).then(({ data }) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
dispatch(fetchAntennaAccountsSuccess(antennaId, data));
|
||||
}).catch(err => dispatch(fetchAntennaAccountsFail(antennaId, err)));
|
||||
};
|
||||
|
||||
export const fetchAntennaAccountsRequest = id => ({
|
||||
type: ANTENNA_ACCOUNTS_FETCH_REQUEST,
|
||||
id,
|
||||
});
|
||||
|
||||
export const fetchAntennaAccountsSuccess = (id, accounts, next) => ({
|
||||
type: ANTENNA_ACCOUNTS_FETCH_SUCCESS,
|
||||
id,
|
||||
accounts,
|
||||
next,
|
||||
});
|
||||
|
||||
export const fetchAntennaAccountsFail = (id, error) => ({
|
||||
type: ANTENNA_ACCOUNTS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
});
|
||||
|
||||
export const fetchAntennaExcludeAccounts = antennaId => (dispatch, getState) => {
|
||||
dispatch(fetchAntennaExcludeAccountsRequest(antennaId));
|
||||
|
||||
api(getState).get(`/api/v1/antennas/${antennaId}/exclude_accounts`, { params: { limit: 0 } }).then(({ data }) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
dispatch(fetchAntennaExcludeAccountsSuccess(antennaId, data));
|
||||
}).catch(err => dispatch(fetchAntennaExcludeAccountsFail(antennaId, err)));
|
||||
};
|
||||
|
||||
export const fetchAntennaExcludeAccountsRequest = id => ({
|
||||
type: ANTENNA_EXCLUDE_ACCOUNTS_FETCH_REQUEST,
|
||||
id,
|
||||
});
|
||||
|
||||
export const fetchAntennaExcludeAccountsSuccess = (id, accounts, next) => ({
|
||||
type: ANTENNA_EXCLUDE_ACCOUNTS_FETCH_SUCCESS,
|
||||
id,
|
||||
accounts,
|
||||
next,
|
||||
});
|
||||
|
||||
export const fetchAntennaExcludeAccountsFail = (id, error) => ({
|
||||
type: ANTENNA_EXCLUDE_ACCOUNTS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
});
|
||||
|
||||
export const fetchAntennaSuggestions = q => (dispatch, getState) => {
|
||||
const params = {
|
||||
q,
|
||||
resolve: false,
|
||||
};
|
||||
|
||||
api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
dispatch(fetchAntennaSuggestionsReady(q, data));
|
||||
}).catch(error => dispatch(showAlertForError(error)));
|
||||
};
|
||||
|
||||
export const fetchAntennaSuggestionsReady = (query, accounts) => ({
|
||||
type: ANTENNA_EDITOR_SUGGESTIONS_READY,
|
||||
query,
|
||||
accounts,
|
||||
});
|
||||
|
||||
export const clearAntennaSuggestions = () => ({
|
||||
type: ANTENNA_EDITOR_SUGGESTIONS_CLEAR,
|
||||
});
|
||||
|
||||
export const changeAntennaSuggestions = value => ({
|
||||
type: ANTENNA_EDITOR_SUGGESTIONS_CHANGE,
|
||||
value,
|
||||
});
|
||||
|
||||
export const addToAntennaEditor = accountId => (dispatch, getState) => {
|
||||
dispatch(addToAntenna(getState().getIn(['antennaEditor', 'antennaId']), accountId));
|
||||
};
|
||||
|
||||
export const addToAntenna = (antennaId, accountId) => (dispatch, getState) => {
|
||||
dispatch(addToAntennaRequest(antennaId, accountId));
|
||||
|
||||
api(getState).post(`/api/v1/antennas/${antennaId}/accounts`, { account_ids: [accountId] })
|
||||
.then(() => dispatch(addToAntennaSuccess(antennaId, accountId)))
|
||||
.catch(err => dispatch(addToAntennaFail(antennaId, accountId, err)));
|
||||
};
|
||||
|
||||
export const addToAntennaRequest = (antennaId, accountId) => ({
|
||||
type: ANTENNA_EDITOR_ADD_REQUEST,
|
||||
antennaId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
export const addToAntennaSuccess = (antennaId, accountId) => ({
|
||||
type: ANTENNA_EDITOR_ADD_SUCCESS,
|
||||
antennaId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
export const addToAntennaFail = (antennaId, accountId, error) => ({
|
||||
type: ANTENNA_EDITOR_ADD_FAIL,
|
||||
antennaId,
|
||||
accountId,
|
||||
error,
|
||||
});
|
||||
|
||||
export const addExcludeToAntennaEditor = accountId => (dispatch, getState) => {
|
||||
dispatch(addExcludeToAntenna(getState().getIn(['antennaEditor', 'antennaId']), accountId));
|
||||
};
|
||||
|
||||
export const addExcludeToAntenna = (antennaId, accountId) => (dispatch, getState) => {
|
||||
dispatch(addExcludeToAntennaRequest(antennaId, accountId));
|
||||
|
||||
api(getState).post(`/api/v1/antennas/${antennaId}/exclude_accounts`, { account_ids: [accountId] })
|
||||
.then(() => dispatch(addExcludeToAntennaSuccess(antennaId, accountId)))
|
||||
.catch(err => dispatch(addExcludeToAntennaFail(antennaId, accountId, err)));
|
||||
};
|
||||
|
||||
export const addExcludeToAntennaRequest = (antennaId, accountId) => ({
|
||||
type: ANTENNA_EDITOR_ADD_EXCLUDE_REQUEST,
|
||||
antennaId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
export const addExcludeToAntennaSuccess = (antennaId, accountId) => ({
|
||||
type: ANTENNA_EDITOR_ADD_EXCLUDE_SUCCESS,
|
||||
antennaId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
export const addExcludeToAntennaFail = (antennaId, accountId, error) => ({
|
||||
type: ANTENNA_EDITOR_ADD_EXCLUDE_FAIL,
|
||||
antennaId,
|
||||
accountId,
|
||||
error,
|
||||
});
|
||||
|
||||
export const removeFromAntennaEditor = accountId => (dispatch, getState) => {
|
||||
dispatch(removeFromAntenna(getState().getIn(['antennaEditor', 'antennaId']), accountId));
|
||||
};
|
||||
|
||||
export const removeFromAntenna = (antennaId, accountId) => (dispatch, getState) => {
|
||||
dispatch(removeFromAntennaRequest(antennaId, accountId));
|
||||
|
||||
api(getState).delete(`/api/v1/antennas/${antennaId}/accounts`, { params: { account_ids: [accountId] } })
|
||||
.then(() => dispatch(removeFromAntennaSuccess(antennaId, accountId)))
|
||||
.catch(err => dispatch(removeFromAntennaFail(antennaId, accountId, err)));
|
||||
};
|
||||
|
||||
export const removeFromAntennaRequest = (antennaId, accountId) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_REQUEST,
|
||||
antennaId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
export const removeFromAntennaSuccess = (antennaId, accountId) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_SUCCESS,
|
||||
antennaId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
export const removeFromAntennaFail = (antennaId, accountId, error) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_FAIL,
|
||||
antennaId,
|
||||
accountId,
|
||||
error,
|
||||
});
|
||||
|
||||
export const removeExcludeFromAntennaEditor = accountId => (dispatch, getState) => {
|
||||
dispatch(removeExcludeFromAntenna(getState().getIn(['antennaEditor', 'antennaId']), accountId));
|
||||
};
|
||||
|
||||
export const removeExcludeFromAntenna = (antennaId, accountId) => (dispatch, getState) => {
|
||||
dispatch(removeExcludeFromAntennaRequest(antennaId, accountId));
|
||||
|
||||
api(getState).delete(`/api/v1/antennas/${antennaId}/exclude_accounts`, { params: { account_ids: [accountId] } })
|
||||
.then(() => dispatch(removeExcludeFromAntennaSuccess(antennaId, accountId)))
|
||||
.catch(err => dispatch(removeExcludeFromAntennaFail(antennaId, accountId, err)));
|
||||
};
|
||||
|
||||
export const removeExcludeFromAntennaRequest = (antennaId, accountId) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_EXCLUDE_REQUEST,
|
||||
antennaId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
export const removeExcludeFromAntennaSuccess = (antennaId, accountId) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_EXCLUDE_SUCCESS,
|
||||
antennaId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
export const removeExcludeFromAntennaFail = (antennaId, accountId, error) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_EXCLUDE_FAIL,
|
||||
antennaId,
|
||||
accountId,
|
||||
error,
|
||||
});
|
||||
|
||||
export const fetchAntennaDomains = antennaId => (dispatch, getState) => {
|
||||
dispatch(fetchAntennaDomainsRequest(antennaId));
|
||||
|
||||
api(getState).get(`/api/v1/antennas/${antennaId}/domains`, { params: { limit: 0 } }).then(({ data }) => {
|
||||
dispatch(fetchAntennaDomainsSuccess(antennaId, data));
|
||||
}).catch(err => dispatch(fetchAntennaDomainsFail(antennaId, err)));
|
||||
};
|
||||
|
||||
export const fetchAntennaDomainsRequest = id => ({
|
||||
type: ANTENNA_EDITOR_FETCH_DOMAINS_REQUEST,
|
||||
id,
|
||||
});
|
||||
|
||||
export const fetchAntennaDomainsSuccess = (id, domains) => ({
|
||||
type: ANTENNA_EDITOR_FETCH_DOMAINS_SUCCESS,
|
||||
id,
|
||||
domains,
|
||||
});
|
||||
|
||||
export const fetchAntennaDomainsFail = (id, error) => ({
|
||||
type: ANTENNA_EDITOR_FETCH_DOMAINS_FAIL,
|
||||
id,
|
||||
error,
|
||||
});
|
||||
|
||||
export const addDomainToAntenna = (antennaId, domain) => (dispatch, getState) => {
|
||||
dispatch(addDomainToAntennaRequest(antennaId, domain));
|
||||
|
||||
api(getState).post(`/api/v1/antennas/${antennaId}/domains`, { domains: [domain] })
|
||||
.then(() => dispatch(addDomainToAntennaSuccess(antennaId, domain)))
|
||||
.catch(err => dispatch(addDomainToAntennaFail(antennaId, domain, err)));
|
||||
};
|
||||
|
||||
export const addDomainToAntennaRequest = (antennaId, domain) => ({
|
||||
type: ANTENNA_EDITOR_ADD_DOMAIN_REQUEST,
|
||||
antennaId,
|
||||
domain,
|
||||
});
|
||||
|
||||
export const addDomainToAntennaSuccess = (antennaId, domain) => ({
|
||||
type: ANTENNA_EDITOR_ADD_DOMAIN_SUCCESS,
|
||||
antennaId,
|
||||
domain,
|
||||
});
|
||||
|
||||
export const addDomainToAntennaFail = (antennaId, domain, error) => ({
|
||||
type: ANTENNA_EDITOR_ADD_DOMAIN_FAIL,
|
||||
antennaId,
|
||||
domain,
|
||||
error,
|
||||
});
|
||||
|
||||
export const removeDomainFromAntenna = (antennaId, domain) => (dispatch, getState) => {
|
||||
dispatch(removeDomainFromAntennaRequest(antennaId, domain));
|
||||
|
||||
api(getState).delete(`/api/v1/antennas/${antennaId}/domains`, { params: { domains: [domain] } })
|
||||
.then(() => dispatch(removeDomainFromAntennaSuccess(antennaId, domain)))
|
||||
.catch(err => dispatch(removeDomainFromAntennaFail(antennaId, domain, err)));
|
||||
};
|
||||
|
||||
export const removeDomainFromAntennaRequest = (antennaId, domain) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_DOMAIN_REQUEST,
|
||||
antennaId,
|
||||
domain,
|
||||
});
|
||||
|
||||
export const removeDomainFromAntennaSuccess = (antennaId, domain) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_DOMAIN_SUCCESS,
|
||||
antennaId,
|
||||
domain,
|
||||
});
|
||||
|
||||
export const removeDomainFromAntennaFail = (antennaId, domain, error) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_DOMAIN_FAIL,
|
||||
antennaId,
|
||||
domain,
|
||||
error,
|
||||
});
|
||||
|
||||
export const addExcludeDomainToAntenna = (antennaId, domain) => (dispatch, getState) => {
|
||||
dispatch(addExcludeDomainToAntennaRequest(antennaId, domain));
|
||||
|
||||
api(getState).post(`/api/v1/antennas/${antennaId}/exclude_domains`, { domains: [domain] })
|
||||
.then(() => dispatch(addExcludeDomainToAntennaSuccess(antennaId, domain)))
|
||||
.catch(err => dispatch(addExcludeDomainToAntennaFail(antennaId, domain, err)));
|
||||
};
|
||||
|
||||
export const addExcludeDomainToAntennaRequest = (antennaId, domain) => ({
|
||||
type: ANTENNA_EDITOR_ADD_EXCLUDE_DOMAIN_REQUEST,
|
||||
antennaId,
|
||||
domain,
|
||||
});
|
||||
|
||||
export const addExcludeDomainToAntennaSuccess = (antennaId, domain) => ({
|
||||
type: ANTENNA_EDITOR_ADD_EXCLUDE_DOMAIN_SUCCESS,
|
||||
antennaId,
|
||||
domain,
|
||||
});
|
||||
|
||||
export const addExcludeDomainToAntennaFail = (antennaId, domain, error) => ({
|
||||
type: ANTENNA_EDITOR_ADD_EXCLUDE_DOMAIN_FAIL,
|
||||
antennaId,
|
||||
domain,
|
||||
error,
|
||||
});
|
||||
|
||||
export const removeExcludeDomainFromAntenna = (antennaId, domain) => (dispatch, getState) => {
|
||||
dispatch(removeExcludeDomainFromAntennaRequest(antennaId, domain));
|
||||
|
||||
api(getState).delete(`/api/v1/antennas/${antennaId}/exclude_domains`, { params: { domains: [domain] } })
|
||||
.then(() => dispatch(removeExcludeDomainFromAntennaSuccess(antennaId, domain)))
|
||||
.catch(err => dispatch(removeExcludeDomainFromAntennaFail(antennaId, domain, err)));
|
||||
};
|
||||
|
||||
export const removeExcludeDomainFromAntennaRequest = (antennaId, domain) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_EXCLUDE_DOMAIN_REQUEST,
|
||||
antennaId,
|
||||
domain,
|
||||
});
|
||||
|
||||
export const removeExcludeDomainFromAntennaSuccess = (antennaId, domain) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_EXCLUDE_DOMAIN_SUCCESS,
|
||||
antennaId,
|
||||
domain,
|
||||
});
|
||||
|
||||
export const removeExcludeDomainFromAntennaFail = (antennaId, domain, error) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_EXCLUDE_DOMAIN_FAIL,
|
||||
antennaId,
|
||||
domain,
|
||||
error,
|
||||
});
|
||||
|
||||
export const fetchAntennaKeywords = antennaId => (dispatch, getState) => {
|
||||
dispatch(fetchAntennaKeywordsRequest(antennaId));
|
||||
|
||||
api(getState).get(`/api/v1/antennas/${antennaId}/keywords`, { params: { limit: 0 } }).then(({ data }) => {
|
||||
dispatch(fetchAntennaKeywordsSuccess(antennaId, data));
|
||||
}).catch(err => dispatch(fetchAntennaKeywordsFail(antennaId, err)));
|
||||
};
|
||||
|
||||
export const fetchAntennaKeywordsRequest = id => ({
|
||||
type: ANTENNA_EDITOR_FETCH_KEYWORDS_REQUEST,
|
||||
id,
|
||||
});
|
||||
|
||||
export const fetchAntennaKeywordsSuccess = (id, keywords) => ({
|
||||
type: ANTENNA_EDITOR_FETCH_KEYWORDS_SUCCESS,
|
||||
id,
|
||||
keywords,
|
||||
});
|
||||
|
||||
export const fetchAntennaKeywordsFail = (id, error) => ({
|
||||
type: ANTENNA_EDITOR_FETCH_KEYWORDS_FAIL,
|
||||
id,
|
||||
error,
|
||||
});
|
||||
|
||||
export const addKeywordToAntenna = (antennaId, keyword) => (dispatch, getState) => {
|
||||
dispatch(addKeywordToAntennaRequest(antennaId, keyword));
|
||||
|
||||
api(getState).post(`/api/v1/antennas/${antennaId}/keywords`, { keywords: [keyword] })
|
||||
.then(() => dispatch(addKeywordToAntennaSuccess(antennaId, keyword)))
|
||||
.catch(err => dispatch(addKeywordToAntennaFail(antennaId, keyword, err)));
|
||||
};
|
||||
|
||||
export const addKeywordToAntennaRequest = (antennaId, keyword) => ({
|
||||
type: ANTENNA_EDITOR_ADD_KEYWORD_REQUEST,
|
||||
antennaId,
|
||||
keyword,
|
||||
});
|
||||
|
||||
export const addKeywordToAntennaSuccess = (antennaId, keyword) => ({
|
||||
type: ANTENNA_EDITOR_ADD_KEYWORD_SUCCESS,
|
||||
antennaId,
|
||||
keyword,
|
||||
});
|
||||
|
||||
export const addKeywordToAntennaFail = (antennaId, keyword, error) => ({
|
||||
type: ANTENNA_EDITOR_ADD_KEYWORD_FAIL,
|
||||
antennaId,
|
||||
keyword,
|
||||
error,
|
||||
});
|
||||
|
||||
export const removeKeywordFromAntenna = (antennaId, keyword) => (dispatch, getState) => {
|
||||
dispatch(removeKeywordFromAntennaRequest(antennaId, keyword));
|
||||
|
||||
api(getState).delete(`/api/v1/antennas/${antennaId}/keywords`, { params: { keywords: [keyword] } })
|
||||
.then(() => dispatch(removeKeywordFromAntennaSuccess(antennaId, keyword)))
|
||||
.catch(err => dispatch(removeKeywordFromAntennaFail(antennaId, keyword, err)));
|
||||
};
|
||||
|
||||
export const removeKeywordFromAntennaRequest = (antennaId, keyword) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_KEYWORD_REQUEST,
|
||||
antennaId,
|
||||
keyword,
|
||||
});
|
||||
|
||||
export const removeKeywordFromAntennaSuccess = (antennaId, keyword) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_KEYWORD_SUCCESS,
|
||||
antennaId,
|
||||
keyword,
|
||||
});
|
||||
|
||||
export const removeKeywordFromAntennaFail = (antennaId, keyword, error) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_KEYWORD_FAIL,
|
||||
antennaId,
|
||||
keyword,
|
||||
error,
|
||||
});
|
||||
|
||||
export const addExcludeKeywordToAntenna = (antennaId, keyword) => (dispatch, getState) => {
|
||||
dispatch(addExcludeKeywordToAntennaRequest(antennaId, keyword));
|
||||
|
||||
api(getState).post(`/api/v1/antennas/${antennaId}/exclude_keywords`, { keywords: [keyword] })
|
||||
.then(() => dispatch(addExcludeKeywordToAntennaSuccess(antennaId, keyword)))
|
||||
.catch(err => dispatch(addExcludeKeywordToAntennaFail(antennaId, keyword, err)));
|
||||
};
|
||||
|
||||
export const addExcludeKeywordToAntennaRequest = (antennaId, keyword) => ({
|
||||
type: ANTENNA_EDITOR_ADD_EXCLUDE_KEYWORD_REQUEST,
|
||||
antennaId,
|
||||
keyword,
|
||||
});
|
||||
|
||||
export const addExcludeKeywordToAntennaSuccess = (antennaId, keyword) => ({
|
||||
type: ANTENNA_EDITOR_ADD_EXCLUDE_KEYWORD_SUCCESS,
|
||||
antennaId,
|
||||
keyword,
|
||||
});
|
||||
|
||||
export const addExcludeKeywordToAntennaFail = (antennaId, keyword, error) => ({
|
||||
type: ANTENNA_EDITOR_ADD_EXCLUDE_KEYWORD_FAIL,
|
||||
antennaId,
|
||||
keyword,
|
||||
error,
|
||||
});
|
||||
|
||||
export const removeExcludeKeywordFromAntenna = (antennaId, keyword) => (dispatch, getState) => {
|
||||
dispatch(removeExcludeKeywordFromAntennaRequest(antennaId, keyword));
|
||||
|
||||
api(getState).delete(`/api/v1/antennas/${antennaId}/exclude_keywords`, { params: { keywords: [keyword] } })
|
||||
.then(() => dispatch(removeExcludeKeywordFromAntennaSuccess(antennaId, keyword)))
|
||||
.catch(err => dispatch(removeExcludeKeywordFromAntennaFail(antennaId, keyword, err)));
|
||||
};
|
||||
|
||||
export const removeExcludeKeywordFromAntennaRequest = (antennaId, keyword) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_EXCLUDE_KEYWORD_REQUEST,
|
||||
antennaId,
|
||||
keyword,
|
||||
});
|
||||
|
||||
export const removeExcludeKeywordFromAntennaSuccess = (antennaId, keyword) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_EXCLUDE_KEYWORD_SUCCESS,
|
||||
antennaId,
|
||||
keyword,
|
||||
});
|
||||
|
||||
export const removeExcludeKeywordFromAntennaFail = (antennaId, keyword, error) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_EXCLUDE_KEYWORD_FAIL,
|
||||
antennaId,
|
||||
keyword,
|
||||
error,
|
||||
});
|
||||
|
||||
export const fetchAntennaTags = antennaId => (dispatch, getState) => {
|
||||
dispatch(fetchAntennaTagsRequest(antennaId));
|
||||
|
||||
api(getState).get(`/api/v1/antennas/${antennaId}/tags`, { params: { limit: 0 } }).then(({ data }) => {
|
||||
dispatch(fetchAntennaTagsSuccess(antennaId, data));
|
||||
}).catch(err => dispatch(fetchAntennaTagsFail(antennaId, err)));
|
||||
};
|
||||
|
||||
export const fetchAntennaTagsRequest = id => ({
|
||||
type: ANTENNA_EDITOR_FETCH_TAGS_REQUEST,
|
||||
id,
|
||||
});
|
||||
|
||||
export const fetchAntennaTagsSuccess = (id, tags) => ({
|
||||
type: ANTENNA_EDITOR_FETCH_TAGS_SUCCESS,
|
||||
id,
|
||||
tags,
|
||||
});
|
||||
|
||||
export const fetchAntennaTagsFail = (id, error) => ({
|
||||
type: ANTENNA_EDITOR_FETCH_TAGS_FAIL,
|
||||
id,
|
||||
error,
|
||||
});
|
||||
|
||||
export const addTagToAntenna = (antennaId, tag) => (dispatch, getState) => {
|
||||
dispatch(addTagToAntennaRequest(antennaId, tag));
|
||||
|
||||
api(getState).post(`/api/v1/antennas/${antennaId}/tags`, { tags: [tag] })
|
||||
.then(() => dispatch(addTagToAntennaSuccess(antennaId, tag)))
|
||||
.catch(err => dispatch(addTagToAntennaFail(antennaId, tag, err)));
|
||||
};
|
||||
|
||||
export const addTagToAntennaRequest = (antennaId, tag) => ({
|
||||
type: ANTENNA_EDITOR_ADD_TAG_REQUEST,
|
||||
antennaId,
|
||||
tag,
|
||||
});
|
||||
|
||||
export const addTagToAntennaSuccess = (antennaId, tag) => ({
|
||||
type: ANTENNA_EDITOR_ADD_TAG_SUCCESS,
|
||||
antennaId,
|
||||
tag,
|
||||
});
|
||||
|
||||
export const addTagToAntennaFail = (antennaId, tag, error) => ({
|
||||
type: ANTENNA_EDITOR_ADD_TAG_FAIL,
|
||||
antennaId,
|
||||
tag,
|
||||
error,
|
||||
});
|
||||
|
||||
export const removeTagFromAntenna = (antennaId, tag) => (dispatch, getState) => {
|
||||
dispatch(removeTagFromAntennaRequest(antennaId, tag));
|
||||
|
||||
api(getState).delete(`/api/v1/antennas/${antennaId}/tags`, { params: { tags: [tag] } })
|
||||
.then(() => dispatch(removeTagFromAntennaSuccess(antennaId, tag)))
|
||||
.catch(err => dispatch(removeTagFromAntennaFail(antennaId, tag, err)));
|
||||
};
|
||||
|
||||
export const removeTagFromAntennaRequest = (antennaId, tag) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_TAG_REQUEST,
|
||||
antennaId,
|
||||
tag,
|
||||
});
|
||||
|
||||
export const removeTagFromAntennaSuccess = (antennaId, tag) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_TAG_SUCCESS,
|
||||
antennaId,
|
||||
tag,
|
||||
});
|
||||
|
||||
export const removeTagFromAntennaFail = (antennaId, tag, error) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_TAG_FAIL,
|
||||
antennaId,
|
||||
tag,
|
||||
error,
|
||||
});
|
||||
|
||||
export const addExcludeTagToAntenna = (antennaId, tag) => (dispatch, getState) => {
|
||||
dispatch(addExcludeTagToAntennaRequest(antennaId, tag));
|
||||
|
||||
api(getState).post(`/api/v1/antennas/${antennaId}/exclude_tags`, { tags: [tag] })
|
||||
.then(() => dispatch(addExcludeTagToAntennaSuccess(antennaId, tag)))
|
||||
.catch(err => dispatch(addExcludeTagToAntennaFail(antennaId, tag, err)));
|
||||
};
|
||||
|
||||
export const addExcludeTagToAntennaRequest = (antennaId, tag) => ({
|
||||
type: ANTENNA_EDITOR_ADD_EXCLUDE_TAG_REQUEST,
|
||||
antennaId,
|
||||
tag,
|
||||
});
|
||||
|
||||
export const addExcludeTagToAntennaSuccess = (antennaId, tag) => ({
|
||||
type: ANTENNA_EDITOR_ADD_EXCLUDE_TAG_SUCCESS,
|
||||
antennaId,
|
||||
tag,
|
||||
});
|
||||
|
||||
export const addExcludeTagToAntennaFail = (antennaId, tag, error) => ({
|
||||
type: ANTENNA_EDITOR_ADD_EXCLUDE_TAG_FAIL,
|
||||
antennaId,
|
||||
tag,
|
||||
error,
|
||||
});
|
||||
|
||||
export const removeExcludeTagFromAntenna = (antennaId, tag) => (dispatch, getState) => {
|
||||
dispatch(removeExcludeTagFromAntennaRequest(antennaId, tag));
|
||||
|
||||
api(getState).delete(`/api/v1/antennas/${antennaId}/exclude_tags`, { params: { tags: [tag] } })
|
||||
.then(() => dispatch(removeExcludeTagFromAntennaSuccess(antennaId, tag)))
|
||||
.catch(err => dispatch(removeExcludeTagFromAntennaFail(antennaId, tag, err)));
|
||||
};
|
||||
|
||||
export const removeExcludeTagFromAntennaRequest = (antennaId, tag) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_EXCLUDE_TAG_REQUEST,
|
||||
antennaId,
|
||||
tag,
|
||||
});
|
||||
|
||||
export const removeExcludeTagFromAntennaSuccess = (antennaId, tag) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_EXCLUDE_TAG_SUCCESS,
|
||||
antennaId,
|
||||
tag,
|
||||
});
|
||||
|
||||
export const removeExcludeTagFromAntennaFail = (antennaId, tag, error) => ({
|
||||
type: ANTENNA_EDITOR_REMOVE_EXCLUDE_TAG_FAIL,
|
||||
antennaId,
|
||||
tag,
|
||||
error,
|
||||
});
|
||||
|
||||
export const resetAntennaAdder = () => ({
|
||||
type: ANTENNA_ADDER_RESET,
|
||||
});
|
||||
|
||||
export const setupAntennaAdder = accountId => (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: ANTENNA_ADDER_SETUP,
|
||||
account: getState().getIn(['accounts', accountId]),
|
||||
});
|
||||
dispatch(fetchAntennas());
|
||||
dispatch(fetchAccountAntennas(accountId));
|
||||
};
|
||||
|
||||
export const setupExcludeAntennaAdder = accountId => (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: ANTENNA_ADDER_SETUP,
|
||||
account: getState().getIn(['accounts', accountId]),
|
||||
});
|
||||
dispatch(fetchAntennas());
|
||||
dispatch(fetchExcludeAccountAntennas(accountId));
|
||||
};
|
||||
|
||||
export const fetchAccountAntennas = accountId => (dispatch, getState) => {
|
||||
dispatch(fetchAccountAntennasRequest(accountId));
|
||||
|
||||
api(getState).get(`/api/v1/accounts/${accountId}/antennas`)
|
||||
.then(({ data }) => dispatch(fetchAccountAntennasSuccess(accountId, data)))
|
||||
.catch(err => dispatch(fetchAccountAntennasFail(accountId, err)));
|
||||
};
|
||||
|
||||
export const fetchAccountAntennasRequest = id => ({
|
||||
type:ANTENNA_ADDER_ANTENNAS_FETCH_REQUEST,
|
||||
id,
|
||||
});
|
||||
|
||||
export const fetchAccountAntennasSuccess = (id, antennas) => ({
|
||||
type: ANTENNA_ADDER_ANTENNAS_FETCH_SUCCESS,
|
||||
id,
|
||||
antennas,
|
||||
});
|
||||
|
||||
export const fetchAccountAntennasFail = (id, err) => ({
|
||||
type: ANTENNA_ADDER_ANTENNAS_FETCH_FAIL,
|
||||
id,
|
||||
err,
|
||||
});
|
||||
|
||||
export const fetchExcludeAccountAntennas = accountId => (dispatch, getState) => {
|
||||
dispatch(fetchExcludeAccountAntennasRequest(accountId));
|
||||
|
||||
api(getState).get(`/api/v1/accounts/${accountId}/exclude_antennas`)
|
||||
.then(({ data }) => dispatch(fetchExcludeAccountAntennasSuccess(accountId, data)))
|
||||
.catch(err => dispatch(fetchExcludeAccountAntennasFail(accountId, err)));
|
||||
};
|
||||
|
||||
export const fetchExcludeAccountAntennasRequest = id => ({
|
||||
type:ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_REQUEST,
|
||||
id,
|
||||
});
|
||||
|
||||
export const fetchExcludeAccountAntennasSuccess = (id, antennas) => ({
|
||||
type: ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_SUCCESS,
|
||||
id,
|
||||
antennas,
|
||||
});
|
||||
|
||||
export const fetchExcludeAccountAntennasFail = (id, err) => ({
|
||||
type: ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_FAIL,
|
||||
id,
|
||||
err,
|
||||
});
|
||||
|
||||
export const addToAntennaAdder = antennaId => (dispatch, getState) => {
|
||||
dispatch(addToAntenna(antennaId, getState().getIn(['antennaAdder', 'accountId'])));
|
||||
};
|
||||
|
||||
export const removeFromAntennaAdder = antennaId => (dispatch, getState) => {
|
||||
dispatch(removeFromAntenna(antennaId, getState().getIn(['antennaAdder', 'accountId'])));
|
||||
};
|
||||
|
||||
export const addExcludeToAntennaAdder = antennaId => (dispatch, getState) => {
|
||||
dispatch(addExcludeToAntenna(antennaId, getState().getIn(['antennaAdder', 'accountId'])));
|
||||
};
|
||||
|
||||
export const removeExcludeFromAntennaAdder = antennaId => (dispatch, getState) => {
|
||||
dispatch(removeExcludeFromAntenna(antennaId, getState().getIn(['antennaAdder', 'accountId'])));
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import api, { getLinks } from '../api';
|
||||
|
||||
import { showAlertForError } from './alerts';
|
||||
import { importFetchedAccounts, importFetchedStatuses } from './importer';
|
||||
import { importFetchedStatuses } from './importer';
|
||||
|
||||
export const CIRCLE_FETCH_REQUEST = 'CIRCLE_FETCH_REQUEST';
|
||||
export const CIRCLE_FETCH_SUCCESS = 'CIRCLE_FETCH_SUCCESS';
|
||||
|
@ -11,10 +10,6 @@ export const CIRCLES_FETCH_REQUEST = 'CIRCLES_FETCH_REQUEST';
|
|||
export const CIRCLES_FETCH_SUCCESS = 'CIRCLES_FETCH_SUCCESS';
|
||||
export const CIRCLES_FETCH_FAIL = 'CIRCLES_FETCH_FAIL';
|
||||
|
||||
export const CIRCLE_EDITOR_TITLE_CHANGE = 'CIRCLE_EDITOR_TITLE_CHANGE';
|
||||
export const CIRCLE_EDITOR_RESET = 'CIRCLE_EDITOR_RESET';
|
||||
export const CIRCLE_EDITOR_SETUP = 'CIRCLE_EDITOR_SETUP';
|
||||
|
||||
export const CIRCLE_CREATE_REQUEST = 'CIRCLE_CREATE_REQUEST';
|
||||
export const CIRCLE_CREATE_SUCCESS = 'CIRCLE_CREATE_SUCCESS';
|
||||
export const CIRCLE_CREATE_FAIL = 'CIRCLE_CREATE_FAIL';
|
||||
|
@ -27,29 +22,6 @@ export const CIRCLE_DELETE_REQUEST = 'CIRCLE_DELETE_REQUEST';
|
|||
export const CIRCLE_DELETE_SUCCESS = 'CIRCLE_DELETE_SUCCESS';
|
||||
export const CIRCLE_DELETE_FAIL = 'CIRCLE_DELETE_FAIL';
|
||||
|
||||
export const CIRCLE_ACCOUNTS_FETCH_REQUEST = 'CIRCLE_ACCOUNTS_FETCH_REQUEST';
|
||||
export const CIRCLE_ACCOUNTS_FETCH_SUCCESS = 'CIRCLE_ACCOUNTS_FETCH_SUCCESS';
|
||||
export const CIRCLE_ACCOUNTS_FETCH_FAIL = 'CIRCLE_ACCOUNTS_FETCH_FAIL';
|
||||
|
||||
export const CIRCLE_EDITOR_SUGGESTIONS_CHANGE = 'CIRCLE_EDITOR_SUGGESTIONS_CHANGE';
|
||||
export const CIRCLE_EDITOR_SUGGESTIONS_READY = 'CIRCLE_EDITOR_SUGGESTIONS_READY';
|
||||
export const CIRCLE_EDITOR_SUGGESTIONS_CLEAR = 'CIRCLE_EDITOR_SUGGESTIONS_CLEAR';
|
||||
|
||||
export const CIRCLE_EDITOR_ADD_REQUEST = 'CIRCLE_EDITOR_ADD_REQUEST';
|
||||
export const CIRCLE_EDITOR_ADD_SUCCESS = 'CIRCLE_EDITOR_ADD_SUCCESS';
|
||||
export const CIRCLE_EDITOR_ADD_FAIL = 'CIRCLE_EDITOR_ADD_FAIL';
|
||||
|
||||
export const CIRCLE_EDITOR_REMOVE_REQUEST = 'CIRCLE_EDITOR_REMOVE_REQUEST';
|
||||
export const CIRCLE_EDITOR_REMOVE_SUCCESS = 'CIRCLE_EDITOR_REMOVE_SUCCESS';
|
||||
export const CIRCLE_EDITOR_REMOVE_FAIL = 'CIRCLE_EDITOR_REMOVE_FAIL';
|
||||
|
||||
export const CIRCLE_ADDER_RESET = 'CIRCLE_ADDER_RESET';
|
||||
export const CIRCLE_ADDER_SETUP = 'CIRCLE_ADDER_SETUP';
|
||||
|
||||
export const CIRCLE_ADDER_CIRCLES_FETCH_REQUEST = 'CIRCLE_ADDER_CIRCLES_FETCH_REQUEST';
|
||||
export const CIRCLE_ADDER_CIRCLES_FETCH_SUCCESS = 'CIRCLE_ADDER_CIRCLES_FETCH_SUCCESS';
|
||||
export const CIRCLE_ADDER_CIRCLES_FETCH_FAIL = 'CIRCLE_ADDER_CIRCLES_FETCH_FAIL';
|
||||
|
||||
export const CIRCLE_STATUSES_FETCH_REQUEST = 'CIRCLE_STATUSES_FETCH_REQUEST';
|
||||
export const CIRCLE_STATUSES_FETCH_SUCCESS = 'CIRCLE_STATUSES_FETCH_SUCCESS';
|
||||
export const CIRCLE_STATUSES_FETCH_FAIL = 'CIRCLE_STATUSES_FETCH_FAIL';
|
||||
|
@ -108,89 +80,6 @@ export const fetchCirclesFail = error => ({
|
|||
error,
|
||||
});
|
||||
|
||||
export const submitCircleEditor = shouldReset => (dispatch, getState) => {
|
||||
const circleId = getState().getIn(['circleEditor', 'circleId']);
|
||||
const title = getState().getIn(['circleEditor', 'title']);
|
||||
|
||||
if (circleId === null) {
|
||||
dispatch(createCircle(title, shouldReset));
|
||||
} else {
|
||||
dispatch(updateCircle(circleId, title, shouldReset));
|
||||
}
|
||||
};
|
||||
|
||||
export const setupCircleEditor = circleId => (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: CIRCLE_EDITOR_SETUP,
|
||||
circle: getState().getIn(['circles', circleId]),
|
||||
});
|
||||
|
||||
dispatch(fetchCircleAccounts(circleId));
|
||||
};
|
||||
|
||||
export const changeCircleEditorTitle = value => ({
|
||||
type: CIRCLE_EDITOR_TITLE_CHANGE,
|
||||
value,
|
||||
});
|
||||
|
||||
export const createCircle = (title, shouldReset) => (dispatch, getState) => {
|
||||
dispatch(createCircleRequest());
|
||||
|
||||
api(getState).post('/api/v1/circles', { title }).then(({ data }) => {
|
||||
dispatch(createCircleSuccess(data));
|
||||
|
||||
if (shouldReset) {
|
||||
dispatch(resetCircleEditor());
|
||||
}
|
||||
}).catch(err => dispatch(createCircleFail(err)));
|
||||
};
|
||||
|
||||
export const createCircleRequest = () => ({
|
||||
type: CIRCLE_CREATE_REQUEST,
|
||||
});
|
||||
|
||||
export const createCircleSuccess = circle => ({
|
||||
type: CIRCLE_CREATE_SUCCESS,
|
||||
circle,
|
||||
});
|
||||
|
||||
export const createCircleFail = error => ({
|
||||
type: CIRCLE_CREATE_FAIL,
|
||||
error,
|
||||
});
|
||||
|
||||
export const updateCircle = (id, title, shouldReset, isExclusive, replies_policy) => (dispatch, getState) => {
|
||||
dispatch(updateCircleRequest(id));
|
||||
|
||||
api(getState).put(`/api/v1/circles/${id}`, { title, replies_policy, exclusive: typeof isExclusive === 'undefined' ? undefined : !!isExclusive }).then(({ data }) => {
|
||||
dispatch(updateCircleSuccess(data));
|
||||
|
||||
if (shouldReset) {
|
||||
dispatch(resetCircleEditor());
|
||||
}
|
||||
}).catch(err => dispatch(updateCircleFail(id, err)));
|
||||
};
|
||||
|
||||
export const updateCircleRequest = id => ({
|
||||
type: CIRCLE_UPDATE_REQUEST,
|
||||
id,
|
||||
});
|
||||
|
||||
export const updateCircleSuccess = circle => ({
|
||||
type: CIRCLE_UPDATE_SUCCESS,
|
||||
circle,
|
||||
});
|
||||
|
||||
export const updateCircleFail = (id, error) => ({
|
||||
type: CIRCLE_UPDATE_FAIL,
|
||||
id,
|
||||
error,
|
||||
});
|
||||
|
||||
export const resetCircleEditor = () => ({
|
||||
type: CIRCLE_EDITOR_RESET,
|
||||
});
|
||||
|
||||
export const deleteCircle = id => (dispatch, getState) => {
|
||||
dispatch(deleteCircleRequest(id));
|
||||
|
||||
|
@ -215,169 +104,6 @@ export const deleteCircleFail = (id, error) => ({
|
|||
error,
|
||||
});
|
||||
|
||||
export const fetchCircleAccounts = circleId => (dispatch, getState) => {
|
||||
dispatch(fetchCircleAccountsRequest(circleId));
|
||||
|
||||
api(getState).get(`/api/v1/circles/${circleId}/accounts`, { params: { limit: 0 } }).then(({ data }) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
dispatch(fetchCircleAccountsSuccess(circleId, data));
|
||||
}).catch(err => dispatch(fetchCircleAccountsFail(circleId, err)));
|
||||
};
|
||||
|
||||
export const fetchCircleAccountsRequest = id => ({
|
||||
type: CIRCLE_ACCOUNTS_FETCH_REQUEST,
|
||||
id,
|
||||
});
|
||||
|
||||
export const fetchCircleAccountsSuccess = (id, accounts, next) => ({
|
||||
type: CIRCLE_ACCOUNTS_FETCH_SUCCESS,
|
||||
id,
|
||||
accounts,
|
||||
next,
|
||||
});
|
||||
|
||||
export const fetchCircleAccountsFail = (id, error) => ({
|
||||
type: CIRCLE_ACCOUNTS_FETCH_FAIL,
|
||||
id,
|
||||
error,
|
||||
});
|
||||
|
||||
export const fetchCircleSuggestions = q => (dispatch, getState) => {
|
||||
const params = {
|
||||
q,
|
||||
resolve: false,
|
||||
follower: true,
|
||||
};
|
||||
|
||||
api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
dispatch(fetchCircleSuggestionsReady(q, data));
|
||||
}).catch(error => dispatch(showAlertForError(error)));
|
||||
};
|
||||
|
||||
export const fetchCircleSuggestionsReady = (query, accounts) => ({
|
||||
type: CIRCLE_EDITOR_SUGGESTIONS_READY,
|
||||
query,
|
||||
accounts,
|
||||
});
|
||||
|
||||
export const clearCircleSuggestions = () => ({
|
||||
type: CIRCLE_EDITOR_SUGGESTIONS_CLEAR,
|
||||
});
|
||||
|
||||
export const changeCircleSuggestions = value => ({
|
||||
type: CIRCLE_EDITOR_SUGGESTIONS_CHANGE,
|
||||
value,
|
||||
});
|
||||
|
||||
export const addToCircleEditor = accountId => (dispatch, getState) => {
|
||||
dispatch(addToCircle(getState().getIn(['circleEditor', 'circleId']), accountId));
|
||||
};
|
||||
|
||||
export const addToCircle = (circleId, accountId) => (dispatch, getState) => {
|
||||
dispatch(addToCircleRequest(circleId, accountId));
|
||||
|
||||
api(getState).post(`/api/v1/circles/${circleId}/accounts`, { account_ids: [accountId] })
|
||||
.then(() => dispatch(addToCircleSuccess(circleId, accountId)))
|
||||
.catch(err => dispatch(addToCircleFail(circleId, accountId, err)));
|
||||
};
|
||||
|
||||
export const addToCircleRequest = (circleId, accountId) => ({
|
||||
type: CIRCLE_EDITOR_ADD_REQUEST,
|
||||
circleId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
export const addToCircleSuccess = (circleId, accountId) => ({
|
||||
type: CIRCLE_EDITOR_ADD_SUCCESS,
|
||||
circleId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
export const addToCircleFail = (circleId, accountId, error) => ({
|
||||
type: CIRCLE_EDITOR_ADD_FAIL,
|
||||
circleId,
|
||||
accountId,
|
||||
error,
|
||||
});
|
||||
|
||||
export const removeFromCircleEditor = accountId => (dispatch, getState) => {
|
||||
dispatch(removeFromCircle(getState().getIn(['circleEditor', 'circleId']), accountId));
|
||||
};
|
||||
|
||||
export const removeFromCircle = (circleId, accountId) => (dispatch, getState) => {
|
||||
dispatch(removeFromCircleRequest(circleId, accountId));
|
||||
|
||||
api(getState).delete(`/api/v1/circles/${circleId}/accounts`, { params: { account_ids: [accountId] } })
|
||||
.then(() => dispatch(removeFromCircleSuccess(circleId, accountId)))
|
||||
.catch(err => dispatch(removeFromCircleFail(circleId, accountId, err)));
|
||||
};
|
||||
|
||||
export const removeFromCircleRequest = (circleId, accountId) => ({
|
||||
type: CIRCLE_EDITOR_REMOVE_REQUEST,
|
||||
circleId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
export const removeFromCircleSuccess = (circleId, accountId) => ({
|
||||
type: CIRCLE_EDITOR_REMOVE_SUCCESS,
|
||||
circleId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
export const removeFromCircleFail = (circleId, accountId, error) => ({
|
||||
type: CIRCLE_EDITOR_REMOVE_FAIL,
|
||||
circleId,
|
||||
accountId,
|
||||
error,
|
||||
});
|
||||
|
||||
export const resetCircleAdder = () => ({
|
||||
type: CIRCLE_ADDER_RESET,
|
||||
});
|
||||
|
||||
export const setupCircleAdder = accountId => (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: CIRCLE_ADDER_SETUP,
|
||||
account: getState().getIn(['accounts', accountId]),
|
||||
});
|
||||
dispatch(fetchCircles());
|
||||
dispatch(fetchAccountCircles(accountId));
|
||||
};
|
||||
|
||||
export const fetchAccountCircles = accountId => (dispatch, getState) => {
|
||||
dispatch(fetchAccountCirclesRequest(accountId));
|
||||
|
||||
api(getState).get(`/api/v1/accounts/${accountId}/circles`)
|
||||
.then(({ data }) => dispatch(fetchAccountCirclesSuccess(accountId, data)))
|
||||
.catch(err => dispatch(fetchAccountCirclesFail(accountId, err)));
|
||||
};
|
||||
|
||||
export const fetchAccountCirclesRequest = id => ({
|
||||
type:CIRCLE_ADDER_CIRCLES_FETCH_REQUEST,
|
||||
id,
|
||||
});
|
||||
|
||||
export const fetchAccountCirclesSuccess = (id, circles) => ({
|
||||
type: CIRCLE_ADDER_CIRCLES_FETCH_SUCCESS,
|
||||
id,
|
||||
circles,
|
||||
});
|
||||
|
||||
export const fetchAccountCirclesFail = (id, err) => ({
|
||||
type: CIRCLE_ADDER_CIRCLES_FETCH_FAIL,
|
||||
id,
|
||||
err,
|
||||
});
|
||||
|
||||
export const addToCircleAdder = circleId => (dispatch, getState) => {
|
||||
dispatch(addToCircle(circleId, getState().getIn(['circleAdder', 'accountId'])));
|
||||
};
|
||||
|
||||
export const removeFromCircleAdder = circleId => (dispatch, getState) => {
|
||||
dispatch(removeFromCircle(circleId, getState().getIn(['circleAdder', 'accountId'])));
|
||||
};
|
||||
|
||||
export function fetchCircleStatuses(circleId) {
|
||||
return (dispatch, getState) => {
|
||||
if (getState().getIn(['circles', circleId, 'isLoading'])) {
|
||||
|
|
|
@ -24,9 +24,12 @@ export const apiGetExcludeAccounts = (antennaId: string) =>
|
|||
});
|
||||
|
||||
export const apiGetDomains = (antennaId: string) =>
|
||||
apiRequestGet<string[]>(`v1/antennas/${antennaId}/domains`, {
|
||||
limit: 0,
|
||||
});
|
||||
apiRequestGet<{ domains: string[]; exclude_domains: string[] }>(
|
||||
`v1/antennas/${antennaId}/domains`,
|
||||
{
|
||||
limit: 0,
|
||||
},
|
||||
);
|
||||
|
||||
export const apiAddDomain = (antennaId: string, domain: string) =>
|
||||
apiRequestPost(`v1/antennas/${antennaId}/domains`, {
|
||||
|
@ -38,29 +41,70 @@ export const apiRemoveDomain = (antennaId: string, domain: string) =>
|
|||
domains: [domain],
|
||||
});
|
||||
|
||||
export const apiGetExcludeDomains = (antennaId: string) =>
|
||||
apiRequestGet<string[]>(`v1/antennas/${antennaId}/exclude_domains`, {
|
||||
limit: 0,
|
||||
export const apiAddExcludeDomain = (antennaId: string, domain: string) =>
|
||||
apiRequestPost(`v1/antennas/${antennaId}/exclude_domains`, {
|
||||
domains: [domain],
|
||||
});
|
||||
|
||||
export const apiRemoveExcludeDomain = (antennaId: string, domain: string) =>
|
||||
apiRequestDelete(`v1/antennas/${antennaId}/exclude_domains`, {
|
||||
domains: [domain],
|
||||
});
|
||||
|
||||
export const apiGetTags = (antennaId: string) =>
|
||||
apiRequestGet<string[]>(`v1/antennas/${antennaId}/tags`, {
|
||||
limit: 0,
|
||||
apiRequestGet<{ tags: string[]; exclude_tags: string[] }>(
|
||||
`v1/antennas/${antennaId}/tags`,
|
||||
{
|
||||
limit: 0,
|
||||
},
|
||||
);
|
||||
|
||||
export const apiAddTag = (antennaId: string, tag: string) =>
|
||||
apiRequestPost(`v1/antennas/${antennaId}/tags`, {
|
||||
tags: [tag],
|
||||
});
|
||||
|
||||
export const apiGetExcludeTags = (antennaId: string) =>
|
||||
apiRequestGet<string[]>(`v1/antennas/${antennaId}/exclude_tags`, {
|
||||
limit: 0,
|
||||
export const apiRemoveTag = (antennaId: string, tag: string) =>
|
||||
apiRequestDelete(`v1/antennas/${antennaId}/tags`, {
|
||||
tags: [tag],
|
||||
});
|
||||
|
||||
export const apiAddExcludeTag = (antennaId: string, tag: string) =>
|
||||
apiRequestPost(`v1/antennas/${antennaId}/exclude_tags`, {
|
||||
tags: [tag],
|
||||
});
|
||||
|
||||
export const apiRemoveExcludeTag = (antennaId: string, tag: string) =>
|
||||
apiRequestDelete(`v1/antennas/${antennaId}/exclude_tags`, {
|
||||
tags: [tag],
|
||||
});
|
||||
|
||||
export const apiGetKeywords = (antennaId: string) =>
|
||||
apiRequestGet<string[]>(`v1/antennas/${antennaId}/keywords`, {
|
||||
limit: 0,
|
||||
apiRequestGet<{ keywords: string[]; exclude_keywords: string[] }>(
|
||||
`v1/antennas/${antennaId}/keywords`,
|
||||
{
|
||||
limit: 0,
|
||||
},
|
||||
);
|
||||
|
||||
export const apiAddKeyword = (antennaId: string, keyword: string) =>
|
||||
apiRequestPost(`v1/antennas/${antennaId}/keywords`, {
|
||||
keywords: [keyword],
|
||||
});
|
||||
|
||||
export const apiGetExcludeKeywords = (antennaId: string) =>
|
||||
apiRequestGet<string[]>(`v1/antennas/${antennaId}/exclude_keywords`, {
|
||||
limit: 0,
|
||||
export const apiRemoveKeyword = (antennaId: string, keyword: string) =>
|
||||
apiRequestDelete(`v1/antennas/${antennaId}/keywords`, {
|
||||
keywords: [keyword],
|
||||
});
|
||||
|
||||
export const apiAddExcludeKeyword = (antennaId: string, keyword: string) =>
|
||||
apiRequestPost(`v1/antennas/${antennaId}/exclude_keywords`, {
|
||||
keywords: [keyword],
|
||||
});
|
||||
|
||||
export const apiRemoveExcludeKeyword = (antennaId: string, keyword: string) =>
|
||||
apiRequestDelete(`v1/antennas/${antennaId}/exclude_keywords`, {
|
||||
keywords: [keyword],
|
||||
});
|
||||
|
||||
export const apiGetAccountAntennas = (accountId: string) =>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// See app/serializers/rest/list_serializer.rb
|
||||
|
||||
import type { ApiAntennaJSON } from './antennas';
|
||||
|
||||
export type RepliesPolicyType = 'list' | 'followed' | 'none';
|
||||
|
||||
export interface ApiListJSON {
|
||||
|
@ -8,4 +10,5 @@ export interface ApiListJSON {
|
|||
exclusive: boolean;
|
||||
replies_policy: RepliesPolicyType;
|
||||
notify: boolean;
|
||||
antennas?: ApiAntennaJSON[];
|
||||
}
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import AddIcon from '@/material-icons/400-24px/add.svg?react';
|
||||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||
|
||||
import { removeFromAntennaEditor, addToAntennaEditor, removeExcludeFromAntennaEditor, addExcludeToAntennaEditor } from '../../../actions/antennas';
|
||||
import { Avatar } from '../../../components/avatar';
|
||||
import { DisplayName } from '../../../components/display_name';
|
||||
import { IconButton } from '../../../components/icon_button';
|
||||
import { makeGetAccount } from '../../../selectors';
|
||||
|
||||
const messages = defineMessages({
|
||||
remove: { id: 'antennas.account.remove', defaultMessage: 'Remove from antenna' },
|
||||
add: { id: 'antennas.account.add', defaultMessage: 'Add to antenna' },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
const mapStateToProps = (state, { accountId, added }) => ({
|
||||
account: getAccount(state, accountId),
|
||||
added: typeof added === 'undefined' ? state.getIn(['antennaEditor', 'accounts', 'items']).includes(accountId) : added,
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { accountId }) => ({
|
||||
onRemove: () => dispatch(removeFromAntennaEditor(accountId)),
|
||||
onAdd: () => dispatch(addToAntennaEditor(accountId)),
|
||||
onExcludeRemove: () => dispatch(removeExcludeFromAntennaEditor(accountId)),
|
||||
onExcludeAdd: () => dispatch(addExcludeToAntennaEditor(accountId)),
|
||||
});
|
||||
|
||||
class Account extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
isExclude: PropTypes.bool.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onRemove: PropTypes.func.isRequired,
|
||||
onAdd: PropTypes.func.isRequired,
|
||||
onExcludeRemove: PropTypes.func.isRequired,
|
||||
onExcludeAdd: PropTypes.func.isRequired,
|
||||
added: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
added: false,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { account, intl, isExclude, onRemove, onAdd, onExcludeRemove, onExcludeAdd, added } = this.props;
|
||||
|
||||
let button;
|
||||
|
||||
if (added) {
|
||||
button = <IconButton icon='times' iconComponent={CloseIcon} title={intl.formatMessage(messages.remove)} onClick={isExclude ? onExcludeRemove : onRemove} />;
|
||||
} else {
|
||||
button = <IconButton icon='plus' iconComponent={AddIcon} title={intl.formatMessage(messages.add)} onClick={isExclude ? onExcludeAdd : onAdd} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='account'>
|
||||
<div className='account__wrapper'>
|
||||
<div className='account__display-name'>
|
||||
<div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div>
|
||||
<DisplayName account={account} />
|
||||
</div>
|
||||
|
||||
<div className='account__relationship'>
|
||||
{button}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(makeMapStateToProps, mapDispatchToProps)(injectIntl(Account));
|
|
@ -1,76 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import CheckIcon from '@/material-icons/400-24px/check.svg?react';
|
||||
|
||||
import { changeAntennaEditorTitle, submitAntennaEditor } from '../../../actions/antennas';
|
||||
import { IconButton } from '../../../components/icon_button';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'antennas.edit.submit', defaultMessage: 'Change title' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
value: state.getIn(['antennaEditor', 'title']),
|
||||
disabled: !state.getIn(['antennaEditor', 'isChanged']) || !state.getIn(['antennaEditor', 'title']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onChange: value => dispatch(changeAntennaEditorTitle(value)),
|
||||
onSubmit: () => dispatch(submitAntennaEditor(false)),
|
||||
});
|
||||
|
||||
class AntennaForm extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
handleChange = e => {
|
||||
this.props.onChange(e.target.value);
|
||||
};
|
||||
|
||||
handleSubmit = e => {
|
||||
e.preventDefault();
|
||||
this.props.onSubmit();
|
||||
};
|
||||
|
||||
handleClick = () => {
|
||||
this.props.onSubmit();
|
||||
};
|
||||
|
||||
render () {
|
||||
const { value, disabled, intl } = this.props;
|
||||
|
||||
const title = intl.formatMessage(messages.title);
|
||||
|
||||
return (
|
||||
<form className='column-inline-form' onSubmit={this.handleSubmit}>
|
||||
<input
|
||||
className='setting-text'
|
||||
value={value}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
disabled={disabled}
|
||||
icon='check'
|
||||
iconComponent={CheckIcon}
|
||||
title={title}
|
||||
onClick={this.handleClick}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(AntennaForm));
|
|
@ -1,83 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import CancelIcon from '@/material-icons/400-24px/cancel-fill.svg?react';
|
||||
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
|
||||
import { fetchAntennaSuggestions, clearAntennaSuggestions, changeAntennaSuggestions } from '../../../actions/antennas';
|
||||
|
||||
const messages = defineMessages({
|
||||
search: { id: 'antennas.search', defaultMessage: 'Search among people you follow' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
value: state.getIn(['antennaEditor', 'suggestions', 'value']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onSubmit: value => dispatch(fetchAntennaSuggestions(value)),
|
||||
onClear: () => dispatch(clearAntennaSuggestions()),
|
||||
onChange: value => dispatch(changeAntennaSuggestions(value)),
|
||||
});
|
||||
|
||||
class Search extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
onClear: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
handleChange = e => {
|
||||
this.props.onChange(e.target.value);
|
||||
};
|
||||
|
||||
handleKeyUp = e => {
|
||||
if (e.keyCode === 13) {
|
||||
this.props.onSubmit(this.props.value);
|
||||
}
|
||||
};
|
||||
|
||||
handleClear = () => {
|
||||
this.props.onClear();
|
||||
};
|
||||
|
||||
render () {
|
||||
const { value, intl } = this.props;
|
||||
const hasValue = value.length > 0;
|
||||
|
||||
return (
|
||||
<div className='list-editor__search search'>
|
||||
<label>
|
||||
<span style={{ display: 'none' }}>{intl.formatMessage(messages.search)}</span>
|
||||
|
||||
<input
|
||||
className='search__input'
|
||||
type='text'
|
||||
value={value}
|
||||
onChange={this.handleChange}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
placeholder={intl.formatMessage(messages.search)}
|
||||
/>
|
||||
</label>
|
||||
|
||||
<div role='button' tabIndex={0} className='search__icon' onClick={this.handleClear}>
|
||||
<Icon id='search' icon={SearchIcon} className={classNames({ active: !hasValue })} />
|
||||
<Icon id='times-circle' icon={CancelIcon} aria-label={intl.formatMessage(messages.search)} className={classNames({ active: hasValue })} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(Search));
|
|
@ -1,84 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
|
||||
import { injectIntl } from 'react-intl';
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import spring from 'react-motion/lib/spring';
|
||||
|
||||
import { setupAntennaEditor, setupExcludeAntennaEditor, clearAntennaSuggestions, resetAntennaEditor } from '../../actions/antennas';
|
||||
import Motion from '../ui/util/optional_motion';
|
||||
|
||||
import Account from './components/account';
|
||||
import EditAntennaForm from './components/edit_antenna_form';
|
||||
import Search from './components/search';
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
accountIds: state.getIn(['antennaEditor', 'accounts', 'items']),
|
||||
searchAccountIds: state.getIn(['antennaEditor', 'suggestions', 'items']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch, { isExclude }) => ({
|
||||
onInitialize: antennaId => dispatch(isExclude ? setupExcludeAntennaEditor(antennaId) : setupAntennaEditor(antennaId)),
|
||||
onClear: () => dispatch(clearAntennaSuggestions()),
|
||||
onReset: () => dispatch(resetAntennaEditor()),
|
||||
});
|
||||
|
||||
class AntennaEditor extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
antennaId: PropTypes.string.isRequired,
|
||||
isExclude: PropTypes.bool.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onInitialize: PropTypes.func.isRequired,
|
||||
onClear: PropTypes.func.isRequired,
|
||||
onReset: PropTypes.func.isRequired,
|
||||
accountIds: ImmutablePropTypes.list.isRequired,
|
||||
searchAccountIds: ImmutablePropTypes.list.isRequired,
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
const { onInitialize, antennaId } = this.props;
|
||||
onInitialize(antennaId);
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
const { onReset } = this.props;
|
||||
onReset();
|
||||
}
|
||||
|
||||
render () {
|
||||
const { accountIds, searchAccountIds, onClear, isExclude } = this.props;
|
||||
const showSearch = searchAccountIds.size > 0;
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal list-editor'>
|
||||
<EditAntennaForm />
|
||||
|
||||
<Search />
|
||||
|
||||
<div className='drawer__pager'>
|
||||
<div className='drawer__inner list-editor__accounts'>
|
||||
{accountIds.map(accountId => <Account key={accountId} accountId={accountId} isExclude={isExclude} added />)}
|
||||
</div>
|
||||
|
||||
{showSearch && <div role='button' tabIndex={-1} className='drawer__backdrop' onClick={onClear} />}
|
||||
|
||||
<Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
|
||||
{({ x }) => (
|
||||
<div className='drawer__inner backdrop' style={{ transform: x === 0 ? null : `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}>
|
||||
{searchAccountIds.map(accountId => <Account key={accountId} accountId={accountId} isExclude={isExclude} />)}
|
||||
</div>
|
||||
)}
|
||||
</Motion>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(AntennaEditor));
|
|
@ -1,46 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import { injectIntl } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
class RadioPanel extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
values: ImmutablePropTypes.list.isRequired,
|
||||
value: PropTypes.object.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
handleChange = e => {
|
||||
const value = e.currentTarget.getAttribute('data-value');
|
||||
|
||||
if (value !== this.props.value.get('value')) {
|
||||
this.props.onChange(value);
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { values, value } = this.props;
|
||||
|
||||
return (
|
||||
<div className='setting-radio-panel'>
|
||||
{values.map((val) => (
|
||||
<button className={classNames('setting-radio-panel__item', {'setting-radio-panel__item__active': value.get('value') === val.get('value')})}
|
||||
key={val.get('value')} onClick={this.handleChange} data-value={val.get('value')}>
|
||||
{val.get('label')}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect()(injectIntl(RadioPanel));
|
|
@ -1,104 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import { injectIntl } from 'react-intl';
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { IconButton } from 'mastodon/components/icon_button';
|
||||
|
||||
class TextListItem extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
icon: PropTypes.string.isRequired,
|
||||
iconComponent: PropTypes.func.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
onRemove: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
handleRemove = () => {
|
||||
this.props.onRemove(this.props.value);
|
||||
};
|
||||
|
||||
render () {
|
||||
const { icon, iconComponent, value } = this.props;
|
||||
|
||||
return (
|
||||
<div className='setting-text-list-item'>
|
||||
<Icon id={icon} icon={iconComponent} />
|
||||
<span className='label'>{value}</span>
|
||||
<IconButton icon='trash' iconComponent={DeleteIcon} onClick={this.handleRemove} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TextList extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
values: ImmutablePropTypes.list.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
icon: PropTypes.string.isRequired,
|
||||
iconComponent: PropTypes.func.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onAdd: PropTypes.func.isRequired,
|
||||
onRemove: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
handleChange = e => {
|
||||
this.props.onChange(e.target.value);
|
||||
};
|
||||
|
||||
handleAdd = () => {
|
||||
this.props.onAdd();
|
||||
};
|
||||
|
||||
handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
this.handleAdd();
|
||||
};
|
||||
|
||||
render () {
|
||||
const { icon, iconComponent, value, values, disabled, label, title } = this.props;
|
||||
|
||||
return (
|
||||
<div className='setting-text-list'>
|
||||
{values.map((val) => (
|
||||
<TextListItem key={val} value={val} icon={icon} iconComponent={iconComponent} onRemove={this.props.onRemove} />
|
||||
))}
|
||||
|
||||
<form className='add-text-form' onSubmit={this.handleSubmit}>
|
||||
<label>
|
||||
<span style={{ display: 'none' }}>{label}</span>
|
||||
|
||||
<input
|
||||
className='setting-text'
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
onChange={this.handleChange}
|
||||
placeholder={label}
|
||||
/>
|
||||
</label>
|
||||
|
||||
<Button
|
||||
disabled={disabled || !value}
|
||||
text={title}
|
||||
onClick={this.handleAdd}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect()(injectIntl(TextList));
|
|
@ -1,587 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
import { List as ImmutableList, Map as ImmutableMap } from 'immutable';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Select, { NonceProvider } from 'react-select';
|
||||
import Toggle from 'react-toggle';
|
||||
|
||||
import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
|
||||
import DomainIcon from '@/material-icons/400-24px/dns.svg?react';
|
||||
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
|
||||
import HashtagIcon from '@/material-icons/400-24px/tag.svg?react';
|
||||
import KeywordIcon from '@/material-icons/400-24px/title.svg?react';
|
||||
import AntennaIcon from '@/material-icons/400-24px/wifi.svg?react';
|
||||
import {
|
||||
fetchAntenna,
|
||||
deleteAntenna,
|
||||
updateAntenna,
|
||||
addDomainToAntenna,
|
||||
removeDomainFromAntenna,
|
||||
addExcludeDomainToAntenna,
|
||||
removeExcludeDomainFromAntenna,
|
||||
fetchAntennaDomains,
|
||||
fetchAntennaKeywords,
|
||||
removeKeywordFromAntenna,
|
||||
addKeywordToAntenna,
|
||||
removeExcludeKeywordFromAntenna,
|
||||
addExcludeKeywordToAntenna,
|
||||
fetchAntennaTags,
|
||||
removeTagFromAntenna,
|
||||
addTagToAntenna,
|
||||
removeExcludeTagFromAntenna,
|
||||
addExcludeTagToAntenna,
|
||||
} from 'mastodon/actions/antennas';
|
||||
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
|
||||
import { fetchLists } from 'mastodon/actions/lists';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import Column from 'mastodon/components/column';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
||||
import { enableLocalTimeline } from 'mastodon/initial_state';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
import RadioPanel from './components/radio_panel';
|
||||
import TextList from './components/text_list';
|
||||
|
||||
const messages = defineMessages({
|
||||
deleteMessage: { id: 'confirmations.delete_antenna.message', defaultMessage: 'Are you sure you want to permanently delete this antenna?' },
|
||||
deleteConfirm: { id: 'confirmations.delete_antenna.confirm', defaultMessage: 'Delete' },
|
||||
editAccounts: { id: 'antennas.edit_accounts', defaultMessage: 'Edit accounts' },
|
||||
noOptions: { id: 'antennas.select.no_options_message', defaultMessage: 'Empty lists' },
|
||||
placeholder: { id: 'antennas.select.placeholder', defaultMessage: 'Select list' },
|
||||
addDomainLabel: { id: 'antennas.add_domain_placeholder', defaultMessage: 'New domain' },
|
||||
addKeywordLabel: { id: 'antennas.add_keyword_placeholder', defaultMessage: 'New keyword' },
|
||||
addTagLabel: { id: 'antennas.add_tag_placeholder', defaultMessage: 'New tag' },
|
||||
addDomainTitle: { id: 'antennas.add_domain', defaultMessage: 'Add domain' },
|
||||
addKeywordTitle: { id: 'antennas.add_keyword', defaultMessage: 'Add keyword' },
|
||||
addTagTitle: { id: 'antennas.add_tag', defaultMessage: 'Add tag' },
|
||||
accounts: { id: 'antennas.accounts', defaultMessage: '{count} accounts' },
|
||||
domains: { id: 'antennas.domains', defaultMessage: '{count} domains' },
|
||||
tags: { id: 'antennas.tags', defaultMessage: '{count} tags' },
|
||||
keywords: { id: 'antennas.keywords', defaultMessage: '{count} keywords' },
|
||||
setHome: { id: 'antennas.select.set_home', defaultMessage: 'Set home' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
antenna: state.getIn(['antennas', props.params.id]),
|
||||
lists: state.get('lists'),
|
||||
domains: state.getIn(['antennas', props.params.id, 'domains']) || ImmutableMap(),
|
||||
keywords: state.getIn(['antennas', props.params.id, 'keywords']) || ImmutableMap(),
|
||||
tags: state.getIn(['antennas', props.params.id, 'tags']) || ImmutableMap(),
|
||||
});
|
||||
|
||||
class AntennaSetting extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
multiColumn: PropTypes.bool,
|
||||
antenna: PropTypes.oneOfType([ImmutablePropTypes.map, PropTypes.bool]),
|
||||
lists: ImmutablePropTypes.map,
|
||||
domains: ImmutablePropTypes.map,
|
||||
keywords: ImmutablePropTypes.map,
|
||||
tags: ImmutablePropTypes.map,
|
||||
intl: PropTypes.object.isRequired,
|
||||
...WithRouterPropTypes,
|
||||
};
|
||||
|
||||
state = {
|
||||
domainName: '',
|
||||
excludeDomainName: '',
|
||||
keywordName: '',
|
||||
excludeKeywordName: '',
|
||||
tagName: '',
|
||||
excludeTagName: '',
|
||||
rangeRadioValue: null,
|
||||
contentRadioValue: null,
|
||||
};
|
||||
|
||||
handlePin = () => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('ANTENNA', { id: this.props.params.id }));
|
||||
this.props.history.push('/');
|
||||
}
|
||||
};
|
||||
|
||||
handleMove = (dir) => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
dispatch(moveColumn(columnId, dir));
|
||||
};
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch } = this.props;
|
||||
const { id } = this.props.params;
|
||||
|
||||
dispatch(fetchAntenna(id));
|
||||
dispatch(fetchAntennaDomains(id));
|
||||
dispatch(fetchAntennaKeywords(id));
|
||||
dispatch(fetchAntennaTags(id));
|
||||
dispatch(fetchLists());
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps (nextProps) {
|
||||
const { dispatch } = this.props;
|
||||
const { id } = nextProps.params;
|
||||
|
||||
if (id !== this.props.params.id) {
|
||||
dispatch(fetchAntenna(id));
|
||||
dispatch(fetchAntennaKeywords(id));
|
||||
dispatch(fetchAntennaDomains(id));
|
||||
dispatch(fetchAntennaKeywords(id));
|
||||
dispatch(fetchAntennaTags(id));
|
||||
dispatch(fetchLists());
|
||||
}
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
};
|
||||
|
||||
handleEditClick = () => {
|
||||
this.props.dispatch(openModal({
|
||||
modalType: 'ANTENNA_EDITOR',
|
||||
modalProps: { antennaId: this.props.params.id, isExclude: false },
|
||||
}));
|
||||
};
|
||||
|
||||
handleExcludeEditClick = () => {
|
||||
this.props.dispatch(openModal({
|
||||
modalType: 'ANTENNA_EDITOR',
|
||||
modalProps: { antennaId: this.props.params.id, isExclude: true },
|
||||
}));
|
||||
};
|
||||
|
||||
handleEditAntennaClick = () => {
|
||||
window.open(`/antennas/${this.props.params.id}/edit`, '_blank');
|
||||
};
|
||||
|
||||
handleDeleteClick = () => {
|
||||
const { dispatch, columnId, intl } = this.props;
|
||||
const { id } = this.props.params;
|
||||
|
||||
dispatch(openModal({
|
||||
modalType: 'CONFIRM',
|
||||
modalProps: {
|
||||
message: intl.formatMessage(messages.deleteMessage),
|
||||
confirm: intl.formatMessage(messages.deleteConfirm),
|
||||
onConfirm: () => {
|
||||
dispatch(deleteAntenna(id));
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
this.props.history.push('/antennasw');
|
||||
}
|
||||
},
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
handleTimelineClick = () => {
|
||||
this.props.history.push(`/antennast/${this.props.params.id}`);
|
||||
};
|
||||
|
||||
onStlToggle = ({ target }) => {
|
||||
const { dispatch } = this.props;
|
||||
const { id } = this.props.params;
|
||||
dispatch(updateAntenna(id, undefined, false, undefined, target.checked, undefined, undefined, undefined, undefined));
|
||||
};
|
||||
|
||||
onLtlToggle = ({ target }) => {
|
||||
const { dispatch } = this.props;
|
||||
const { id } = this.props.params;
|
||||
dispatch(updateAntenna(id, undefined, false, undefined, undefined, target.checked, undefined, undefined, undefined));
|
||||
};
|
||||
|
||||
onMediaOnlyToggle = ({ target }) => {
|
||||
const { dispatch } = this.props;
|
||||
const { id } = this.props.params;
|
||||
dispatch(updateAntenna(id, undefined, false, undefined, undefined, undefined, target.checked, undefined, undefined));
|
||||
};
|
||||
|
||||
onIgnoreReblogToggle = ({ target }) => {
|
||||
const { dispatch } = this.props;
|
||||
const { id } = this.props.params;
|
||||
dispatch(updateAntenna(id, undefined, false, undefined, undefined, undefined, undefined, target.checked, undefined));
|
||||
};
|
||||
|
||||
onNoInsertFeedsToggle = ({ target }) => {
|
||||
const { dispatch } = this.props;
|
||||
const { id } = this.props.params;
|
||||
dispatch(updateAntenna(id, undefined, false, undefined, undefined, undefined, undefined, undefined, target.checked));
|
||||
};
|
||||
|
||||
onSelect = value => {
|
||||
const { dispatch } = this.props;
|
||||
const { id } = this.props.params;
|
||||
dispatch(updateAntenna(id, undefined, false, value.value, undefined, undefined, undefined, undefined, undefined));
|
||||
};
|
||||
|
||||
onHomeSelect = () => this.onSelect({ value: '0' });
|
||||
|
||||
noOptionsMessage = () => this.props.intl.formatMessage(messages.noOptions);
|
||||
|
||||
onRangeRadioChanged = (value) => this.setState({ rangeRadioValue: value });
|
||||
|
||||
onContentRadioChanged = (value) => this.setState({ contentRadioValue: value });
|
||||
|
||||
onDomainNameChanged = (value) => this.setState({ domainName: value });
|
||||
|
||||
onDomainAdd = () => {
|
||||
this.props.dispatch(addDomainToAntenna(this.props.params.id, this.state.domainName));
|
||||
this.setState({ domainName: '' });
|
||||
};
|
||||
|
||||
onDomainRemove = (value) => this.props.dispatch(removeDomainFromAntenna(this.props.params.id, value));
|
||||
|
||||
onKeywordNameChanged = (value) => this.setState({ keywordName: value });
|
||||
|
||||
onKeywordAdd = () => {
|
||||
this.props.dispatch(addKeywordToAntenna(this.props.params.id, this.state.keywordName));
|
||||
this.setState({ keywordName: '' });
|
||||
};
|
||||
|
||||
onKeywordRemove = (value) => this.props.dispatch(removeKeywordFromAntenna(this.props.params.id, value));
|
||||
|
||||
onTagNameChanged = (value) => this.setState({ tagName: value });
|
||||
|
||||
onTagAdd = () => {
|
||||
this.props.dispatch(addTagToAntenna(this.props.params.id, this.state.tagName));
|
||||
this.setState({ tagName: '' });
|
||||
};
|
||||
|
||||
onTagRemove = (value) => this.props.dispatch(removeTagFromAntenna(this.props.params.id, value));
|
||||
|
||||
onExcludeDomainNameChanged = (value) => this.setState({ excludeDomainName: value });
|
||||
|
||||
onExcludeDomainAdd = () => {
|
||||
this.props.dispatch(addExcludeDomainToAntenna(this.props.params.id, this.state.excludeDomainName));
|
||||
this.setState({ excludeDomainName: '' });
|
||||
};
|
||||
|
||||
onExcludeDomainRemove = (value) => this.props.dispatch(removeExcludeDomainFromAntenna(this.props.params.id, value));
|
||||
|
||||
onExcludeKeywordNameChanged = (value) => this.setState({ excludeKeywordName: value });
|
||||
|
||||
onExcludeKeywordAdd = () => {
|
||||
this.props.dispatch(addExcludeKeywordToAntenna(this.props.params.id, this.state.excludeKeywordName));
|
||||
this.setState({ excludeKeywordName: '' });
|
||||
};
|
||||
|
||||
onExcludeKeywordRemove = (value) => this.props.dispatch(removeExcludeKeywordFromAntenna(this.props.params.id, value));
|
||||
|
||||
onExcludeTagNameChanged = (value) => this.setState({ excludeTagName: value });
|
||||
|
||||
onExcludeTagAdd = () => {
|
||||
this.props.dispatch(addExcludeTagToAntenna(this.props.params.id, this.state.excludeTagName));
|
||||
this.setState({ excludeTagName: '' });
|
||||
};
|
||||
|
||||
onExcludeTagRemove = (value) => this.props.dispatch(removeExcludeTagFromAntenna(this.props.params.id, value));
|
||||
|
||||
render () {
|
||||
const { columnId, multiColumn, antenna, lists, domains, keywords, tags, intl } = this.props;
|
||||
const { id } = this.props.params;
|
||||
const pinned = !!columnId;
|
||||
const title = antenna ? antenna.get('title') : id;
|
||||
const isStl = antenna ? antenna.get('stl') : undefined;
|
||||
const isLtl = antenna ? antenna.get('ltl') : undefined;
|
||||
const isMediaOnly = antenna ? antenna.get('with_media_only') : undefined;
|
||||
const isIgnoreReblog = antenna ? antenna.get('ignore_reblog') : undefined;
|
||||
const isInsertFeeds = antenna ? antenna.get('insert_feeds') : undefined;
|
||||
|
||||
if (typeof antenna === 'undefined') {
|
||||
return (
|
||||
<Column>
|
||||
<div className='scrollable'>
|
||||
<LoadingIndicator />
|
||||
</div>
|
||||
</Column>
|
||||
);
|
||||
} else if (antenna === false) {
|
||||
return (
|
||||
<BundleColumnError multiColumn={multiColumn} errorType='routing' />
|
||||
);
|
||||
}
|
||||
|
||||
let columnSettings;
|
||||
if (!isStl && !isLtl) {
|
||||
columnSettings = (
|
||||
<>
|
||||
<section className='similar-row'>
|
||||
<div className='setting-toggle'>
|
||||
<Toggle id={`antenna-${id}-mediaonly`} checked={isMediaOnly} onChange={this.onMediaOnlyToggle} />
|
||||
<label htmlFor={`antenna-${id}-mediaonly`} className='setting-toggle__label'>
|
||||
<FormattedMessage id='antennas.media_only' defaultMessage='Media only' />
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className='similar-row'>
|
||||
<div className='setting-toggle'>
|
||||
<Toggle id={`antenna-${id}-ignorereblog`} checked={isIgnoreReblog} onChange={this.onIgnoreReblogToggle} />
|
||||
<label htmlFor={`antenna-${id}-ignorereblog`} className='setting-toggle__label'>
|
||||
<FormattedMessage id='antennas.ignore_reblog' defaultMessage='Exclude boosts' />
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
let stlAlert;
|
||||
if (isStl) {
|
||||
stlAlert = (
|
||||
<div className='antenna-setting'>
|
||||
<p><FormattedMessage id='antennas.in_stl_mode' defaultMessage='This antenna is in STL mode.' /></p>
|
||||
</div>
|
||||
);
|
||||
} else if (isLtl) {
|
||||
stlAlert = (
|
||||
<div className='antenna-setting'>
|
||||
<p><FormattedMessage id='antennas.in_ltl_mode' defaultMessage='This antenna is in LTL mode.' /></p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const rangeRadioValues = ImmutableList([
|
||||
ImmutableMap({ value: 'accounts', label: intl.formatMessage(messages.accounts, { count: antenna.get('accounts_count') }) }),
|
||||
ImmutableMap({ value: 'domains', label: intl.formatMessage(messages.domains, { count: antenna.get('domains_count') }) }),
|
||||
]);
|
||||
const rangeRadioValue = ImmutableMap({ value: this.state.rangeRadioValue || (antenna.get('domains_count') > 0 ? 'domains' : 'accounts') });
|
||||
const rangeRadioAlert = antenna.get(rangeRadioValue.get('value') === 'accounts' ? 'domains_count' : 'accounts_count') > 0;
|
||||
|
||||
const contentRadioValues = ImmutableList([
|
||||
ImmutableMap({ value: 'keywords', label: intl.formatMessage(messages.keywords, { count: antenna.get('keywords_count') }) }),
|
||||
ImmutableMap({ value: 'tags', label: intl.formatMessage(messages.tags, { count: antenna.get('tags_count') }) }),
|
||||
]);
|
||||
const contentRadioValue = ImmutableMap({ value: this.state.contentRadioValue || (antenna.get('tags_count') > 0 ? 'tags' : 'keywords') });
|
||||
const contentRadioAlert = antenna.get(contentRadioValue.get('value') === 'tags' ? 'keywords_count' : 'tags_count') > 0;
|
||||
|
||||
const listOptions = lists.toArray().filter((list) => list.length >= 2 && list[1]).map((list) => {
|
||||
return { value: list[1].get('id'), label: list[1].get('title') };
|
||||
});
|
||||
|
||||
const isShowStlToggle = !isLtl && (enableLocalTimeline || isStl);
|
||||
const isShowLtlToggle = !isStl && (enableLocalTimeline || isLtl);
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={title}>
|
||||
<ColumnHeader
|
||||
icon='wifi'
|
||||
iconComponent={AntennaIcon}
|
||||
title={title}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
onClick={this.handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
>
|
||||
<div className='column-settings'>
|
||||
<section className='column-header__links'>
|
||||
<button type='button' className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.handleEditAntennaClick}>
|
||||
<Icon id='pencil' icon={EditIcon} /> <FormattedMessage id='antennas.edit_static' defaultMessage='Edit antenna' />
|
||||
</button>
|
||||
|
||||
<button type='button' className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.handleDeleteClick}>
|
||||
<Icon id='trash' icon={DeleteIcon} /> <FormattedMessage id='antennas.delete' defaultMessage='Delete antenna' />
|
||||
</button>
|
||||
|
||||
<button type='button' className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.handleTimelineClick}>
|
||||
<Icon id='wifi' icon={AntennaIcon} /> <FormattedMessage id='antennas.go_timeline' defaultMessage='Go to antenna timeline' />
|
||||
</button>
|
||||
</section>
|
||||
|
||||
{isShowStlToggle && (
|
||||
<section>
|
||||
<div className='setting-toggle'>
|
||||
<Toggle id={`antenna-${id}-stl`} checked={isStl} onChange={this.onStlToggle} />
|
||||
<label htmlFor={`antenna-${id}-stl`} className='setting-toggle__label'>
|
||||
<FormattedMessage id='antennas.stl' defaultMessage='STL mode' />
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{isShowLtlToggle && (
|
||||
<section className={isShowStlToggle && 'similar-row'}>
|
||||
<div className='setting-toggle'>
|
||||
<Toggle id={`antenna-${id}-ltl`} checked={isLtl} onChange={this.onLtlToggle} />
|
||||
<label htmlFor={`antenna-${id}-ltl`} className='setting-toggle__label'>
|
||||
<FormattedMessage id='antennas.ltl' defaultMessage='LTL mode' />
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
<section className={(isShowStlToggle || isShowLtlToggle) && 'similar-row'}>
|
||||
<div className='setting-toggle'>
|
||||
<Toggle id={`antenna-${id}-noinsertfeeds`} checked={isInsertFeeds} onChange={this.onNoInsertFeedsToggle} />
|
||||
<label htmlFor={`antenna-${id}-noinsertfeeds`} className='setting-toggle__label'>
|
||||
<FormattedMessage id='antennas.insert_feeds' defaultMessage='Insert to feeds' />
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{columnSettings}
|
||||
</div>
|
||||
</ColumnHeader>
|
||||
|
||||
{stlAlert}
|
||||
<div className='antenna-setting'>
|
||||
{isInsertFeeds && (
|
||||
<>
|
||||
{antenna.get('list') ? (
|
||||
<p><FormattedMessage id='antennas.related_list' defaultMessage='This antenna is related to {listTitle}.' values={{ listTitle: antenna.getIn(['list', 'title']) }} /></p>
|
||||
) : (
|
||||
<p><FormattedMessage id='antennas.not_related_list' defaultMessage='This antenna is not related list. Posts will appear in home timeline. Open edit page to set list.' /></p>
|
||||
)}
|
||||
|
||||
<NonceProvider nonce={document.querySelector('meta[name=style-nonce]').content} cacheKey='lists'>
|
||||
<Select
|
||||
value={{ value: antenna.getIn(['list', 'id']), label: antenna.getIn(['list', 'title']) }}
|
||||
options={listOptions}
|
||||
noOptionsMessage={this.noOptionsMessage}
|
||||
onChange={this.onSelect}
|
||||
className='column-content-select__container'
|
||||
classNamePrefix='column-content-select'
|
||||
name='lists'
|
||||
placeholder={this.props.intl.formatMessage(messages.placeholder)}
|
||||
defaultOptions
|
||||
/>
|
||||
</NonceProvider>
|
||||
|
||||
<Button secondary text={this.props.intl.formatMessage(messages.setHome)} onClick={this.onHomeSelect} />
|
||||
</>
|
||||
)}
|
||||
|
||||
{!isStl && !isLtl && (
|
||||
<>
|
||||
<h2><FormattedMessage id='antennas.filter' defaultMessage='Filter' /></h2>
|
||||
<RadioPanel values={rangeRadioValues} value={rangeRadioValue} onChange={this.onRangeRadioChanged} />
|
||||
|
||||
{rangeRadioValue.get('value') === 'accounts' && <Button text={intl.formatMessage(messages.editAccounts)} onClick={this.handleEditClick} />}
|
||||
|
||||
{rangeRadioValue.get('value') === 'domains' && (
|
||||
<TextList
|
||||
onChange={this.onDomainNameChanged}
|
||||
onAdd={this.onDomainAdd}
|
||||
onRemove={this.onDomainRemove}
|
||||
value={this.state.domainName}
|
||||
values={domains.get('domains') || ImmutableList()}
|
||||
icon='sitemap'
|
||||
iconComponent={DomainIcon}
|
||||
label={intl.formatMessage(messages.addDomainLabel)}
|
||||
title={intl.formatMessage(messages.addDomainTitle)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{rangeRadioAlert && <div className='alert'><FormattedMessage id='antennas.warnings.range_radio' defaultMessage='Simultaneous account and domain designation is not recommended.' /></div>}
|
||||
|
||||
<RadioPanel values={contentRadioValues} value={contentRadioValue} onChange={this.onContentRadioChanged} />
|
||||
|
||||
{contentRadioValue.get('value') === 'tags' && (
|
||||
<TextList
|
||||
onChange={this.onTagNameChanged}
|
||||
onAdd={this.onTagAdd}
|
||||
onRemove={this.onTagRemove}
|
||||
value={this.state.tagName}
|
||||
values={tags.get('tags') || ImmutableList()}
|
||||
icon='hashtag'
|
||||
iconComponent={HashtagIcon}
|
||||
label={intl.formatMessage(messages.addTagLabel)}
|
||||
title={intl.formatMessage(messages.addTagTitle)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{contentRadioValue.get('value') === 'keywords' && (
|
||||
<TextList
|
||||
onChange={this.onKeywordNameChanged}
|
||||
onAdd={this.onKeywordAdd}
|
||||
onRemove={this.onKeywordRemove}
|
||||
value={this.state.keywordName}
|
||||
values={keywords.get('keywords') || ImmutableList()}
|
||||
icon='paragraph'
|
||||
iconComponent={KeywordIcon}
|
||||
label={intl.formatMessage(messages.addKeywordLabel)}
|
||||
title={intl.formatMessage(messages.addKeywordTitle)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{contentRadioAlert && <div className='alert'><FormattedMessage id='antennas.warnings.content_radio' defaultMessage='Simultaneous keyword and tag designation is not recommended.' /></div>}
|
||||
|
||||
<h2><FormattedMessage id='antennas.filter_not' defaultMessage='Filter Not' /></h2>
|
||||
<h3><FormattedMessage id='antennas.exclude_accounts' defaultMessage='Exclude accounts' /></h3>
|
||||
<Button text={intl.formatMessage(messages.editAccounts)} onClick={this.handleExcludeEditClick} />
|
||||
<h3><FormattedMessage id='antennas.exclude_domains' defaultMessage='Exclude domains' /></h3>
|
||||
<TextList
|
||||
onChange={this.onExcludeDomainNameChanged}
|
||||
onAdd={this.onExcludeDomainAdd}
|
||||
onRemove={this.onExcludeDomainRemove}
|
||||
value={this.state.excludeDomainName}
|
||||
values={domains.get('exclude_domains') || ImmutableList()}
|
||||
icon='sitemap'
|
||||
iconComponent={DomainIcon}
|
||||
label={intl.formatMessage(messages.addDomainLabel)}
|
||||
title={intl.formatMessage(messages.addDomainTitle)}
|
||||
/>
|
||||
<h3><FormattedMessage id='antennas.exclude_keywords' defaultMessage='Exclude keywords' /></h3>
|
||||
<TextList
|
||||
onChange={this.onExcludeKeywordNameChanged}
|
||||
onAdd={this.onExcludeKeywordAdd}
|
||||
onRemove={this.onExcludeKeywordRemove}
|
||||
value={this.state.excludeKeywordName}
|
||||
values={keywords.get('exclude_keywords') || ImmutableList()}
|
||||
icon='paragraph'
|
||||
iconComponent={KeywordIcon}
|
||||
label={intl.formatMessage(messages.addKeywordLabel)}
|
||||
title={intl.formatMessage(messages.addKeywordTitle)}
|
||||
/>
|
||||
<h3><FormattedMessage id='antennas.exclude_tags' defaultMessage='Exclude tags' /></h3>
|
||||
<TextList
|
||||
onChange={this.onExcludeTagNameChanged}
|
||||
onAdd={this.onExcludeTagAdd}
|
||||
onRemove={this.onExcludeTagRemove}
|
||||
value={this.state.excludeTagName}
|
||||
values={tags.get('exclude_tags') || ImmutableList()}
|
||||
icon='hashtag'
|
||||
iconComponent={HashtagIcon}
|
||||
label={intl.formatMessage(messages.addTagLabel)}
|
||||
title={intl.formatMessage(messages.addTagTitle)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Helmet>
|
||||
<title>{title}</title>
|
||||
<meta name='robots' content='noindex' />
|
||||
</Helmet>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(injectIntl(AntennaSetting)));
|
|
@ -113,7 +113,7 @@ class AntennaTimeline extends PureComponent {
|
|||
};
|
||||
|
||||
handleEditClick = () => {
|
||||
this.props.history.push(`/antennasw/${this.props.params.id}`);
|
||||
this.props.history.push(`/antennas/${this.props.params.id}/edit`);
|
||||
};
|
||||
|
||||
handleDeleteClick = () => {
|
||||
|
|
|
@ -1,373 +0,0 @@
|
|||
import { useCallback, useState, useEffect, useRef } from 'react';
|
||||
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { useParams, Link } from 'react-router-dom';
|
||||
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
|
||||
import AddIcon from '@/material-icons/400-24px/add.svg?react';
|
||||
import ArrowBackIcon from '@/material-icons/400-24px/arrow_back.svg?react';
|
||||
import AntennaIcon from '@/material-icons/400-24px/wifi.svg?react';
|
||||
import SquigglyArrow from '@/svg-icons/squiggly_arrow.svg?react';
|
||||
import { fetchFollowing } from 'mastodon/actions/accounts';
|
||||
import { importFetchedAccounts } from 'mastodon/actions/importer';
|
||||
import { fetchList } from 'mastodon/actions/lists';
|
||||
import { apiRequest } from 'mastodon/api';
|
||||
import {
|
||||
apiGetAccounts,
|
||||
apiAddAccountToList,
|
||||
apiRemoveAccountFromList,
|
||||
} from 'mastodon/api/lists';
|
||||
import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
|
||||
import { Avatar } from 'mastodon/components/avatar';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import Column from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { FollowersCounter } from 'mastodon/components/counters';
|
||||
import { DisplayName } from 'mastodon/components/display_name';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||
import { ShortNumber } from 'mastodon/components/short_number';
|
||||
import { VerifiedBadge } from 'mastodon/components/verified_badge';
|
||||
import { ButtonInTabsBar } from 'mastodon/features/ui/util/columns_context';
|
||||
import { me } from 'mastodon/initial_state';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.list_members', defaultMessage: 'Manage list members' },
|
||||
placeholder: {
|
||||
id: 'lists.search_placeholder',
|
||||
defaultMessage: 'Search people you follow',
|
||||
},
|
||||
enterSearch: { id: 'lists.add_to_list', defaultMessage: 'Add to list' },
|
||||
add: { id: 'lists.add_member', defaultMessage: 'Add' },
|
||||
remove: { id: 'lists.remove_member', defaultMessage: 'Remove' },
|
||||
back: { id: 'column_back_button.label', defaultMessage: 'Back' },
|
||||
});
|
||||
|
||||
type Mode = 'remove' | 'add';
|
||||
|
||||
const ColumnSearchHeader: React.FC<{
|
||||
onBack: () => void;
|
||||
onSubmit: (value: string) => void;
|
||||
}> = ({ onBack, onSubmit }) => {
|
||||
const intl = useIntl();
|
||||
const [value, setValue] = useState('');
|
||||
|
||||
const handleChange = useCallback(
|
||||
({ target: { value } }: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setValue(value);
|
||||
onSubmit(value);
|
||||
},
|
||||
[setValue, onSubmit],
|
||||
);
|
||||
|
||||
const handleSubmit = useCallback(() => {
|
||||
onSubmit(value);
|
||||
}, [onSubmit, value]);
|
||||
|
||||
return (
|
||||
<ButtonInTabsBar>
|
||||
<form className='column-search-header' onSubmit={handleSubmit}>
|
||||
<button
|
||||
type='button'
|
||||
className='column-header__back-button compact'
|
||||
onClick={onBack}
|
||||
aria-label={intl.formatMessage(messages.back)}
|
||||
>
|
||||
<Icon
|
||||
id='chevron-left'
|
||||
icon={ArrowBackIcon}
|
||||
className='column-back-button__icon'
|
||||
/>
|
||||
</button>
|
||||
|
||||
<input
|
||||
type='search'
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
placeholder={intl.formatMessage(messages.placeholder)}
|
||||
/* eslint-disable-next-line jsx-a11y/no-autofocus */
|
||||
autoFocus
|
||||
/>
|
||||
</form>
|
||||
</ButtonInTabsBar>
|
||||
);
|
||||
};
|
||||
|
||||
const AccountItem: React.FC<{
|
||||
accountId: string;
|
||||
listId: string;
|
||||
partOfList: boolean;
|
||||
onToggle: (accountId: string) => void;
|
||||
}> = ({ accountId, listId, partOfList, onToggle }) => {
|
||||
const intl = useIntl();
|
||||
const account = useAppSelector((state) => state.accounts.get(accountId));
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (partOfList) {
|
||||
void apiRemoveAccountFromList(listId, accountId);
|
||||
} else {
|
||||
void apiAddAccountToList(listId, accountId);
|
||||
}
|
||||
|
||||
onToggle(accountId);
|
||||
}, [accountId, listId, partOfList, onToggle]);
|
||||
|
||||
if (!account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const firstVerifiedField = account.fields.find((item) => !!item.verified_at);
|
||||
|
||||
return (
|
||||
<div className='account'>
|
||||
<div className='account__wrapper'>
|
||||
<Link
|
||||
key={account.id}
|
||||
className='account__display-name'
|
||||
title={account.acct}
|
||||
to={`/@${account.acct}`}
|
||||
data-hover-card-account={account.id}
|
||||
>
|
||||
<div className='account__avatar-wrapper'>
|
||||
<Avatar account={account} size={36} />
|
||||
</div>
|
||||
|
||||
<div className='account__contents'>
|
||||
<DisplayName account={account} />
|
||||
|
||||
<div className='account__details'>
|
||||
<ShortNumber
|
||||
value={account.followers_count}
|
||||
renderer={FollowersCounter}
|
||||
/>{' '}
|
||||
{firstVerifiedField && (
|
||||
<VerifiedBadge link={firstVerifiedField.value} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
<div className='account__relationship'>
|
||||
<Button
|
||||
text={intl.formatMessage(
|
||||
partOfList ? messages.remove : messages.add,
|
||||
)}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ListMembers: React.FC<{
|
||||
multiColumn?: boolean;
|
||||
}> = ({ multiColumn }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const intl = useIntl();
|
||||
|
||||
const followingAccountIds = useAppSelector(
|
||||
(state) => state.user_lists.getIn(['following', me, 'items']) as string[],
|
||||
);
|
||||
const [searching, setSearching] = useState(false);
|
||||
const [accountIds, setAccountIds] = useState<string[]>([]);
|
||||
const [searchAccountIds, setSearchAccountIds] = useState<string[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [mode, setMode] = useState<Mode>('remove');
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
setLoading(true);
|
||||
dispatch(fetchList(id));
|
||||
|
||||
void apiGetAccounts(id)
|
||||
.then((data) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
setAccountIds(data.map((a) => a.id));
|
||||
setLoading(false);
|
||||
return '';
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
|
||||
dispatch(fetchFollowing(me));
|
||||
}
|
||||
}, [dispatch, id]);
|
||||
|
||||
const handleSearchClick = useCallback(() => {
|
||||
setMode('add');
|
||||
}, [setMode]);
|
||||
|
||||
const handleDismissSearchClick = useCallback(() => {
|
||||
setMode('remove');
|
||||
setSearching(false);
|
||||
}, [setMode]);
|
||||
|
||||
const handleAccountToggle = useCallback(
|
||||
(accountId: string) => {
|
||||
const partOfList = accountIds.includes(accountId);
|
||||
|
||||
if (partOfList) {
|
||||
setAccountIds(accountIds.filter((id) => id !== accountId));
|
||||
} else {
|
||||
setAccountIds([accountId, ...accountIds]);
|
||||
}
|
||||
},
|
||||
[accountIds, setAccountIds],
|
||||
);
|
||||
|
||||
const searchRequestRef = useRef<AbortController | null>(null);
|
||||
|
||||
const handleSearch = useDebouncedCallback(
|
||||
(value: string) => {
|
||||
if (searchRequestRef.current) {
|
||||
searchRequestRef.current.abort();
|
||||
}
|
||||
|
||||
if (value.trim().length === 0) {
|
||||
setSearching(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
searchRequestRef.current = new AbortController();
|
||||
|
||||
void apiRequest<ApiAccountJSON[]>('GET', 'v1/accounts/search', {
|
||||
signal: searchRequestRef.current.signal,
|
||||
params: {
|
||||
q: value,
|
||||
resolve: false,
|
||||
following: true,
|
||||
},
|
||||
})
|
||||
.then((data) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
setSearchAccountIds(data.map((a) => a.id));
|
||||
setLoading(false);
|
||||
setSearching(true);
|
||||
return '';
|
||||
})
|
||||
.catch(() => {
|
||||
setSearching(true);
|
||||
setLoading(false);
|
||||
});
|
||||
},
|
||||
500,
|
||||
{ leading: true, trailing: true },
|
||||
);
|
||||
|
||||
let displayedAccountIds: string[];
|
||||
|
||||
if (mode === 'add') {
|
||||
displayedAccountIds = searching ? searchAccountIds : followingAccountIds;
|
||||
} else {
|
||||
displayedAccountIds = accountIds;
|
||||
}
|
||||
|
||||
return (
|
||||
<Column
|
||||
bindToDocument={!multiColumn}
|
||||
label={intl.formatMessage(messages.heading)}
|
||||
>
|
||||
{mode === 'remove' ? (
|
||||
<ColumnHeader
|
||||
title={intl.formatMessage(messages.heading)}
|
||||
icon='list-ul'
|
||||
iconComponent={AntennaIcon}
|
||||
multiColumn={multiColumn}
|
||||
showBackButton
|
||||
extraButton={
|
||||
<button
|
||||
onClick={handleSearchClick}
|
||||
type='button'
|
||||
className='column-header__button'
|
||||
title={intl.formatMessage(messages.enterSearch)}
|
||||
aria-label={intl.formatMessage(messages.enterSearch)}
|
||||
>
|
||||
<Icon id='plus' icon={AddIcon} />
|
||||
</button>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<ColumnSearchHeader
|
||||
onBack={handleDismissSearchClick}
|
||||
onSubmit={handleSearch}
|
||||
/>
|
||||
)}
|
||||
|
||||
<ScrollableList
|
||||
scrollKey='list_members'
|
||||
trackScroll={!multiColumn}
|
||||
bindToDocument={!multiColumn}
|
||||
isLoading={loading}
|
||||
showLoading={loading && displayedAccountIds.length === 0}
|
||||
hasMore={false}
|
||||
footer={
|
||||
mode === 'remove' && (
|
||||
<>
|
||||
{displayedAccountIds.length > 0 && <div className='spacer' />}
|
||||
|
||||
<div className='column-footer'>
|
||||
<Link to={`/lists/${id}`} className='button button--block'>
|
||||
<FormattedMessage id='lists.done' defaultMessage='Done' />
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
emptyMessage={
|
||||
mode === 'remove' ? (
|
||||
<>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='lists.no_members_yet'
|
||||
defaultMessage='No members yet.'
|
||||
/>
|
||||
<br />
|
||||
<FormattedMessage
|
||||
id='lists.find_users_to_add'
|
||||
defaultMessage='Find users to add'
|
||||
/>
|
||||
</span>
|
||||
|
||||
<SquigglyArrow className='empty-column-indicator__arrow' />
|
||||
</>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id='lists.no_results_found'
|
||||
defaultMessage='No results found.'
|
||||
/>
|
||||
)
|
||||
}
|
||||
>
|
||||
{displayedAccountIds.map((accountId) => (
|
||||
<AccountItem
|
||||
key={accountId}
|
||||
accountId={accountId}
|
||||
listId={id}
|
||||
partOfList={
|
||||
displayedAccountIds === accountIds ||
|
||||
accountIds.includes(accountId)
|
||||
}
|
||||
onToggle={handleAccountToggle}
|
||||
/>
|
||||
))}
|
||||
</ScrollableList>
|
||||
|
||||
<Helmet>
|
||||
<title>{intl.formatMessage(messages.heading)}</title>
|
||||
<meta name='robots' content='noindex' />
|
||||
</Helmet>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default ListMembers;
|
|
@ -7,27 +7,34 @@ import { useParams, Link } from 'react-router-dom';
|
|||
|
||||
import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
|
||||
import DomainIcon from '@/material-icons/400-24px/dns.svg?react';
|
||||
//import EditIcon from '@/material-icons/400-24px/edit.svg?react';
|
||||
//import HashtagIcon from '@/material-icons/400-24px/tag.svg?react';
|
||||
//import KeywordIcon from '@/material-icons/400-24px/title.svg?react';
|
||||
import HashtagIcon from '@/material-icons/400-24px/tag.svg?react';
|
||||
import KeywordIcon from '@/material-icons/400-24px/title.svg?react';
|
||||
import AntennaIcon from '@/material-icons/400-24px/wifi.svg?react';
|
||||
import { fetchAntenna } from 'mastodon/actions/antennas';
|
||||
import {
|
||||
fetchAntenna,
|
||||
fetchAntennaAccounts,
|
||||
fetchAntennaDomains,
|
||||
fetchAntennaExcludeAccounts,
|
||||
fetchAntennaKeywords,
|
||||
fetchAntennaTags,
|
||||
} from 'mastodon/actions/antennas';
|
||||
import {
|
||||
apiAddDomain,
|
||||
apiGetAccounts,
|
||||
apiGetDomains,
|
||||
apiAddDomain,
|
||||
apiRemoveDomain,
|
||||
apiGetTags,
|
||||
apiAddTag,
|
||||
apiRemoveTag,
|
||||
apiGetKeywords,
|
||||
apiAddKeyword,
|
||||
apiRemoveKeyword,
|
||||
apiAddExcludeDomain,
|
||||
apiRemoveExcludeDomain,
|
||||
apiAddExcludeTag,
|
||||
apiRemoveExcludeTag,
|
||||
apiAddExcludeKeyword,
|
||||
apiRemoveExcludeKeyword,
|
||||
apiGetExcludeAccounts,
|
||||
} from 'mastodon/api/antennas';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import Column from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import type { IconProp , Icon } from 'mastodon/components/icon';
|
||||
import type { IconProp } from 'mastodon/components/icon';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { IconButton } from 'mastodon/components/icon_button';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
|
@ -83,7 +90,9 @@ const TextListItem: React.FC<{
|
|||
value: string;
|
||||
onRemove: (value: string) => void;
|
||||
}> = ({ icon, iconComponent, value, onRemove }) => {
|
||||
const handleRemove = useCallback(() => { onRemove(value); }, [onRemove, value]);
|
||||
const handleRemove = useCallback(() => {
|
||||
onRemove(value);
|
||||
}, [onRemove, value]);
|
||||
|
||||
return (
|
||||
<div className='setting-text-list-item'>
|
||||
|
@ -133,7 +142,9 @@ const TextList: React.FC<{
|
|||
}, [onAdd, value]);
|
||||
|
||||
const handleRemove = useCallback(
|
||||
(removeValue: string) => { onRemove(removeValue); },
|
||||
(removeValue: string) => {
|
||||
onRemove(removeValue);
|
||||
},
|
||||
[onRemove],
|
||||
);
|
||||
|
||||
|
@ -141,16 +152,6 @@ const TextList: React.FC<{
|
|||
|
||||
return (
|
||||
<div className='setting-text-list'>
|
||||
{values.map((val) => (
|
||||
<TextListItem
|
||||
key={val}
|
||||
value={val}
|
||||
icon={icon}
|
||||
iconComponent={iconComponent}
|
||||
onRemove={handleRemove}
|
||||
/>
|
||||
))}
|
||||
|
||||
<form className='add-text-form' onSubmit={handleSubmit}>
|
||||
<label>
|
||||
<span style={{ display: 'none' }}>{label}</span>
|
||||
|
@ -170,6 +171,16 @@ const TextList: React.FC<{
|
|||
onClick={handleAdd}
|
||||
/>
|
||||
</form>
|
||||
|
||||
{values.map((val) => (
|
||||
<TextListItem
|
||||
key={val}
|
||||
value={val}
|
||||
icon={icon}
|
||||
iconComponent={iconComponent}
|
||||
onRemove={handleRemove}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -185,25 +196,26 @@ const RadioPanel: React.FC<{
|
|||
|
||||
useEffect(() => {
|
||||
if (valueLengths.length >= 2) {
|
||||
setError(valueLengths.slice(1).some((v) => v > 0));
|
||||
setError(valueLengths.filter((v) => v > 0).length > 1);
|
||||
} else {
|
||||
setError(false);
|
||||
}
|
||||
}, [valueLengths]);
|
||||
|
||||
useEffect(() => {
|
||||
if (items.length > 0 && !items.some((i) => i.value === value)) {
|
||||
if (items.length > 0) {
|
||||
for (let i = 0; i < valueLengths.length; i++) {
|
||||
const length = valueLengths[i] ?? 0;
|
||||
const item = items[i] ?? { value: '' };
|
||||
if (length > 0) {
|
||||
setValue(item.value);
|
||||
onChange(item.value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
setValue(items[0]?.value ?? '');
|
||||
}
|
||||
}, [items]);
|
||||
}, [items, valueLengths, setValue, onChange]);
|
||||
|
||||
const handleChange = useCallback(
|
||||
({ currentTarget }: React.MouseEvent<HTMLButtonElement>) => {
|
||||
|
@ -213,7 +225,7 @@ const RadioPanel: React.FC<{
|
|||
setValue(selected);
|
||||
}
|
||||
},
|
||||
[setValue],
|
||||
[value, setValue, onChange],
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -240,26 +252,33 @@ const RadioPanel: React.FC<{
|
|||
|
||||
const MembersLink: React.FC<{
|
||||
id: string;
|
||||
onCountFetched: (count: number) => void;
|
||||
}> = ({ id, onCountFetched }) => {
|
||||
isExclude: boolean;
|
||||
onCountFetched?: (count: number) => void;
|
||||
}> = ({ id, isExclude, onCountFetched }) => {
|
||||
const [count, setCount] = useState(0);
|
||||
const [avatars, setAvatars] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
void apiGetAccounts(id)
|
||||
const api = isExclude ? apiGetExcludeAccounts : apiGetAccounts;
|
||||
void api(id)
|
||||
.then((data) => {
|
||||
setCount(data.length);
|
||||
onCountFetched(data.length);
|
||||
if (onCountFetched) {
|
||||
onCountFetched(data.length);
|
||||
}
|
||||
setAvatars(data.slice(0, 3).map((a) => a.avatar));
|
||||
return '';
|
||||
})
|
||||
.catch(() => {
|
||||
// Nothing
|
||||
});
|
||||
}, [id, setCount, setAvatars]);
|
||||
}, [id, setCount, setAvatars, isExclude, onCountFetched]);
|
||||
|
||||
return (
|
||||
<Link to={`/antennas/${id}/members`} className='app-form__link'>
|
||||
<Link
|
||||
to={`/antennas/${id}/${isExclude ? 'exclude_members' : 'members'}`}
|
||||
className='app-form__link'
|
||||
>
|
||||
<div className='app-form__link__text'>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
|
@ -294,29 +313,48 @@ const AntennaSetting: React.FC<{
|
|||
const antenna = useAppSelector((state) =>
|
||||
id ? state.antennas.get(id) : undefined,
|
||||
);
|
||||
const domains = useAppSelector((state) =>
|
||||
id ? state.antennas.getIn(['domains', id]) : undefined,
|
||||
) as string[] | undefined;
|
||||
const [domainList, setDomainList] = useState([] as string[]);
|
||||
const [excludeDomainList, setExcludeDomainList] = useState([] as string[]);
|
||||
const [tagList, setTagList] = useState([] as string[]);
|
||||
const [excludeTagList, setExcludeTagList] = useState([] as string[]);
|
||||
const [keywordList, setKeywordList] = useState([] as string[]);
|
||||
const [excludeKeywordList, setExcludeKeywordList] = useState([] as string[]);
|
||||
const [accountsCount, setAccountsCount] = useState(0);
|
||||
const [rangeMode, setRangeMode] = useState('accounts');
|
||||
const [contentMode, setContentMode] = useState('keywords');
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
dispatch(fetchAntenna(id));
|
||||
dispatch(fetchAntennaKeywords(id));
|
||||
dispatch(fetchAntennaDomains(id));
|
||||
dispatch(fetchAntennaTags(id));
|
||||
dispatch(fetchAntennaAccounts(id));
|
||||
dispatch(fetchAntennaExcludeAccounts(id));
|
||||
}
|
||||
}, [dispatch, id]);
|
||||
|
||||
useEffect(() => {
|
||||
if (id && antenna) {
|
||||
setDomainList(domains ?? []);
|
||||
void apiGetDomains(id).then((data) => {
|
||||
setDomainList(data.domains);
|
||||
setExcludeDomainList(data.exclude_domains);
|
||||
return true;
|
||||
});
|
||||
|
||||
void apiGetTags(id).then((data) => {
|
||||
setTagList(data.tags);
|
||||
setExcludeTagList(data.exclude_tags);
|
||||
return true;
|
||||
});
|
||||
|
||||
void apiGetKeywords(id).then((data) => {
|
||||
setKeywordList(data.keywords);
|
||||
setExcludeKeywordList(data.exclude_keywords);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}, [id, antenna, domains, setDomainList]);
|
||||
}, [
|
||||
dispatch,
|
||||
id,
|
||||
setDomainList,
|
||||
setExcludeDomainList,
|
||||
setTagList,
|
||||
setExcludeTagList,
|
||||
setKeywordList,
|
||||
setExcludeKeywordList,
|
||||
]);
|
||||
|
||||
const handleAccountsFetched = useCallback(
|
||||
(count: number) => {
|
||||
|
@ -349,15 +387,166 @@ const AntennaSetting: React.FC<{
|
|||
[id, domainList, setDomainList],
|
||||
);
|
||||
|
||||
const handleAddExcludeDomain = useCallback(
|
||||
(value: string) => {
|
||||
if (!id) return;
|
||||
|
||||
void apiAddExcludeDomain(id, value).then(() => {
|
||||
setExcludeDomainList([...excludeDomainList, value]);
|
||||
return value;
|
||||
});
|
||||
},
|
||||
[id, excludeDomainList, setExcludeDomainList],
|
||||
);
|
||||
|
||||
const handleRemoveExcludeDomain = useCallback(
|
||||
(value: string) => {
|
||||
if (!id) return;
|
||||
|
||||
void apiRemoveExcludeDomain(id, value).then(() => {
|
||||
setExcludeDomainList(excludeDomainList.filter((v) => v !== value));
|
||||
return value;
|
||||
});
|
||||
},
|
||||
[id, excludeDomainList, setExcludeDomainList],
|
||||
);
|
||||
|
||||
const handleAddTag = useCallback(
|
||||
(value: string) => {
|
||||
if (!id) return;
|
||||
|
||||
void apiAddTag(id, value).then(() => {
|
||||
setTagList([...tagList, value]);
|
||||
return value;
|
||||
});
|
||||
},
|
||||
[id, tagList, setTagList],
|
||||
);
|
||||
|
||||
const handleRemoveTag = useCallback(
|
||||
(value: string) => {
|
||||
if (!id) return;
|
||||
|
||||
void apiRemoveTag(id, value).then(() => {
|
||||
setTagList(tagList.filter((v) => v !== value));
|
||||
return value;
|
||||
});
|
||||
},
|
||||
[id, tagList, setTagList],
|
||||
);
|
||||
|
||||
const handleAddExcludeTag = useCallback(
|
||||
(value: string) => {
|
||||
if (!id) return;
|
||||
|
||||
void apiAddExcludeTag(id, value).then(() => {
|
||||
setExcludeTagList([...excludeTagList, value]);
|
||||
return value;
|
||||
});
|
||||
},
|
||||
[id, excludeTagList, setExcludeTagList],
|
||||
);
|
||||
|
||||
const handleRemoveExcludeTag = useCallback(
|
||||
(value: string) => {
|
||||
if (!id) return;
|
||||
|
||||
void apiRemoveExcludeTag(id, value).then(() => {
|
||||
setExcludeTagList(excludeTagList.filter((v) => v !== value));
|
||||
return value;
|
||||
});
|
||||
},
|
||||
[id, excludeTagList, setExcludeTagList],
|
||||
);
|
||||
|
||||
const handleAddKeyword = useCallback(
|
||||
(value: string) => {
|
||||
if (!id) return;
|
||||
|
||||
void apiAddKeyword(id, value).then(() => {
|
||||
setKeywordList([...keywordList, value]);
|
||||
return value;
|
||||
});
|
||||
},
|
||||
[id, keywordList, setKeywordList],
|
||||
);
|
||||
|
||||
const handleRemoveKeyword = useCallback(
|
||||
(value: string) => {
|
||||
if (!id) return;
|
||||
|
||||
void apiRemoveKeyword(id, value).then(() => {
|
||||
setKeywordList(keywordList.filter((v) => v !== value));
|
||||
return value;
|
||||
});
|
||||
},
|
||||
[id, keywordList, setKeywordList],
|
||||
);
|
||||
|
||||
const handleAddExcludeKeyword = useCallback(
|
||||
(value: string) => {
|
||||
if (!id) return;
|
||||
|
||||
void apiAddExcludeKeyword(id, value).then(() => {
|
||||
setExcludeKeywordList([...excludeKeywordList, value]);
|
||||
return value;
|
||||
});
|
||||
},
|
||||
[id, excludeKeywordList, setExcludeKeywordList],
|
||||
);
|
||||
|
||||
const handleRemoveExcludeKeyword = useCallback(
|
||||
(value: string) => {
|
||||
if (!id) return;
|
||||
|
||||
void apiRemoveExcludeKeyword(id, value).then(() => {
|
||||
setExcludeKeywordList(excludeKeywordList.filter((v) => v !== value));
|
||||
return value;
|
||||
});
|
||||
},
|
||||
[id, excludeKeywordList, setExcludeKeywordList],
|
||||
);
|
||||
|
||||
const handleRangeRadioChange = useCallback(
|
||||
(value: string) => {
|
||||
setRangeMode(value);
|
||||
},
|
||||
[id, antenna, setRangeMode],
|
||||
[setRangeMode],
|
||||
);
|
||||
|
||||
const handleContentRadioChange = useCallback(
|
||||
(value: string) => {
|
||||
setContentMode(value);
|
||||
},
|
||||
[setContentMode],
|
||||
);
|
||||
|
||||
if (!antenna || !id) return <div />;
|
||||
|
||||
if (antenna.stl)
|
||||
return (
|
||||
<div className='antenna-setting'>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='antennas.in_stl_mode'
|
||||
defaultMessage='This antenna is in STL mode.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (antenna.ltl)
|
||||
return (
|
||||
<div className='antenna-setting'>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='antennas.in_ltl_mode'
|
||||
defaultMessage='This antenna is in LTL mode.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
const rangeRadioItems = [
|
||||
{
|
||||
value: 'accounts',
|
||||
|
@ -368,7 +557,21 @@ const AntennaSetting: React.FC<{
|
|||
title: intl.formatMessage(messages.domains, { count: domainList.length }),
|
||||
},
|
||||
];
|
||||
const rangeRadioLengths = [0, domainList.length];
|
||||
const rangeRadioLengths = [accountsCount, domainList.length];
|
||||
|
||||
const contentRadioItems = [
|
||||
{
|
||||
value: 'keywords',
|
||||
title: intl.formatMessage(messages.keywords, {
|
||||
count: keywordList.length,
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: 'tags',
|
||||
title: intl.formatMessage(messages.tags, { count: tagList.length }),
|
||||
},
|
||||
];
|
||||
const contentRadioLengths = [keywordList.length, tagList.length];
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} label={antenna.title}>
|
||||
|
@ -395,7 +598,11 @@ const AntennaSetting: React.FC<{
|
|||
onChange={handleRangeRadioChange}
|
||||
/>
|
||||
{rangeMode === 'accounts' && (
|
||||
<MembersLink id={id} onCountFetched={handleAccountsFetched} />
|
||||
<MembersLink
|
||||
id={id}
|
||||
onCountFetched={handleAccountsFetched}
|
||||
isExclude={false}
|
||||
/>
|
||||
)}
|
||||
{rangeMode === 'domains' && (
|
||||
<TextList
|
||||
|
@ -408,6 +615,101 @@ const AntennaSetting: React.FC<{
|
|||
onRemove={handleRemoveDomain}
|
||||
/>
|
||||
)}
|
||||
|
||||
<RadioPanel
|
||||
items={contentRadioItems}
|
||||
valueLengths={contentRadioLengths}
|
||||
alertMessage={
|
||||
<div className='alert'>
|
||||
<FormattedMessage
|
||||
id='antennas.warnings.content_radio'
|
||||
defaultMessage='Simultaneous keyword and tag designation is not recommended.'
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
onChange={handleContentRadioChange}
|
||||
/>
|
||||
{contentMode === 'keywords' && (
|
||||
<TextList
|
||||
values={keywordList}
|
||||
icon='paragraph'
|
||||
iconComponent={KeywordIcon}
|
||||
label={intl.formatMessage(messages.addKeywordLabel)}
|
||||
title={intl.formatMessage(messages.addKeywordTitle)}
|
||||
onAdd={handleAddKeyword}
|
||||
onRemove={handleRemoveKeyword}
|
||||
/>
|
||||
)}
|
||||
{contentMode === 'tags' && (
|
||||
<TextList
|
||||
values={tagList}
|
||||
icon='hashtag'
|
||||
iconComponent={HashtagIcon}
|
||||
label={intl.formatMessage(messages.addTagLabel)}
|
||||
title={intl.formatMessage(messages.addTagTitle)}
|
||||
onAdd={handleAddTag}
|
||||
onRemove={handleRemoveTag}
|
||||
/>
|
||||
)}
|
||||
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id='antennas.filter_not'
|
||||
defaultMessage='Filter Not'
|
||||
/>
|
||||
</h2>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='antennas.exclude_accounts'
|
||||
defaultMessage='Exclude accounts'
|
||||
/>
|
||||
</h3>
|
||||
<MembersLink id={id} isExclude />
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='antennas.exclude_domains'
|
||||
defaultMessage='Exclude domains'
|
||||
/>
|
||||
</h3>
|
||||
<TextList
|
||||
values={excludeDomainList}
|
||||
icon='sitemap'
|
||||
iconComponent={DomainIcon}
|
||||
label={intl.formatMessage(messages.addDomainLabel)}
|
||||
title={intl.formatMessage(messages.addDomainTitle)}
|
||||
onAdd={handleAddExcludeDomain}
|
||||
onRemove={handleRemoveExcludeDomain}
|
||||
/>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='antennas.exclude_keywords'
|
||||
defaultMessage='Exclude keywords'
|
||||
/>
|
||||
</h3>
|
||||
<TextList
|
||||
values={excludeKeywordList}
|
||||
icon='paragraph'
|
||||
iconComponent={KeywordIcon}
|
||||
label={intl.formatMessage(messages.addKeywordLabel)}
|
||||
title={intl.formatMessage(messages.addKeywordTitle)}
|
||||
onAdd={handleAddExcludeKeyword}
|
||||
onRemove={handleRemoveExcludeKeyword}
|
||||
/>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='antennas.exclude_tags'
|
||||
defaultMessage='Exclude tags'
|
||||
/>
|
||||
</h3>
|
||||
<TextList
|
||||
values={excludeTagList}
|
||||
icon='paragraph'
|
||||
iconComponent={HashtagIcon}
|
||||
label={intl.formatMessage(messages.addTagLabel)}
|
||||
title={intl.formatMessage(messages.addTagTitle)}
|
||||
onAdd={handleAddExcludeTag}
|
||||
onRemove={handleRemoveExcludeTag}
|
||||
/>
|
||||
</div>
|
||||
</Column>
|
||||
);
|
|
@ -34,14 +34,15 @@ const AntennaItem: React.FC<{
|
|||
title: string;
|
||||
insert_feeds: boolean;
|
||||
isList: boolean;
|
||||
}> = ({ id, title, insert_feeds, isList }) => {
|
||||
listTitle?: string;
|
||||
}> = ({ id, title, insert_feeds, isList, listTitle }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
|
||||
const handleDeleteClick = useCallback(() => {
|
||||
dispatch(
|
||||
openModal({
|
||||
modalType: 'CONFIRM_DELETE_LIST',
|
||||
modalType: 'CONFIRM_DELETE_ANTENNA',
|
||||
modalProps: {
|
||||
antennaId: id,
|
||||
},
|
||||
|
@ -58,15 +59,18 @@ const AntennaItem: React.FC<{
|
|||
);
|
||||
|
||||
return (
|
||||
<div className='antennas__item'>
|
||||
<Link to={`/antennas/${id}`} className='antennas__item__title'>
|
||||
<div className='lists__item'>
|
||||
<Link to={`/antennas/${id}`} className='lists__item__title'>
|
||||
<Icon id='antenna-ul' icon={AntennaIcon} />
|
||||
<span>{title}</span>
|
||||
{insert_feeds
|
||||
? intl.formatMessage(
|
||||
isList ? messages.insert_list : messages.insert_home,
|
||||
)
|
||||
: undefined}
|
||||
{insert_feeds ? (
|
||||
<span className='column-link__badge'>
|
||||
{isList
|
||||
? (listTitle?.slice(0, 4) ??
|
||||
intl.formatMessage(messages.insert_list))
|
||||
: intl.formatMessage(messages.insert_home)}
|
||||
</span>
|
||||
) : undefined}
|
||||
</Link>
|
||||
|
||||
<DropdownMenuContainer
|
||||
|
@ -144,6 +148,7 @@ const Antennas: React.FC<{
|
|||
title={antenna.title}
|
||||
insert_feeds={antenna.insert_feeds}
|
||||
isList={!!antenna.list}
|
||||
listTitle={antenna.list?.title}
|
||||
/>
|
||||
))}
|
||||
</ScrollableList>
|
||||
|
|
|
@ -19,6 +19,9 @@ import {
|
|||
apiGetAccounts,
|
||||
apiAddAccountToAntenna,
|
||||
apiRemoveAccountFromAntenna,
|
||||
apiRemoveExcludeAccountFromAntenna,
|
||||
apiAddExcludeAccountToAntenna,
|
||||
apiGetExcludeAccounts,
|
||||
} from 'mastodon/api/antennas';
|
||||
import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
|
||||
import { Avatar } from 'mastodon/components/avatar';
|
||||
|
@ -107,20 +110,27 @@ const AccountItem: React.FC<{
|
|||
accountId: string;
|
||||
antennaId: string;
|
||||
partOfAntenna: boolean;
|
||||
isExclude?: boolean;
|
||||
onToggle: (accountId: string) => void;
|
||||
}> = ({ accountId, antennaId, partOfAntenna, onToggle }) => {
|
||||
}> = ({ accountId, antennaId, partOfAntenna, isExclude, onToggle }) => {
|
||||
const intl = useIntl();
|
||||
const account = useAppSelector((state) => state.accounts.get(accountId));
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (partOfAntenna) {
|
||||
void apiRemoveAccountFromAntenna(antennaId, accountId);
|
||||
const api = isExclude
|
||||
? apiRemoveExcludeAccountFromAntenna
|
||||
: apiRemoveAccountFromAntenna;
|
||||
void api(antennaId, accountId);
|
||||
} else {
|
||||
void apiAddAccountToAntenna(antennaId, accountId);
|
||||
const api = isExclude
|
||||
? apiAddExcludeAccountToAntenna
|
||||
: apiAddAccountToAntenna;
|
||||
void api(antennaId, accountId);
|
||||
}
|
||||
|
||||
onToggle(accountId);
|
||||
}, [accountId, antennaId, partOfAntenna, onToggle]);
|
||||
}, [accountId, antennaId, partOfAntenna, onToggle, isExclude]);
|
||||
|
||||
if (!account) {
|
||||
return null;
|
||||
|
@ -171,8 +181,9 @@ const AccountItem: React.FC<{
|
|||
};
|
||||
|
||||
const AntennaMembers: React.FC<{
|
||||
isExclude?: boolean;
|
||||
multiColumn?: boolean;
|
||||
}> = ({ multiColumn }) => {
|
||||
}> = ({ isExclude, multiColumn }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const intl = useIntl();
|
||||
|
@ -188,7 +199,8 @@ const AntennaMembers: React.FC<{
|
|||
setLoading(true);
|
||||
dispatch(fetchAntenna(id));
|
||||
|
||||
void apiGetAccounts(id)
|
||||
const api = isExclude ? apiGetExcludeAccounts : apiGetAccounts;
|
||||
void api(id)
|
||||
.then((data) => {
|
||||
dispatch(importFetchedAccounts(data));
|
||||
setAccountIds(data.map((a) => a.id));
|
||||
|
@ -201,7 +213,7 @@ const AntennaMembers: React.FC<{
|
|||
|
||||
dispatch(fetchFollowing(me));
|
||||
}
|
||||
}, [dispatch, id]);
|
||||
}, [dispatch, id, isExclude]);
|
||||
|
||||
const handleSearchClick = useCallback(() => {
|
||||
setMode('add');
|
||||
|
@ -317,7 +329,10 @@ const AntennaMembers: React.FC<{
|
|||
{displayedAccountIds.length > 0 && <div className='spacer' />}
|
||||
|
||||
<div className='column-footer'>
|
||||
<Link to={`/antennasw/${id}`} className='button button--block'>
|
||||
<Link
|
||||
to={`/antennas/${id}/filtering`}
|
||||
className='button button--block'
|
||||
>
|
||||
<FormattedMessage id='antennas.done' defaultMessage='Done' />
|
||||
</Link>
|
||||
</div>
|
||||
|
@ -358,6 +373,7 @@ const AntennaMembers: React.FC<{
|
|||
displayedAccountIds === accountIds ||
|
||||
accountIds.includes(accountId)
|
||||
}
|
||||
isExclude={isExclude}
|
||||
onToggle={handleAccountToggle}
|
||||
/>
|
||||
))}
|
||||
|
|
|
@ -16,6 +16,7 @@ import { fetchLists } from 'mastodon/actions/lists';
|
|||
import Column from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||
import { getOrderedLists } from 'mastodon/selectors/lists';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
@ -27,12 +28,12 @@ const FiltersLink: React.FC<{
|
|||
id: string;
|
||||
}> = ({ id }) => {
|
||||
return (
|
||||
<Link to={`/antennasw/${id}`} className='app-form__link'>
|
||||
<Link to={`/antennas/${id}/filtering`} className='app-form__link'>
|
||||
<div className='app-form__link__text'>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id='antennas.filter_items'
|
||||
defaultMessage='Antenna filtering'
|
||||
defaultMessage='Antenna filter settings'
|
||||
/>
|
||||
</strong>
|
||||
</div>
|
||||
|
@ -51,7 +52,7 @@ const NewAntenna: React.FC<{
|
|||
const antenna = useAppSelector((state) =>
|
||||
id ? state.antennas.get(id) : undefined,
|
||||
);
|
||||
const lists = useAppSelector((state) => state.lists);
|
||||
const lists = useAppSelector((state) => getOrderedLists(state));
|
||||
const [title, setTitle] = useState('');
|
||||
const [stl, setStl] = useState(false);
|
||||
const [ltl, setLtl] = useState(false);
|
||||
|
@ -59,6 +60,8 @@ const NewAntenna: React.FC<{
|
|||
const [listId, setListId] = useState('');
|
||||
const [withMediaOnly, setWithMediaOnly] = useState(false);
|
||||
const [ignoreReblog, setIgnoreReblog] = useState(false);
|
||||
const [mode, setMode] = useState('filtering');
|
||||
const [destination, setDestination] = useState('home');
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -74,9 +77,27 @@ const NewAntenna: React.FC<{
|
|||
setStl(antenna.stl);
|
||||
setLtl(antenna.ltl);
|
||||
setInsertFeeds(antenna.insert_feeds);
|
||||
setListId(antenna.list?.id ?? '');
|
||||
setListId(antenna.list?.id ?? '0');
|
||||
setWithMediaOnly(antenna.with_media_only);
|
||||
setIgnoreReblog(antenna.ignore_reblog);
|
||||
|
||||
if (antenna.stl) {
|
||||
setMode('stl');
|
||||
} else if (antenna.ltl) {
|
||||
setMode('ltl');
|
||||
} else {
|
||||
setMode('filtering');
|
||||
}
|
||||
|
||||
if (antenna.insert_feeds) {
|
||||
if (antenna.list) {
|
||||
setDestination('list');
|
||||
} else {
|
||||
setDestination('home');
|
||||
}
|
||||
} else {
|
||||
setDestination('timeline');
|
||||
}
|
||||
}
|
||||
}, [
|
||||
setTitle,
|
||||
|
@ -86,6 +107,8 @@ const NewAntenna: React.FC<{
|
|||
setListId,
|
||||
setWithMediaOnly,
|
||||
setIgnoreReblog,
|
||||
setMode,
|
||||
setDestination,
|
||||
id,
|
||||
antenna,
|
||||
lists,
|
||||
|
@ -98,29 +121,6 @@ const NewAntenna: React.FC<{
|
|||
[setTitle],
|
||||
);
|
||||
|
||||
/*
|
||||
const handleStlChange = useCallback(
|
||||
({ target: { checked } }: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setStl(checked);
|
||||
},
|
||||
[setStl],
|
||||
);
|
||||
|
||||
const handleLtlChange = useCallback(
|
||||
({ target: { checked } }: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setLtl(checked);
|
||||
},
|
||||
[setLtl],
|
||||
);
|
||||
*/
|
||||
|
||||
const handleInsertFeedsChange = useCallback(
|
||||
({ target: { checked } }: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setInsertFeeds(checked);
|
||||
},
|
||||
[setInsertFeeds],
|
||||
);
|
||||
|
||||
const handleListIdChange = useCallback(
|
||||
({ target: { value } }: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
setListId(value);
|
||||
|
@ -128,7 +128,43 @@ const NewAntenna: React.FC<{
|
|||
[setListId],
|
||||
);
|
||||
|
||||
/*
|
||||
const handleModeChange = useCallback(
|
||||
({ target: { value } }: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
if (value === 'stl') {
|
||||
setStl(true);
|
||||
setLtl(false);
|
||||
} else if (value === 'ltl') {
|
||||
setStl(false);
|
||||
setLtl(true);
|
||||
} else if (value === 'filtering') {
|
||||
setStl(false);
|
||||
setLtl(false);
|
||||
}
|
||||
|
||||
setMode(value);
|
||||
},
|
||||
[setLtl, setStl, setMode, listId, setListId, lists],
|
||||
);
|
||||
|
||||
const handleDestinationChange = useCallback(
|
||||
({ target: { value } }: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
if (value === 'list') {
|
||||
setInsertFeeds(true);
|
||||
if (listId === '0' && lists.length > 0) {
|
||||
setListId(lists[0]?.id ?? '0');
|
||||
}
|
||||
} else if (value === 'home') {
|
||||
setInsertFeeds(true);
|
||||
// listId = 0
|
||||
} else if (value === 'timeline') {
|
||||
setInsertFeeds(false);
|
||||
}
|
||||
|
||||
setDestination(value);
|
||||
},
|
||||
[setDestination, setListId, listId, lists],
|
||||
);
|
||||
|
||||
const handleWithMediaOnlyChange = useCallback(
|
||||
({ target: { checked } }: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setWithMediaOnly(checked);
|
||||
|
@ -142,7 +178,6 @@ const NewAntenna: React.FC<{
|
|||
},
|
||||
[setIgnoreReblog],
|
||||
);
|
||||
*/
|
||||
|
||||
const handleSubmit = useCallback(() => {
|
||||
setSubmitting(true);
|
||||
|
@ -155,7 +190,7 @@ const NewAntenna: React.FC<{
|
|||
stl,
|
||||
ltl,
|
||||
insert_feeds: insertFeeds,
|
||||
list_id: listId,
|
||||
list_id: destination === 'list' ? listId : '0',
|
||||
with_media_only: withMediaOnly,
|
||||
ignore_reblog: ignoreReblog,
|
||||
}),
|
||||
|
@ -170,7 +205,7 @@ const NewAntenna: React.FC<{
|
|||
stl,
|
||||
ltl,
|
||||
insert_feeds: insertFeeds,
|
||||
list_id: listId,
|
||||
list_id: destination === 'list' ? listId : '0',
|
||||
with_media_only: withMediaOnly,
|
||||
ignore_reblog: ignoreReblog,
|
||||
}),
|
||||
|
@ -197,6 +232,7 @@ const NewAntenna: React.FC<{
|
|||
listId,
|
||||
withMediaOnly,
|
||||
ignoreReblog,
|
||||
destination,
|
||||
]);
|
||||
|
||||
return (
|
||||
|
@ -240,32 +276,40 @@ const NewAntenna: React.FC<{
|
|||
</div>
|
||||
|
||||
<div className='fields-group'>
|
||||
{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
|
||||
<label className='app-form__toggle'>
|
||||
<div className='app-form__toggle__label'>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id='antennas.insert_feeds'
|
||||
defaultMessage='Insert to feeds'
|
||||
/>
|
||||
</strong>
|
||||
<span className='hint'>
|
||||
<FormattedMessage
|
||||
id='antennas.insert_feeds_hint'
|
||||
defaultMessage='Insert to any timelines.'
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div className='input with_label'>
|
||||
<div className='label_input'>
|
||||
<label htmlFor='antenna_list'>
|
||||
<FormattedMessage id='antennas.mode' defaultMessage='Mode' />
|
||||
</label>
|
||||
|
||||
<div className='app-form__toggle__toggle'>
|
||||
<div>
|
||||
<Toggle
|
||||
checked={insertFeeds}
|
||||
onChange={handleInsertFeedsChange}
|
||||
/>
|
||||
<div className='label_input__wrapper'>
|
||||
<select
|
||||
id='antenna_insert_list'
|
||||
value={mode}
|
||||
onChange={handleModeChange}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='antennas.mode.stl'
|
||||
defaultMessage='Social timeline mode'
|
||||
>
|
||||
{(msg) => <option value='stl'>{msg}</option>}
|
||||
</FormattedMessage>
|
||||
<FormattedMessage
|
||||
id='antennas.mode.ltl'
|
||||
defaultMessage='Local timeline mode'
|
||||
>
|
||||
{(msg) => <option value='ltl'>{msg}</option>}
|
||||
</FormattedMessage>
|
||||
<FormattedMessage
|
||||
id='antennas.mode.filtering'
|
||||
defaultMessage='Filtering'
|
||||
>
|
||||
{(msg) => <option value='filtering'>{msg}</option>}
|
||||
</FormattedMessage>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='fields-group'>
|
||||
|
@ -273,38 +317,136 @@ const NewAntenna: React.FC<{
|
|||
<div className='label_input'>
|
||||
<label htmlFor='antenna_list'>
|
||||
<FormattedMessage
|
||||
id='antennas.insert_list'
|
||||
defaultMessage='List'
|
||||
id='antennas.destination'
|
||||
defaultMessage='Destination'
|
||||
/>
|
||||
</label>
|
||||
|
||||
<div className='label_input__wrapper'>
|
||||
<select
|
||||
id='antenna_insert_list'
|
||||
value={listId}
|
||||
onChange={handleListIdChange}
|
||||
id='antenna_insert_destination'
|
||||
value={destination}
|
||||
onChange={handleDestinationChange}
|
||||
>
|
||||
<option value=''>Home</option>
|
||||
{lists.forEach(
|
||||
(list) =>
|
||||
list !== null && (
|
||||
<option key={list.id} value={list.id}>
|
||||
{list.title}
|
||||
</option>
|
||||
),
|
||||
)}
|
||||
<FormattedMessage
|
||||
id='antennas.destination.home'
|
||||
defaultMessage='Insert to home'
|
||||
>
|
||||
{(msg) => <option value='home'>{msg}</option>}
|
||||
</FormattedMessage>
|
||||
<FormattedMessage
|
||||
id='antennas.destination.list'
|
||||
defaultMessage='Insert to list'
|
||||
>
|
||||
{(msg) => <option value='list'>{msg}</option>}
|
||||
</FormattedMessage>
|
||||
<FormattedMessage
|
||||
id='antennas.destination.timeline'
|
||||
defaultMessage='Antenna timeline only'
|
||||
>
|
||||
{(msg) => <option value='timeline'>{msg}</option>}
|
||||
</FormattedMessage>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{id && (
|
||||
{destination === 'list' && (
|
||||
<div className='fields-group'>
|
||||
<FiltersLink id={id} />
|
||||
<div className='input with_label'>
|
||||
<div className='label_input'>
|
||||
<label htmlFor='antenna_list'>
|
||||
<FormattedMessage
|
||||
id='antennas.insert_list'
|
||||
defaultMessage='List'
|
||||
/>
|
||||
</label>
|
||||
|
||||
<div className='label_input__wrapper'>
|
||||
<select
|
||||
id='antenna_insert_list'
|
||||
value={listId}
|
||||
onChange={handleListIdChange}
|
||||
>
|
||||
{lists.map((list) => (
|
||||
<option key={list.id} value={list.id}>
|
||||
{list.title}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{id && mode === 'filtering' && (
|
||||
<>
|
||||
<div className='fields-group'>
|
||||
<FiltersLink id={id} />
|
||||
</div>
|
||||
|
||||
<div className='fields-group'>
|
||||
{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
|
||||
<label className='app-form__toggle'>
|
||||
<div className='app-form__toggle__label'>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id='antennas.media_only'
|
||||
defaultMessage='Media only'
|
||||
/>
|
||||
</strong>
|
||||
<span className='hint'>
|
||||
<FormattedMessage
|
||||
id='antennas.media_only_hint'
|
||||
defaultMessage='Only posts with media will be added antenna.'
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className='app-form__toggle__toggle'>
|
||||
<div>
|
||||
<Toggle
|
||||
checked={withMediaOnly}
|
||||
onChange={handleWithMediaOnlyChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className='fields-group'>
|
||||
{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
|
||||
<label className='app-form__toggle'>
|
||||
<div className='app-form__toggle__label'>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id='antennas.ignore_reblog'
|
||||
defaultMessage='Exclude boosts'
|
||||
/>
|
||||
</strong>
|
||||
<span className='hint'>
|
||||
<FormattedMessage
|
||||
id='antennas.ignore_reblog_hint'
|
||||
defaultMessage='Boosts will be excluded from antenna detection.'
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className='app-form__toggle__toggle'>
|
||||
<div>
|
||||
<Toggle
|
||||
checked={ignoreReblog}
|
||||
onChange={handleIgnoreReblogChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className='actions'>
|
||||
<button className='button' type='submit'>
|
||||
{submitting ? (
|
||||
|
|
|
@ -26,15 +26,15 @@ const messages = defineMessages({
|
|||
},
|
||||
create: {
|
||||
id: 'bookmark_categories.create_bookmark_category',
|
||||
defaultMessage: 'Create bookmark_category',
|
||||
defaultMessage: 'Create category',
|
||||
},
|
||||
edit: {
|
||||
id: 'bookmark_categories.edit',
|
||||
defaultMessage: 'Edit bookmark_category',
|
||||
defaultMessage: 'Edit category',
|
||||
},
|
||||
delete: {
|
||||
id: 'bookmark_categories.delete',
|
||||
defaultMessage: 'Delete bookmark_category',
|
||||
defaultMessage: 'Delete category',
|
||||
},
|
||||
more: { id: 'status.more', defaultMessage: 'More' },
|
||||
});
|
||||
|
@ -49,7 +49,7 @@ const BookmarkCategoryItem: React.FC<{
|
|||
const handleDeleteClick = useCallback(() => {
|
||||
dispatch(
|
||||
openModal({
|
||||
modalType: 'CONFIRM_DELETE_LIST',
|
||||
modalType: 'CONFIRM_DELETE_BOOKMARK_CATEGORY',
|
||||
modalProps: {
|
||||
bookmark_categoryId: id,
|
||||
},
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import AddIcon from '@/material-icons/400-24px/add.svg?react';
|
||||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||
|
||||
import { removeFromCircleEditor, addToCircleEditor } from '../../../actions/circles';
|
||||
import { Avatar } from '../../../components/avatar';
|
||||
import { DisplayName } from '../../../components/display_name';
|
||||
import { IconButton } from '../../../components/icon_button';
|
||||
import { makeGetAccount } from '../../../selectors';
|
||||
|
||||
const messages = defineMessages({
|
||||
remove: { id: 'circles.account.remove', defaultMessage: 'Remove from circle' },
|
||||
add: { id: 'circles.account.add', defaultMessage: 'Add to circle' },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
const mapStateToProps = (state, { accountId, added }) => ({
|
||||
account: getAccount(state, accountId),
|
||||
added: typeof added === 'undefined' ? state.getIn(['circleEditor', 'accounts', 'items']).includes(accountId) : added,
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { accountId }) => ({
|
||||
onRemove: () => dispatch(removeFromCircleEditor(accountId)),
|
||||
onAdd: () => dispatch(addToCircleEditor(accountId)),
|
||||
});
|
||||
|
||||
class Account extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onRemove: PropTypes.func.isRequired,
|
||||
onAdd: PropTypes.func.isRequired,
|
||||
added: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
added: false,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { account, intl, onRemove, onAdd, added } = this.props;
|
||||
|
||||
let button;
|
||||
|
||||
if (added) {
|
||||
button = <IconButton icon='times' iconComponent={CloseIcon} title={intl.formatMessage(messages.remove)} onClick={onRemove} />;
|
||||
} else {
|
||||
button = <IconButton icon='plus' iconComponent={AddIcon} title={intl.formatMessage(messages.add)} onClick={onAdd} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='account'>
|
||||
<div className='account__wrapper'>
|
||||
<div className='account__display-name'>
|
||||
<div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div>
|
||||
<DisplayName account={account} />
|
||||
</div>
|
||||
|
||||
<div className='account__relationship'>
|
||||
{button}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(makeMapStateToProps, mapDispatchToProps)(injectIntl(Account));
|
|
@ -1,76 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import CheckIcon from '@/material-icons/400-24px/check.svg?react';
|
||||
|
||||
import { changeCircleEditorTitle, submitCircleEditor } from '../../../actions/circles';
|
||||
import { IconButton } from '../../../components/icon_button';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'circles.edit.submit', defaultMessage: 'Change title' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
value: state.getIn(['circleEditor', 'title']),
|
||||
disabled: !state.getIn(['circleEditor', 'isChanged']) || !state.getIn(['circleEditor', 'title']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onChange: value => dispatch(changeCircleEditorTitle(value)),
|
||||
onSubmit: () => dispatch(submitCircleEditor(false)),
|
||||
});
|
||||
|
||||
class CircleForm extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
handleChange = e => {
|
||||
this.props.onChange(e.target.value);
|
||||
};
|
||||
|
||||
handleSubmit = e => {
|
||||
e.preventDefault();
|
||||
this.props.onSubmit();
|
||||
};
|
||||
|
||||
handleClick = () => {
|
||||
this.props.onSubmit();
|
||||
};
|
||||
|
||||
render () {
|
||||
const { value, disabled, intl } = this.props;
|
||||
|
||||
const title = intl.formatMessage(messages.title);
|
||||
|
||||
return (
|
||||
<form className='column-inline-form' onSubmit={this.handleSubmit}>
|
||||
<input
|
||||
className='setting-text'
|
||||
value={value}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
disabled={disabled}
|
||||
icon='check'
|
||||
iconComponent={CheckIcon}
|
||||
title={title}
|
||||
onClick={this.handleClick}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(CircleForm));
|
|
@ -1,83 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import CancelIcon from '@/material-icons/400-24px/cancel-fill.svg?react';
|
||||
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
|
||||
import { fetchCircleSuggestions, clearCircleSuggestions, changeCircleSuggestions } from '../../../actions/circles';
|
||||
|
||||
const messages = defineMessages({
|
||||
search: { id: 'circles.search', defaultMessage: 'Search among people follow you' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
value: state.getIn(['circleEditor', 'suggestions', 'value']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onSubmit: value => dispatch(fetchCircleSuggestions(value)),
|
||||
onClear: () => dispatch(clearCircleSuggestions()),
|
||||
onChange: value => dispatch(changeCircleSuggestions(value)),
|
||||
});
|
||||
|
||||
class Search extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
onClear: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
handleChange = e => {
|
||||
this.props.onChange(e.target.value);
|
||||
};
|
||||
|
||||
handleKeyUp = e => {
|
||||
if (e.keyCode === 13) {
|
||||
this.props.onSubmit(this.props.value);
|
||||
}
|
||||
};
|
||||
|
||||
handleClear = () => {
|
||||
this.props.onClear();
|
||||
};
|
||||
|
||||
render () {
|
||||
const { value, intl } = this.props;
|
||||
const hasValue = value.length > 0;
|
||||
|
||||
return (
|
||||
<div className='list-editor__search search'>
|
||||
<label>
|
||||
<span style={{ display: 'none' }}>{intl.formatMessage(messages.search)}</span>
|
||||
|
||||
<input
|
||||
className='search__input'
|
||||
type='text'
|
||||
value={value}
|
||||
onChange={this.handleChange}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
placeholder={intl.formatMessage(messages.search)}
|
||||
/>
|
||||
</label>
|
||||
|
||||
<div role='button' tabIndex={0} className='search__icon' onClick={this.handleClear}>
|
||||
<Icon id='search' icon={SearchIcon} className={classNames({ active: !hasValue })} />
|
||||
<Icon id='times-circle' icon={CancelIcon} aria-label={intl.formatMessage(messages.search)} className={classNames({ active: hasValue })} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(Search));
|
|
@ -1,83 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
|
||||
import { injectIntl } from 'react-intl';
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import spring from 'react-motion/lib/spring';
|
||||
|
||||
import { setupCircleEditor, clearCircleSuggestions, resetCircleEditor } from '../../actions/circles';
|
||||
import Motion from '../ui/util/optional_motion';
|
||||
|
||||
import Account from './components/account';
|
||||
import EditCircleForm from './components/edit_circle_form';
|
||||
import Search from './components/search';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
accountIds: state.getIn(['circleEditor', 'accounts', 'items']),
|
||||
searchAccountIds: state.getIn(['circleEditor', 'suggestions', 'items']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onInitialize: circleId => dispatch(setupCircleEditor(circleId)),
|
||||
onClear: () => dispatch(clearCircleSuggestions()),
|
||||
onReset: () => dispatch(resetCircleEditor()),
|
||||
});
|
||||
|
||||
class CircleEditor extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
circleId: PropTypes.string.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
onInitialize: PropTypes.func.isRequired,
|
||||
onClear: PropTypes.func.isRequired,
|
||||
onReset: PropTypes.func.isRequired,
|
||||
accountIds: ImmutablePropTypes.list.isRequired,
|
||||
searchAccountIds: ImmutablePropTypes.list.isRequired,
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
const { onInitialize, circleId } = this.props;
|
||||
onInitialize(circleId);
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
const { onReset } = this.props;
|
||||
onReset();
|
||||
}
|
||||
|
||||
render () {
|
||||
const { accountIds, searchAccountIds, onClear } = this.props;
|
||||
const showSearch = searchAccountIds.size > 0;
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal list-editor'>
|
||||
<EditCircleForm />
|
||||
|
||||
<Search />
|
||||
|
||||
<div className='drawer__pager'>
|
||||
<div className='drawer__inner list-editor__accounts'>
|
||||
{accountIds.map(accountId => <Account key={accountId} accountId={accountId} added />)}
|
||||
</div>
|
||||
|
||||
{showSearch && <div role='button' tabIndex={-1} className='drawer__backdrop' onClick={onClear} />}
|
||||
|
||||
<Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
|
||||
{({ x }) => (
|
||||
<div className='drawer__inner backdrop' style={{ transform: x === 0 ? null : `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}>
|
||||
{searchAccountIds.map(accountId => <Account key={accountId} accountId={accountId} />)}
|
||||
</div>
|
||||
)}
|
||||
</Motion>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(CircleEditor));
|
|
@ -84,10 +84,7 @@ class CircleStatuses extends ImmutablePureComponent {
|
|||
};
|
||||
|
||||
handleEditClick = () => {
|
||||
this.props.dispatch(openModal({
|
||||
modalType: 'CIRCLE_EDITOR',
|
||||
modalProps: { circleId: this.props.params.id },
|
||||
}));
|
||||
this.props.history.push(`/circles/${this.props.params.id}/edit`);
|
||||
};
|
||||
|
||||
handleDeleteClick = () => {
|
||||
|
|
|
@ -37,7 +37,7 @@ const CircleItem: React.FC<{
|
|||
const handleDeleteClick = useCallback(() => {
|
||||
dispatch(
|
||||
openModal({
|
||||
modalType: 'CONFIRM_DELETE_LIST',
|
||||
modalType: 'CONFIRM_DELETE_CIRCLE',
|
||||
modalProps: {
|
||||
circleId: id,
|
||||
},
|
||||
|
|
|
@ -145,7 +145,7 @@ class GettingStarted extends ImmutablePureComponent {
|
|||
<ColumnLink key='bookmark' icon='bookmarks' iconComponent={BookmarksIcon} text={intl.formatMessage(messages.bookmarks)} to='/bookmark_categories' />,
|
||||
<ColumnLink key='favourites' icon='star' iconComponent={StarIcon} text={intl.formatMessage(messages.favourites)} to='/favourites' />,
|
||||
<ColumnLink key='lists' icon='list-ul' iconComponent={ListAltIcon} text={intl.formatMessage(messages.lists)} to='/lists' />,
|
||||
<ColumnLink key='antennas' icon='wifi' iconComponent={AntennaIcon} text={intl.formatMessage(messages.antennas)} to='/antennasw' />,
|
||||
<ColumnLink key='antennas' icon='wifi' iconComponent={AntennaIcon} text={intl.formatMessage(messages.antennas)} to='/antennas' />,
|
||||
<ColumnLink key='circles' icon='user-circle' iconComponent={CirclesIcon} text={intl.formatMessage(messages.circles)} to='/circles' />,
|
||||
);
|
||||
|
||||
|
|
|
@ -115,11 +115,17 @@ class ListTimeline extends PureComponent {
|
|||
dispatch(openModal({ modalType: 'CONFIRM_DELETE_LIST', modalProps: { listId: id, columnId } }));
|
||||
};
|
||||
|
||||
handleEditAntennaClick = (e) => {
|
||||
const id = e.currentTarget.getAttribute('data-id');
|
||||
this.props.history.push(`/antennas/${id}/edit`);
|
||||
};
|
||||
|
||||
render () {
|
||||
const { hasUnread, columnId, multiColumn, list } = this.props;
|
||||
const { id } = this.props.params;
|
||||
const pinned = !!columnId;
|
||||
const title = list ? list.get('title') : id;
|
||||
const antennas = list ? (list.get('antennas') ?? []) : [];
|
||||
|
||||
if (typeof list === 'undefined') {
|
||||
return (
|
||||
|
@ -158,6 +164,22 @@ class ListTimeline extends PureComponent {
|
|||
<Icon id='trash' icon={DeleteIcon} /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' />
|
||||
</button>
|
||||
</section>
|
||||
|
||||
{ antennas.length > 0 && (
|
||||
<section aria-labelledby={`list-${id}-antenna`}>
|
||||
<h3><FormattedMessage id='lists.antennas' defaultMessage='Related antennas:' /></h3>
|
||||
|
||||
<ul className='column-settings__row'>
|
||||
{ antennas.map(antenna => (
|
||||
<li key={antenna.id} className='column-settings__row__antenna'>
|
||||
<button type='button' className='text-btn column-header__setting-btn' data-id={antenna.id} onClick={this.handleEditAntennaClick}>
|
||||
<Icon id='pencil' icon={EditIcon} /> {antenna.title}{antenna.stl && ' [STL]'}{antenna.ltl && ' [LTL]'}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
</ColumnHeader>
|
||||
|
||||
|
|
|
@ -30,7 +30,8 @@ const messages = defineMessages({
|
|||
const ListItem: React.FC<{
|
||||
id: string;
|
||||
title: string;
|
||||
}> = ({ id, title }) => {
|
||||
antennaTitles?: string[];
|
||||
}> = ({ id, title, antennaTitles }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
|
||||
|
@ -58,6 +59,11 @@ const ListItem: React.FC<{
|
|||
<Link to={`/lists/${id}`} className='lists__item__title'>
|
||||
<Icon id='list-ul' icon={ListAltIcon} />
|
||||
<span>{title}</span>
|
||||
{antennaTitles?.map((at) => (
|
||||
<span key={at} className='column-link__badge'>
|
||||
{at.slice(0, 4)}
|
||||
</span>
|
||||
))}
|
||||
</Link>
|
||||
|
||||
<DropdownMenuContainer
|
||||
|
@ -129,7 +135,12 @@ const Lists: React.FC<{
|
|||
bindToDocument={!multiColumn}
|
||||
>
|
||||
{lists.map((list) => (
|
||||
<ListItem key={list.id} id={list.id} title={list.title} />
|
||||
<ListItem
|
||||
key={list.id}
|
||||
id={list.id}
|
||||
title={list.title}
|
||||
antennaTitles={list.antennas.map((a) => a.title)}
|
||||
/>
|
||||
))}
|
||||
</ScrollableList>
|
||||
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import { useCallback } from 'react';
|
||||
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { useHistory } from 'react-router';
|
||||
|
||||
import { deleteAntenna } from 'mastodon/actions/antennas';
|
||||
import { removeColumn } from 'mastodon/actions/columns';
|
||||
import { useAppDispatch } from 'mastodon/store';
|
||||
|
||||
import type { BaseConfirmationModalProps } from './confirmation_modal';
|
||||
import { ConfirmationModal } from './confirmation_modal';
|
||||
|
||||
const messages = defineMessages({
|
||||
deleteAntennaTitle: {
|
||||
id: 'confirmations.delete_antenna.title',
|
||||
defaultMessage: 'Delete antenna?',
|
||||
},
|
||||
deleteAntennaMessage: {
|
||||
id: 'confirmations.delete_antenna.message',
|
||||
defaultMessage: 'Are you sure you want to permanently delete this antenna?',
|
||||
},
|
||||
deleteAntennaConfirm: {
|
||||
id: 'confirmations.delete_antenna.confirm',
|
||||
defaultMessage: 'Delete',
|
||||
},
|
||||
});
|
||||
|
||||
export const ConfirmDeleteAntennaModal: React.FC<
|
||||
{
|
||||
antennaId: string;
|
||||
columnId: string;
|
||||
} & BaseConfirmationModalProps
|
||||
> = ({ antennaId, columnId, onClose }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
const history = useHistory();
|
||||
|
||||
const onConfirm = useCallback(() => {
|
||||
dispatch(deleteAntenna(antennaId));
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
history.push('/antennas');
|
||||
}
|
||||
}, [dispatch, history, columnId, antennaId]);
|
||||
|
||||
return (
|
||||
<ConfirmationModal
|
||||
title={intl.formatMessage(messages.deleteAntennaTitle)}
|
||||
message={intl.formatMessage(messages.deleteAntennaMessage)}
|
||||
confirm={intl.formatMessage(messages.deleteAntennaConfirm)}
|
||||
onConfirm={onConfirm}
|
||||
onClose={onClose}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,59 @@
|
|||
import { useCallback } from 'react';
|
||||
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { useHistory } from 'react-router';
|
||||
|
||||
import { deleteBookmarkCategory } from 'mastodon/actions/bookmark_categories';
|
||||
import { removeColumn } from 'mastodon/actions/columns';
|
||||
import { useAppDispatch } from 'mastodon/store';
|
||||
|
||||
import type { BaseConfirmationModalProps } from './confirmation_modal';
|
||||
import { ConfirmationModal } from './confirmation_modal';
|
||||
|
||||
const messages = defineMessages({
|
||||
deleteBookmarkCategoryTitle: {
|
||||
id: 'confirmations.delete_bookmark_category.title',
|
||||
defaultMessage: 'Delete category?',
|
||||
},
|
||||
deleteBookmarkCategoryMessage: {
|
||||
id: 'confirmations.delete_bookmark_category.message',
|
||||
defaultMessage:
|
||||
'Are you sure you want to permanently delete this category?',
|
||||
},
|
||||
deleteBookmarkCategoryConfirm: {
|
||||
id: 'confirmations.delete_bookmark_category.confirm',
|
||||
defaultMessage: 'Delete',
|
||||
},
|
||||
});
|
||||
|
||||
export const ConfirmDeleteBookmarkCategoryModal: React.FC<
|
||||
{
|
||||
bookmark_categoryId: string;
|
||||
columnId: string;
|
||||
} & BaseConfirmationModalProps
|
||||
> = ({ bookmark_categoryId, columnId, onClose }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
const history = useHistory();
|
||||
|
||||
const onConfirm = useCallback(() => {
|
||||
dispatch(deleteBookmarkCategory(bookmark_categoryId));
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
history.push('/bookmark_categorys');
|
||||
}
|
||||
}, [dispatch, history, columnId, bookmark_categoryId]);
|
||||
|
||||
return (
|
||||
<ConfirmationModal
|
||||
title={intl.formatMessage(messages.deleteBookmarkCategoryTitle)}
|
||||
message={intl.formatMessage(messages.deleteBookmarkCategoryMessage)}
|
||||
confirm={intl.formatMessage(messages.deleteBookmarkCategoryConfirm)}
|
||||
onConfirm={onConfirm}
|
||||
onClose={onClose}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,58 @@
|
|||
import { useCallback } from 'react';
|
||||
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { useHistory } from 'react-router';
|
||||
|
||||
import { deleteCircle } from 'mastodon/actions/circles';
|
||||
import { removeColumn } from 'mastodon/actions/columns';
|
||||
import { useAppDispatch } from 'mastodon/store';
|
||||
|
||||
import type { BaseConfirmationModalProps } from './confirmation_modal';
|
||||
import { ConfirmationModal } from './confirmation_modal';
|
||||
|
||||
const messages = defineMessages({
|
||||
deleteCircleTitle: {
|
||||
id: 'confirmations.delete_circle.title',
|
||||
defaultMessage: 'Delete circle?',
|
||||
},
|
||||
deleteCircleMessage: {
|
||||
id: 'confirmations.delete_circle.message',
|
||||
defaultMessage: 'Are you sure you want to permanently delete this circle?',
|
||||
},
|
||||
deleteCircleConfirm: {
|
||||
id: 'confirmations.delete_circle.confirm',
|
||||
defaultMessage: 'Delete',
|
||||
},
|
||||
});
|
||||
|
||||
export const ConfirmDeleteCircleModal: React.FC<
|
||||
{
|
||||
circleId: string;
|
||||
columnId: string;
|
||||
} & BaseConfirmationModalProps
|
||||
> = ({ circleId, columnId, onClose }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
const history = useHistory();
|
||||
|
||||
const onConfirm = useCallback(() => {
|
||||
dispatch(deleteCircle(circleId));
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
history.push('/circles');
|
||||
}
|
||||
}, [dispatch, history, columnId, circleId]);
|
||||
|
||||
return (
|
||||
<ConfirmationModal
|
||||
title={intl.formatMessage(messages.deleteCircleTitle)}
|
||||
message={intl.formatMessage(messages.deleteCircleMessage)}
|
||||
confirm={intl.formatMessage(messages.deleteCircleConfirm)}
|
||||
onConfirm={onConfirm}
|
||||
onClose={onClose}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -1,6 +1,9 @@
|
|||
export { ConfirmationModal } from './confirmation_modal';
|
||||
export { ConfirmDeleteStatusModal } from './delete_status';
|
||||
export { ConfirmDeleteListModal } from './delete_list';
|
||||
export { ConfirmDeleteAntennaModal } from './delete_antenna';
|
||||
export { ConfirmDeleteCircleModal } from './delete_circle';
|
||||
export { ConfirmDeleteBookmarkCategoryModal } from './delete_bookmark_category';
|
||||
export { ConfirmReplyModal } from './reply';
|
||||
export { ConfirmEditStatusModal } from './edit_status';
|
||||
export { ConfirmUnfollowModal } from './unfollow';
|
||||
|
|
|
@ -50,7 +50,7 @@ export const ListPanel = () => {
|
|||
<ColumnLink icon='list-ul' key={list.get('id')} iconComponent={ListAltIcon} activeIconComponent={ListAltActiveIcon} text={list.get('title')} to={`/lists/${list.get('id')}`} transparent />
|
||||
))}
|
||||
{antennas && antennas.map(antenna => (
|
||||
<ColumnLink icon='wifi' key={antenna.get('id')} iconComponent={AntennaIcon} activeIconComponent={AntennaIcon} text={antenna.get('title')} to={`/antennast/${antenna.get('id')}`} transparent />
|
||||
<ColumnLink icon='wifi' key={antenna.get('id')} iconComponent={AntennaIcon} activeIconComponent={AntennaIcon} text={antenna.get('title')} to={`/antennas/${antenna.get('id')}`} transparent />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -34,6 +34,9 @@ import {
|
|||
ConfirmationModal,
|
||||
ConfirmDeleteStatusModal,
|
||||
ConfirmDeleteListModal,
|
||||
ConfirmDeleteAntennaModal,
|
||||
ConfirmDeleteCircleModal,
|
||||
ConfirmDeleteBookmarkCategoryModal,
|
||||
ConfirmReplyModal,
|
||||
ConfirmEditStatusModal,
|
||||
ConfirmUnfollowModal,
|
||||
|
@ -55,6 +58,9 @@ export const MODAL_COMPONENTS = {
|
|||
'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }),
|
||||
'CONFIRM_DELETE_STATUS': () => Promise.resolve({ default: ConfirmDeleteStatusModal }),
|
||||
'CONFIRM_DELETE_LIST': () => Promise.resolve({ default: ConfirmDeleteListModal }),
|
||||
'CONFIRM_DELETE_ANTENNA': () => Promise.resolve({ default: ConfirmDeleteAntennaModal }),
|
||||
'CONFIRM_DELETE_CIRCLE': () => Promise.resolve({ default: ConfirmDeleteCircleModal }),
|
||||
'CONFIRM_DELETE_BOOKMARK_CATEGORY': () => Promise.resolve({ default: ConfirmDeleteBookmarkCategoryModal }),
|
||||
'CONFIRM_REPLY': () => Promise.resolve({ default: ConfirmReplyModal }),
|
||||
'CONFIRM_EDIT_STATUS': () => Promise.resolve({ default: ConfirmEditStatusModal }),
|
||||
'CONFIRM_UNFOLLOW': () => Promise.resolve({ default: ConfirmUnfollowModal }),
|
||||
|
|
|
@ -122,7 +122,7 @@ class NavigationPanel extends Component {
|
|||
};
|
||||
|
||||
isAntennasActive = (match, location) => {
|
||||
return (match || location.pathname.startsWith('/antennast'));
|
||||
return (match || location.pathname.startsWith('/antennas'));
|
||||
};
|
||||
|
||||
render () {
|
||||
|
@ -197,7 +197,7 @@ class NavigationPanel extends Component {
|
|||
{signedIn && (
|
||||
<>
|
||||
<ColumnLink transparent to='/lists' icon='list-ul' iconComponent={ListAltIcon} activeIconComponent={ListAltActiveIcon} text={intl.formatMessage(messages.lists)} />
|
||||
<ColumnLink transparent to='/antennasw' icon='wifi' iconComponent={AntennaIcon} text={intl.formatMessage(messages.antennas)} isActive={this.isAntennasActive} />
|
||||
<ColumnLink transparent to='/antennas' icon='wifi' iconComponent={AntennaIcon} text={intl.formatMessage(messages.antennas)} isActive={this.isAntennasActive} />
|
||||
<ColumnLink transparent to='/circles' icon='user-circle' iconComponent={CirclesIcon} text={intl.formatMessage(messages.circles)} />
|
||||
<FollowRequestsLink />
|
||||
<ColumnLink transparent to='/conversations' icon='at' iconComponent={AlternateEmailIcon} text={intl.formatMessage(messages.direct)} />
|
||||
|
|
|
@ -80,7 +80,6 @@ import {
|
|||
PrivacyPolicy,
|
||||
CommunityTimeline,
|
||||
AntennaEdit,
|
||||
AntennaExcludeMembers,
|
||||
AntennaMembers,
|
||||
CircleEdit,
|
||||
CircleMembers,
|
||||
|
@ -235,9 +234,9 @@ class SwitchingColumnsArea extends PureComponent {
|
|||
<WrappedRoute path='/antennas/new' component={AntennaEdit} content={children} />
|
||||
<WrappedRoute path='/antennas/:id/edit' component={AntennaEdit} content={children} />
|
||||
<WrappedRoute path='/antennas/:id/members' component={AntennaMembers} content={children} />
|
||||
<WrappedRoute path='/antennas/:id/exclude_members' component={AntennaExcludeMembers} content={children} />
|
||||
<WrappedRoute path='/antennasw/:id' component={AntennaSetting} content={children} />
|
||||
<WrappedRoute path='/antennast/:id' component={AntennaTimeline} content={children} />
|
||||
<WrappedRoute path='/antennas/:id/exclude_members' component={AntennaMembers} componentParams={{ isExclude: true }} content={children} />
|
||||
<WrappedRoute path='/antennas/:id/filtering' component={AntennaSetting} content={children} />
|
||||
<WrappedRoute path='/antennas/:id' component={AntennaTimeline} content={children} />
|
||||
<WrappedRoute path='/circles/new' component={CircleEdit} content={children} />
|
||||
<WrappedRoute path='/circles/:id/edit' component={CircleEdit} content={children} />
|
||||
<WrappedRoute path='/circles/:id/members' component={CircleMembers} content={children} />
|
||||
|
@ -289,7 +288,7 @@ class SwitchingColumnsArea extends PureComponent {
|
|||
<WrappedRoute path='/followed_tags' component={FollowedTags} content={children} />
|
||||
<WrappedRoute path='/mutes' component={Mutes} content={children} />
|
||||
<WrappedRoute path='/lists' component={Lists} content={children} />
|
||||
<WrappedRoute path='/antennasw' component={Antennas} content={children} />
|
||||
<WrappedRoute path='/antennas' component={Antennas} content={children} />
|
||||
<WrappedRoute path='/circles' component={Circles} content={children} />
|
||||
<WrappedRoute path='/bookmark_categories' component={BookmarkCategories} content={children} />
|
||||
|
||||
|
|
|
@ -202,22 +202,10 @@ export function AntennaAdder () {
|
|||
return import(/*webpackChunkName: "features/antenna_adder" */'../../antenna_adder');
|
||||
}
|
||||
|
||||
export function AntennaEditor () {
|
||||
return import(/*webpackChunkName: "features/antenna_editor" */'../../antenna_editor');
|
||||
}
|
||||
|
||||
export function CircleAdder () {
|
||||
return import(/*webpackChunkName: "features/circle_adder" */'../../circle_adder');
|
||||
}
|
||||
|
||||
export function CircleEditor () {
|
||||
return import(/*webpackChunkName: "features/circle_editor" */'../../circle_editor');
|
||||
}
|
||||
|
||||
export function AntennaSetting () {
|
||||
return import(/*webpackChunkName: "features/antenna_setting" */'../../antenna_setting');
|
||||
}
|
||||
|
||||
export function Tesseract () {
|
||||
return import(/*webpackChunkName: "tesseract" */'tesseract.js');
|
||||
}
|
||||
|
@ -302,8 +290,8 @@ export function AntennaMembers () {
|
|||
return import(/* webpackChunkName: "features/antennas" */'../../antennas/members');
|
||||
}
|
||||
|
||||
export function AntennaExcludeMembers () {
|
||||
return import(/* webpackChunkName: "features/antennas" */'../../antennas/exclude_members');
|
||||
export function AntennaSetting () {
|
||||
return import(/*webpackChunkName: "features/antennas/filtering" */'../../antennas/filtering');
|
||||
}
|
||||
|
||||
export function CircleEdit () {
|
||||
|
|
|
@ -119,47 +119,61 @@
|
|||
"annual_report.summary.percentile.text": "<topLabel>That puts you in the top</topLabel><percentage></percentage><bottomLabel>of Mastodon users.</bottomLabel>",
|
||||
"annual_report.summary.percentile.we_wont_tell_bernie": "We won't tell Bernie.",
|
||||
"annual_report.summary.thanks": "Thanks for being part of Mastodon!",
|
||||
"antennas.account.add": "Add to antenna",
|
||||
"antennas.account.remove": "Remove from antenna",
|
||||
"antennas.accounts": "{count} accounts",
|
||||
"antennas.add_domain": "Add domain",
|
||||
"antennas.add_domain_placeholder": "New domain",
|
||||
"antennas.add_keyword": "Add keyword",
|
||||
"antennas.add_keyword_placeholder": "New keyword",
|
||||
"antennas.add_member": "Add",
|
||||
"antennas.add_tag": "Add tag",
|
||||
"antennas.add_tag_placeholder": "New tag",
|
||||
"antennas.add_to_antenna": "Add to antenna",
|
||||
"antennas.add_to_antennas": "Add {name} to antennas",
|
||||
"antennas.antenna_accounts": "Antenna accounts",
|
||||
"antennas.antenna_accounts_count": "{count, plural, one {# member} other {# accounts}}",
|
||||
"antennas.antenna_name": "Antenna name",
|
||||
"antennas.create": "Create",
|
||||
"antennas.create_a_antenna_to_organize": "Create a new antenna to organize your Home feed",
|
||||
"antennas.create_antenna": "Create antenna",
|
||||
"antennas.delete": "Delete antenna",
|
||||
"antennas.destination": "Destination",
|
||||
"antennas.destination.home": "Insert to home",
|
||||
"antennas.destination.list": "Insert to list",
|
||||
"antennas.destination.timeline": "Antenna timeline only",
|
||||
"antennas.domains": "{count} domains",
|
||||
"antennas.done": "Done",
|
||||
"antennas.edit": "Edit antenna",
|
||||
"antennas.edit.submit": "Change title",
|
||||
"antennas.edit_accounts": "Edit accounts",
|
||||
"antennas.edit_static": "Edit antenna",
|
||||
"antennas.exclude_accounts": "Exclude accounts",
|
||||
"antennas.exclude_domains": "Exclude domains",
|
||||
"antennas.exclude_keywords": "Exclude keywords",
|
||||
"antennas.exclude_tags": "Exclude tags",
|
||||
"antennas.filter": "Filter",
|
||||
"antennas.filter_items": "Antenna filter settings",
|
||||
"antennas.filter_not": "Filter Not",
|
||||
"antennas.go_timeline": "Go to antenna timeline",
|
||||
"antennas.find_users_to_add": "Find users to add",
|
||||
"antennas.ignore_reblog": "Exclude boosts",
|
||||
"antennas.ignore_reblog_hint": "Boosts will be excluded from antenna detection.",
|
||||
"antennas.in_ltl_mode": "This antenna is in LTL mode.",
|
||||
"antennas.in_stl_mode": "This antenna is in STL mode.",
|
||||
"antennas.insert_feeds": "Insert to feeds",
|
||||
"antennas.insert_home": "Home",
|
||||
"antennas.insert_list": "List",
|
||||
"antennas.keywords": "{count} keywords",
|
||||
"antennas.ltl": "LTL mode",
|
||||
"antennas.media_only": "Media only",
|
||||
"antennas.new.create": "Add antenna",
|
||||
"antennas.new.title_placeholder": "New antenna title",
|
||||
"antennas.not_related_list": "This antenna is not related list. Posts will appear in home timeline. Open edit page to set list.",
|
||||
"antennas.related_list": "This antenna is related to {listTitle}.",
|
||||
"antennas.search": "Search among people you follow",
|
||||
"antennas.media_only_hint": "Only posts with media will be added antenna.",
|
||||
"antennas.mode": "Mode",
|
||||
"antennas.mode.filtering": "Filtering",
|
||||
"antennas.mode.ltl": "Local timeline mode",
|
||||
"antennas.mode.stl": "Social timeline mode",
|
||||
"antennas.new_antenna_name": "New antenna name",
|
||||
"antennas.no_antennas_yet": "No antennas yet.",
|
||||
"antennas.no_members_yet": "No members yet.",
|
||||
"antennas.no_results_found": "No results found.",
|
||||
"antennas.remove_member": "Remove",
|
||||
"antennas.save": "Save",
|
||||
"antennas.search_placeholder": "Search people you follow",
|
||||
"antennas.select.no_options_message": "Empty lists",
|
||||
"antennas.select.placeholder": "Select list",
|
||||
"antennas.select.set_home": "Set home",
|
||||
"antennas.stl": "STL mode",
|
||||
"antennas.subheading": "Your antennas",
|
||||
"antennas.tags": "{count} tags",
|
||||
"antennas.warnings.content_radio": "Simultaneous keyword and tag designation is not recommended.",
|
||||
"antennas.warnings.range_radio": "Simultaneous account and domain designation is not recommended.",
|
||||
|
@ -173,15 +187,17 @@
|
|||
"block_modal.they_will_know": "They can see that they're blocked.",
|
||||
"block_modal.title": "Block user?",
|
||||
"block_modal.you_wont_see_mentions": "You won't see posts that mention them.",
|
||||
"bookmark_categories.all_bookmarks": "All bookmarks",
|
||||
"bookmark_categories.add_to_bookmark_categories": "Add {name} to bookmark_categories",
|
||||
"bookmark_categories.bookmark_category_name": "BookmarkCategory name",
|
||||
"bookmark_categories.create": "Create",
|
||||
"bookmark_categories.create_a_bookmark_category_to_organize": "Create a new bookmark_category to organize your Home feed",
|
||||
"bookmark_categories.create_bookmark_category": "Create bookmark_category",
|
||||
"bookmark_categories.delete": "Delete category",
|
||||
"bookmark_categories.edit": "Edit category",
|
||||
"bookmark_categories.edit.submit": "Change title",
|
||||
"bookmark_categories.new.create": "Add category",
|
||||
"bookmark_categories.new.title_placeholder": "New category title",
|
||||
"bookmark_categories.status.add": "Add to bookmark category",
|
||||
"bookmark_categories.status.remove": "Remove from bookmark category",
|
||||
"bookmark_categories.subheading": "Your categories",
|
||||
"bookmark_categories.new_bookmark_category_name": "New bookmark_category name",
|
||||
"bookmark_categories.no_bookmark_categories_yet": "No bookmark_categories yet.",
|
||||
"bookmark_categories.save": "Save",
|
||||
"boost_modal.combo": "You can press {combo} to skip this next time",
|
||||
"boost_modal.reblog": "Boost post?",
|
||||
"boost_modal.undo_reblog": "Unboost post?",
|
||||
|
@ -197,15 +213,26 @@
|
|||
"bundle_modal_error.close": "Close",
|
||||
"bundle_modal_error.message": "Something went wrong while loading this component.",
|
||||
"bundle_modal_error.retry": "Try again",
|
||||
"circles.account.add": "Add to circle",
|
||||
"circles.account.remove": "Remove from circle",
|
||||
"circles.add_member": "Add",
|
||||
"circles.add_to_circle": "Add to circle",
|
||||
"circles.add_to_circles": "Add {name} to circles",
|
||||
"circles.circle_members": "Circle members",
|
||||
"circles.circle_members_count": "{count, plural, one {# member} other {# members}}",
|
||||
"circles.circle_name": "Circle name",
|
||||
"circles.create": "Create",
|
||||
"circles.create_a_circle_to_organize": "Create a new circle to organize your Home feed",
|
||||
"circles.create_circle": "Create circle",
|
||||
"circles.delete": "Delete circle",
|
||||
"circles.done": "Done",
|
||||
"circles.edit": "Edit circle",
|
||||
"circles.edit.submit": "Change title",
|
||||
"circles.new.create": "Add circle",
|
||||
"circles.new.title_placeholder": "New circle title",
|
||||
"circles.search": "Search among people follow you",
|
||||
"circles.subheading": "Your circles",
|
||||
"circles.find_users_to_add": "Find users to add",
|
||||
"circles.new_circle_name": "New circle name",
|
||||
"circles.no_circles_yet": "No circles yet.",
|
||||
"circles.no_members_yet": "No members yet.",
|
||||
"circles.no_results_found": "No results found.",
|
||||
"circles.remove_member": "Remove",
|
||||
"circles.save": "Save",
|
||||
"circles.search_placeholder": "Search people you follow",
|
||||
"closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.",
|
||||
"closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.",
|
||||
"closed_registrations_modal.description_when_reaching_limit": "New registrations are currently temporarily restricted. Either the maximum number of registrations has been reached for registration. Please contact the administrator for more information or wait until the restriction is lifted.",
|
||||
|
@ -213,17 +240,25 @@
|
|||
"closed_registrations_modal.preamble": "Mastodon is decentralized, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!",
|
||||
"closed_registrations_modal.title": "Signing up on Mastodon",
|
||||
"column.about": "About",
|
||||
"column.antenna_members": "Manage antenna members",
|
||||
"column.antennas": "Antennas",
|
||||
"column.blocks": "Blocked users",
|
||||
"column.bookmark_categories": "Bookmark categories",
|
||||
"column.bookmarks": "Bookmarks",
|
||||
"column.circle_members": "Manage circle members",
|
||||
"column.circles": "Circles",
|
||||
"column.community": "Local timeline",
|
||||
"column.create_antenna": "Create antenna",
|
||||
"column.create_bookmark_category": "Create bookmark_category",
|
||||
"column.create_circle": "Create circle",
|
||||
"column.create_list": "Create list",
|
||||
"column.deep_local": "Deep",
|
||||
"column.direct": "Private mentions",
|
||||
"column.directory": "Browse profiles",
|
||||
"column.domain_blocks": "Blocked domains",
|
||||
"column.edit_antenna": "Edit antenna",
|
||||
"column.edit_bookmark_category": "Edit bookmark_category",
|
||||
"column.edit_circle": "Edit circle",
|
||||
"column.edit_list": "Edit list",
|
||||
"column.emoji_reactions": "Emoji Reactions",
|
||||
"column.favourites": "Favorites",
|
||||
|
@ -286,10 +321,13 @@
|
|||
"confirmations.delete.title": "Delete post?",
|
||||
"confirmations.delete_antenna.confirm": "Delete",
|
||||
"confirmations.delete_antenna.message": "Are you sure you want to permanently delete this antenna?",
|
||||
"confirmations.delete_antenna.title": "Delete antenna?",
|
||||
"confirmations.delete_bookmark_category.confirm": "Delete",
|
||||
"confirmations.delete_bookmark_category.message": "Are you sure you want to permanently delete this category?",
|
||||
"confirmations.delete_bookmark_category.title": "Delete bookmark_category?",
|
||||
"confirmations.delete_circle.confirm": "Delete",
|
||||
"confirmations.delete_circle.message": "Are you sure you want to permanently delete this circle?",
|
||||
"confirmations.delete_circle.title": "Delete circle?",
|
||||
"confirmations.delete_list.confirm": "Delete",
|
||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
||||
"confirmations.delete_list.title": "Delete list?",
|
||||
|
@ -377,12 +415,9 @@
|
|||
"empty_column.account_timeline": "No posts here!",
|
||||
"empty_column.account_unavailable": "Profile unavailable",
|
||||
"empty_column.antenna": "There is nothing in this antenna yet. When members of this list post new statuses, they will appear here.",
|
||||
"empty_column.antennas": "You don't have any antennas yet. When you create one, it will show up here.",
|
||||
"empty_column.blocks": "You haven't blocked any users yet.",
|
||||
"empty_column.bookmark_categories": "You don't have any categories yet. When you create one, it will show up here.",
|
||||
"empty_column.bookmarked_statuses": "You don't have any bookmarked posts yet. When you bookmark one, it will show up here.",
|
||||
"empty_column.circle_statuses": "You don't have any circle posts yet. When you post one as circle, it will show up here.",
|
||||
"empty_column.circles": "You don't have any circles yet. When you create one, it will show up here.",
|
||||
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
|
||||
"empty_column.direct": "You don't have any private mentions yet. When you send or receive one, it will show up here.",
|
||||
"empty_column.domain_blocks": "There are no blocked domains yet.",
|
||||
|
@ -576,7 +611,7 @@
|
|||
"lists.add_member": "Add",
|
||||
"lists.add_to_list": "Add to list",
|
||||
"lists.add_to_lists": "Add {name} to lists",
|
||||
"lists.antennas": "Related antennas",
|
||||
"lists.antennas": "Related antennas:",
|
||||
"lists.create": "Create",
|
||||
"lists.create_a_list_to_organize": "Create a new list to organize your Home feed",
|
||||
"lists.create_list": "Create list",
|
||||
|
@ -594,6 +629,7 @@
|
|||
"lists.no_members_yet": "No members yet.",
|
||||
"lists.no_results_found": "No results found.",
|
||||
"lists.notify": "Notify these posts",
|
||||
"lists.notify_hint": "Notify when new post is added.",
|
||||
"lists.remove_member": "Remove",
|
||||
"lists.replies_policy.followed": "Any followed user",
|
||||
"lists.replies_policy.list": "Members of the list",
|
||||
|
@ -601,7 +637,6 @@
|
|||
"lists.save": "Save",
|
||||
"lists.search_placeholder": "Search people you follow",
|
||||
"lists.show_replies_to": "Include replies from list members to",
|
||||
"lists.with_antenna": "Antenna",
|
||||
"load_pending": "{count, plural, one {# new item} other {# new items}}",
|
||||
"loading_indicator.label": "Loading…",
|
||||
"media_gallery.hide": "Hide",
|
||||
|
|
|
@ -117,33 +117,50 @@
|
|||
"annual_report.summary.percentile.text": "<topLabel>それにより、あなたは上位に位置しています。</topLabel><percentage></percentage><bottomLabel>Mastodonユーザーの中で。</bottomLabel>",
|
||||
"annual_report.summary.percentile.we_wont_tell_bernie": "バー二ーには秘密にしておくよ。",
|
||||
"annual_report.summary.thanks": "Mastodonの一員になってくれてありがとう!",
|
||||
"antennas.account.add": "アンテナに追加",
|
||||
"antennas.account.remove": "アンテナから外す",
|
||||
"antennas.accounts": "{count} のアカウント",
|
||||
"antennas.add_domain": "新規ドメイン",
|
||||
"antennas.add_domain_placeholder": "新しいドメイン名",
|
||||
"antennas.add_keyword": "新規キーワード",
|
||||
"antennas.add_keyword_placeholder": "新しいキーワード",
|
||||
"antennas.add_member": "追加",
|
||||
"antennas.add_tag": "新規タグ",
|
||||
"antennas.add_tag_placeholder": "新しいタグ",
|
||||
"antennas.add_to_antenna": "アンテナに追加",
|
||||
"antennas.add_to_antennas": "{name}をアンテナに追加",
|
||||
"antennas.antenna_accounts": "アンテナのアカウント",
|
||||
"antennas.antenna_accounts_count": "{count}のアカウント",
|
||||
"antennas.antenna_name": "アンテナの名前",
|
||||
"antennas.create": "新規作成",
|
||||
"antennas.create_a_antenna_to_organize": "興味ある話題を検出するためにアンテナを作成する",
|
||||
"antennas.create_antenna": "アンテナを作成",
|
||||
"antennas.delete": "アンテナを削除",
|
||||
"antennas.destination": "検出された投稿の配置先",
|
||||
"antennas.destination.home": "ホームに追加",
|
||||
"antennas.destination.list": "リストに追加",
|
||||
"antennas.destination.timeline": "アンテナタイムラインのみ",
|
||||
"antennas.domains": "{count} のドメイン",
|
||||
"antennas.done": "保存",
|
||||
"antennas.edit": "アンテナを編集",
|
||||
"antennas.edit.submit": "タイトルを変更",
|
||||
"antennas.edit_static": "旧編集画面に移動",
|
||||
"antennas.edit_accounts": "アカウントを編集",
|
||||
"antennas.exclude_accounts": "除外するアカウント",
|
||||
"antennas.exclude_domains": "除外するドメイン",
|
||||
"antennas.exclude_keywords": "除外するキーワード",
|
||||
"antennas.exclude_tags": "除外するタグ",
|
||||
"antennas.filter": "絞り込み条件",
|
||||
"antennas.filter_items": "絞り込み条件を設定する",
|
||||
"antennas.filter_not": "絞り込み条件の例外",
|
||||
"antennas.go_timeline": "タイムラインを見る",
|
||||
"antennas.ignore_reblog": "ブーストを除外",
|
||||
"antennas.ignore_reblog_hint": "ブーストはアンテナの検出対象から外れます",
|
||||
"antennas.in_ltl_mode": "LTLモードが有効になっています",
|
||||
"antennas.in_stl_mode": "STLモードが有効になっています",
|
||||
"antennas.insert_feeds": "リストまたはホームに挿入",
|
||||
"antennas.insert_home": "ホーム",
|
||||
"antennas.insert_list": "リスト",
|
||||
"antennas.keywords": "{count} のキーワード",
|
||||
"antennas.media_only": "メディアのみ",
|
||||
"antennas.media_only_hint": "メディアの添付された投稿のみがアンテナに検出されます",
|
||||
"antennas.mode": "動作モード",
|
||||
"antennas.mode.filtering": "フィルタリング",
|
||||
"antennas.mode.ltl": "ローカルタイムラインモード",
|
||||
"antennas.mode.stl": "ソーシャルタイムラインモード",
|
||||
"antennas.new.create": "アンテナを作成",
|
||||
"antennas.new.title_placeholder": "新規アンテナ名",
|
||||
"antennas.not_related_list": "このアンテナはどのリストにも関連付けられていません。",
|
||||
|
@ -274,15 +291,18 @@
|
|||
"confirmations.delete.confirm": "削除",
|
||||
"confirmations.delete.message": "本当に削除しますか?",
|
||||
"confirmations.delete.title": "投稿を削除しようとしています",
|
||||
"confirmations.delete_antenna.confirm": "削除",
|
||||
"confirmations.delete_antenna.message": "本当にこのアンテナを完全に削除しますか?",
|
||||
"confirmations.delete_antenna.title": "アンテナを削除しようとしています",
|
||||
"confirmations.delete_bookmark_category.confirm": "削除",
|
||||
"confirmations.delete_bookmark_category.message": "本当にこの分類を完全に削除しますか?各投稿からこの分類は削除されますが、ブックマークは解除されません。",
|
||||
"confirmations.delete_bookmark_category.title": "分類を削除しようとしています",
|
||||
"confirmations.delete_circle.confirm": "削除",
|
||||
"confirmations.delete_circle.message": "本当にこのサークルを完全に削除しますか?",
|
||||
"confirmations.delete_circle.title": "サークルを削除しようとしています",
|
||||
"confirmations.delete_list.confirm": "削除",
|
||||
"confirmations.delete_list.message": "本当にこのリストを完全に削除しますか?",
|
||||
"confirmations.delete_list.title": "リストを削除しようとしています",
|
||||
"confirmations.delete_antenna.confirm": "削除",
|
||||
"confirmations.delete_antenna.message": "本当にこのアンテナを完全に削除しますか?",
|
||||
"confirmations.discard_edit_media.confirm": "破棄",
|
||||
"confirmations.discard_edit_media.message": "メディアの説明またはプレビューに保存されていない変更があります。それでも破棄しますか?",
|
||||
"confirmations.edit.confirm": "編集",
|
||||
|
|
|
@ -12,6 +12,7 @@ const ListFactory = Record<ListShape>({
|
|||
exclusive: false,
|
||||
replies_policy: 'list',
|
||||
notify: false,
|
||||
antennas: [],
|
||||
});
|
||||
|
||||
export function createList(attributes: Partial<ListShape>) {
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
|
||||
import {
|
||||
ANTENNA_ADDER_RESET,
|
||||
ANTENNA_ADDER_SETUP,
|
||||
ANTENNA_ADDER_ANTENNAS_FETCH_REQUEST,
|
||||
ANTENNA_ADDER_ANTENNAS_FETCH_SUCCESS,
|
||||
ANTENNA_ADDER_ANTENNAS_FETCH_FAIL,
|
||||
ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_REQUEST,
|
||||
ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_SUCCESS,
|
||||
ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_FAIL,
|
||||
ANTENNA_EDITOR_ADD_SUCCESS,
|
||||
ANTENNA_EDITOR_REMOVE_SUCCESS,
|
||||
ANTENNA_EDITOR_ADD_EXCLUDE_SUCCESS,
|
||||
ANTENNA_EDITOR_REMOVE_EXCLUDE_SUCCESS,
|
||||
} from '../actions/antennas';
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
accountId: null,
|
||||
|
||||
antennas: ImmutableMap({
|
||||
items: ImmutableList(),
|
||||
loaded: false,
|
||||
isLoading: false,
|
||||
}),
|
||||
});
|
||||
|
||||
export default function antennaAdderReducer(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case ANTENNA_ADDER_RESET:
|
||||
return initialState;
|
||||
case ANTENNA_ADDER_SETUP:
|
||||
return state.withMutations(map => {
|
||||
map.set('accountId', action.account.get('id'));
|
||||
});
|
||||
case ANTENNA_ADDER_ANTENNAS_FETCH_REQUEST:
|
||||
case ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_REQUEST:
|
||||
return state.setIn(['antennas', 'isLoading'], true);
|
||||
case ANTENNA_ADDER_ANTENNAS_FETCH_FAIL:
|
||||
case ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_FAIL:
|
||||
return state.setIn(['antennas', 'isLoading'], false);
|
||||
case ANTENNA_ADDER_ANTENNAS_FETCH_SUCCESS:
|
||||
case ANTENNA_ADDER_EXCLUDE_ANTENNAS_FETCH_SUCCESS:
|
||||
return state.update('antennas', antennas => antennas.withMutations(map => {
|
||||
map.set('isLoading', false);
|
||||
map.set('loaded', true);
|
||||
map.set('items', ImmutableList(action.antennas.map(item => item.id)));
|
||||
}));
|
||||
case ANTENNA_EDITOR_ADD_SUCCESS:
|
||||
case ANTENNA_EDITOR_ADD_EXCLUDE_SUCCESS:
|
||||
return state.updateIn(['antennas', 'items'], antenna => antenna.unshift(action.antennaId));
|
||||
case ANTENNA_EDITOR_REMOVE_SUCCESS:
|
||||
case ANTENNA_EDITOR_REMOVE_EXCLUDE_SUCCESS:
|
||||
return state.updateIn(['antennas', 'items'], antenna => antenna.filterNot(item => item === action.antennaId));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
|
||||
import {
|
||||
ANTENNA_CREATE_REQUEST,
|
||||
ANTENNA_CREATE_FAIL,
|
||||
ANTENNA_CREATE_SUCCESS,
|
||||
ANTENNA_UPDATE_REQUEST,
|
||||
ANTENNA_UPDATE_FAIL,
|
||||
ANTENNA_UPDATE_SUCCESS,
|
||||
ANTENNA_EDITOR_RESET,
|
||||
ANTENNA_EDITOR_SETUP,
|
||||
ANTENNA_EDITOR_TITLE_CHANGE,
|
||||
ANTENNA_ACCOUNTS_FETCH_REQUEST,
|
||||
ANTENNA_ACCOUNTS_FETCH_SUCCESS,
|
||||
ANTENNA_ACCOUNTS_FETCH_FAIL,
|
||||
ANTENNA_EXCLUDE_ACCOUNTS_FETCH_REQUEST,
|
||||
ANTENNA_EXCLUDE_ACCOUNTS_FETCH_SUCCESS,
|
||||
ANTENNA_EXCLUDE_ACCOUNTS_FETCH_FAIL,
|
||||
ANTENNA_EDITOR_SUGGESTIONS_READY,
|
||||
ANTENNA_EDITOR_SUGGESTIONS_CLEAR,
|
||||
ANTENNA_EDITOR_SUGGESTIONS_CHANGE,
|
||||
ANTENNA_EDITOR_ADD_SUCCESS,
|
||||
ANTENNA_EDITOR_REMOVE_SUCCESS,
|
||||
ANTENNA_EDITOR_ADD_EXCLUDE_SUCCESS,
|
||||
ANTENNA_EDITOR_REMOVE_EXCLUDE_SUCCESS,
|
||||
} from '../actions/antennas';
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
antennaId: null,
|
||||
isSubmitting: false,
|
||||
isChanged: false,
|
||||
title: '',
|
||||
accountsCount: 0,
|
||||
|
||||
accounts: ImmutableMap({
|
||||
items: ImmutableList(),
|
||||
loaded: false,
|
||||
isLoading: false,
|
||||
}),
|
||||
|
||||
suggestions: ImmutableMap({
|
||||
value: '',
|
||||
items: ImmutableList(),
|
||||
}),
|
||||
});
|
||||
|
||||
export default function antennaEditorReducer(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case ANTENNA_EDITOR_RESET:
|
||||
return initialState;
|
||||
case ANTENNA_EDITOR_SETUP:
|
||||
return state.withMutations(map => {
|
||||
map.set('antennaId', action.antenna.get('id'));
|
||||
map.set('title', action.antenna.get('title'));
|
||||
map.set('accountsCount', action.antenna.get('accounts_count'));
|
||||
map.set('isSubmitting', false);
|
||||
});
|
||||
case ANTENNA_EDITOR_TITLE_CHANGE:
|
||||
return state.withMutations(map => {
|
||||
map.set('title', action.value);
|
||||
map.set('isChanged', true);
|
||||
});
|
||||
case ANTENNA_CREATE_REQUEST:
|
||||
case ANTENNA_UPDATE_REQUEST:
|
||||
return state.withMutations(map => {
|
||||
map.set('isSubmitting', true);
|
||||
map.set('isChanged', false);
|
||||
});
|
||||
case ANTENNA_CREATE_FAIL:
|
||||
case ANTENNA_UPDATE_FAIL:
|
||||
return state.set('isSubmitting', false);
|
||||
case ANTENNA_CREATE_SUCCESS:
|
||||
case ANTENNA_UPDATE_SUCCESS:
|
||||
return state.withMutations(map => {
|
||||
map.set('isSubmitting', false);
|
||||
map.set('antennaId', action.antenna.id);
|
||||
});
|
||||
case ANTENNA_ACCOUNTS_FETCH_REQUEST:
|
||||
return state.setIn(['accounts', 'isLoading'], true);
|
||||
case ANTENNA_ACCOUNTS_FETCH_FAIL:
|
||||
return state.setIn(['accounts', 'isLoading'], false);
|
||||
case ANTENNA_ACCOUNTS_FETCH_SUCCESS:
|
||||
return state.update('accounts', accounts => accounts.withMutations(map => {
|
||||
map.set('isLoading', false);
|
||||
map.set('loaded', true);
|
||||
map.set('items', ImmutableList(action.accounts.map(item => item.id)));
|
||||
}));
|
||||
case ANTENNA_EXCLUDE_ACCOUNTS_FETCH_REQUEST:
|
||||
return state.setIn(['accounts', 'isLoading'], true);
|
||||
case ANTENNA_EXCLUDE_ACCOUNTS_FETCH_FAIL:
|
||||
return state.setIn(['accounts', 'isLoading'], false);
|
||||
case ANTENNA_EXCLUDE_ACCOUNTS_FETCH_SUCCESS:
|
||||
return state.update('accounts', accounts => accounts.withMutations(map => {
|
||||
map.set('isLoading', false);
|
||||
map.set('loaded', true);
|
||||
map.set('items', ImmutableList(action.accounts.map(item => item.id)));
|
||||
}));
|
||||
case ANTENNA_EDITOR_SUGGESTIONS_CHANGE:
|
||||
return state.setIn(['suggestions', 'value'], action.value);
|
||||
case ANTENNA_EDITOR_SUGGESTIONS_READY:
|
||||
return state.setIn(['suggestions', 'items'], ImmutableList(action.accounts.map(item => item.id)));
|
||||
case ANTENNA_EDITOR_SUGGESTIONS_CLEAR:
|
||||
return state.update('suggestions', suggestions => suggestions.withMutations(map => {
|
||||
map.set('items', ImmutableList());
|
||||
map.set('value', '');
|
||||
}));
|
||||
case ANTENNA_EDITOR_ADD_SUCCESS:
|
||||
case ANTENNA_EDITOR_ADD_EXCLUDE_SUCCESS:
|
||||
return state.updateIn(['accounts', 'items'], antenna => antenna.unshift(action.accountId));
|
||||
case ANTENNA_EDITOR_REMOVE_SUCCESS:
|
||||
case ANTENNA_EDITOR_REMOVE_EXCLUDE_SUCCESS:
|
||||
return state.updateIn(['accounts', 'items'], antenna => antenna.filterNot(item => item === action.accountId));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -11,9 +11,6 @@ import {
|
|||
ANTENNA_FETCH_FAIL,
|
||||
ANTENNAS_FETCH_SUCCESS,
|
||||
ANTENNA_DELETE_SUCCESS,
|
||||
ANTENNA_EDITOR_FETCH_DOMAINS_SUCCESS,
|
||||
//ANTENNA_EDITOR_FETCH_KEYWORDS_SUCCESS,
|
||||
//ANTENNA_EDITOR_FETCH_TAGS_SUCCESS,
|
||||
} from '../actions/antennas';
|
||||
|
||||
const initialState = ImmutableMap<string, Antenna | null>();
|
||||
|
@ -48,16 +45,6 @@ export const antennasReducer: Reducer<State> = (
|
|||
case ANTENNA_DELETE_SUCCESS:
|
||||
case ANTENNA_FETCH_FAIL:
|
||||
return state.set(action.id as string, null);
|
||||
case ANTENNA_EDITOR_FETCH_DOMAINS_SUCCESS:
|
||||
return state
|
||||
.setIn(
|
||||
['domains', action.id],
|
||||
(action.domains as { domains: string[] }).domains,
|
||||
)
|
||||
.setIn(
|
||||
['exclude_domains', action.id],
|
||||
(action.domains as { exclude_domains: string[] }).exclude_domains,
|
||||
);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
|
||||
import {
|
||||
CIRCLE_ADDER_RESET,
|
||||
CIRCLE_ADDER_SETUP,
|
||||
CIRCLE_ADDER_CIRCLES_FETCH_REQUEST,
|
||||
CIRCLE_ADDER_CIRCLES_FETCH_SUCCESS,
|
||||
CIRCLE_ADDER_CIRCLES_FETCH_FAIL,
|
||||
CIRCLE_EDITOR_ADD_SUCCESS,
|
||||
CIRCLE_EDITOR_REMOVE_SUCCESS,
|
||||
} from '../actions/circles';
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
accountId: null,
|
||||
|
||||
circles: ImmutableMap({
|
||||
items: ImmutableList(),
|
||||
loaded: false,
|
||||
isLoading: false,
|
||||
}),
|
||||
});
|
||||
|
||||
export default function circleAdderReducer(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case CIRCLE_ADDER_RESET:
|
||||
return initialState;
|
||||
case CIRCLE_ADDER_SETUP:
|
||||
return state.withMutations(map => {
|
||||
map.set('accountId', action.account.get('id'));
|
||||
});
|
||||
case CIRCLE_ADDER_CIRCLES_FETCH_REQUEST:
|
||||
return state.setIn(['circles', 'isLoading'], true);
|
||||
case CIRCLE_ADDER_CIRCLES_FETCH_FAIL:
|
||||
return state.setIn(['circles', 'isLoading'], false);
|
||||
case CIRCLE_ADDER_CIRCLES_FETCH_SUCCESS:
|
||||
return state.update('circles', circles => circles.withMutations(map => {
|
||||
map.set('isLoading', false);
|
||||
map.set('loaded', true);
|
||||
map.set('items', ImmutableList(action.circles.map(item => item.id)));
|
||||
}));
|
||||
case CIRCLE_EDITOR_ADD_SUCCESS:
|
||||
return state.updateIn(['circles', 'items'], circle => circle.unshift(action.circleId));
|
||||
case CIRCLE_EDITOR_REMOVE_SUCCESS:
|
||||
return state.updateIn(['circles', 'items'], circle => circle.filterNot(item => item === action.circleId));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
|
||||
import {
|
||||
CIRCLE_CREATE_REQUEST,
|
||||
CIRCLE_CREATE_FAIL,
|
||||
CIRCLE_CREATE_SUCCESS,
|
||||
CIRCLE_UPDATE_REQUEST,
|
||||
CIRCLE_UPDATE_FAIL,
|
||||
CIRCLE_UPDATE_SUCCESS,
|
||||
CIRCLE_EDITOR_RESET,
|
||||
CIRCLE_EDITOR_SETUP,
|
||||
CIRCLE_EDITOR_TITLE_CHANGE,
|
||||
CIRCLE_ACCOUNTS_FETCH_REQUEST,
|
||||
CIRCLE_ACCOUNTS_FETCH_SUCCESS,
|
||||
CIRCLE_ACCOUNTS_FETCH_FAIL,
|
||||
CIRCLE_EDITOR_SUGGESTIONS_READY,
|
||||
CIRCLE_EDITOR_SUGGESTIONS_CLEAR,
|
||||
CIRCLE_EDITOR_SUGGESTIONS_CHANGE,
|
||||
CIRCLE_EDITOR_ADD_SUCCESS,
|
||||
CIRCLE_EDITOR_REMOVE_SUCCESS,
|
||||
} from '../actions/circles';
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
circleId: null,
|
||||
isSubmitting: false,
|
||||
isChanged: false,
|
||||
title: '',
|
||||
isExclusive: false,
|
||||
|
||||
accounts: ImmutableMap({
|
||||
items: ImmutableList(),
|
||||
loaded: false,
|
||||
isLoading: false,
|
||||
}),
|
||||
|
||||
suggestions: ImmutableMap({
|
||||
value: '',
|
||||
items: ImmutableList(),
|
||||
}),
|
||||
});
|
||||
|
||||
export default function circleEditorReducer(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case CIRCLE_EDITOR_RESET:
|
||||
return initialState;
|
||||
case CIRCLE_EDITOR_SETUP:
|
||||
return state.withMutations(map => {
|
||||
map.set('circleId', action.circle.get('id'));
|
||||
map.set('title', action.circle.get('title'));
|
||||
map.set('isExclusive', action.circle.get('is_exclusive'));
|
||||
map.set('isSubmitting', false);
|
||||
});
|
||||
case CIRCLE_EDITOR_TITLE_CHANGE:
|
||||
return state.withMutations(map => {
|
||||
map.set('title', action.value);
|
||||
map.set('isChanged', true);
|
||||
});
|
||||
case CIRCLE_CREATE_REQUEST:
|
||||
case CIRCLE_UPDATE_REQUEST:
|
||||
return state.withMutations(map => {
|
||||
map.set('isSubmitting', true);
|
||||
map.set('isChanged', false);
|
||||
});
|
||||
case CIRCLE_CREATE_FAIL:
|
||||
case CIRCLE_UPDATE_FAIL:
|
||||
return state.set('isSubmitting', false);
|
||||
case CIRCLE_CREATE_SUCCESS:
|
||||
case CIRCLE_UPDATE_SUCCESS:
|
||||
return state.withMutations(map => {
|
||||
map.set('isSubmitting', false);
|
||||
map.set('circleId', action.circle.id);
|
||||
});
|
||||
case CIRCLE_ACCOUNTS_FETCH_REQUEST:
|
||||
return state.setIn(['accounts', 'isLoading'], true);
|
||||
case CIRCLE_ACCOUNTS_FETCH_FAIL:
|
||||
return state.setIn(['accounts', 'isLoading'], false);
|
||||
case CIRCLE_ACCOUNTS_FETCH_SUCCESS:
|
||||
return state.update('accounts', accounts => accounts.withMutations(map => {
|
||||
map.set('isLoading', false);
|
||||
map.set('loaded', true);
|
||||
map.set('items', ImmutableList(action.accounts.map(item => item.id)));
|
||||
}));
|
||||
case CIRCLE_EDITOR_SUGGESTIONS_CHANGE:
|
||||
return state.setIn(['suggestions', 'value'], action.value);
|
||||
case CIRCLE_EDITOR_SUGGESTIONS_READY:
|
||||
return state.setIn(['suggestions', 'items'], ImmutableList(action.accounts.map(item => item.id)));
|
||||
case CIRCLE_EDITOR_SUGGESTIONS_CLEAR:
|
||||
return state.update('suggestions', suggestions => suggestions.withMutations(map => {
|
||||
map.set('items', ImmutableList());
|
||||
map.set('value', '');
|
||||
}));
|
||||
case CIRCLE_EDITOR_ADD_SUCCESS:
|
||||
return state.updateIn(['accounts', 'items'], circle => circle.unshift(action.accountId));
|
||||
case CIRCLE_EDITOR_REMOVE_SUCCESS:
|
||||
return state.updateIn(['accounts', 'items'], circle => circle.filterNot(item => item === action.accountId));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -8386,11 +8386,14 @@ noscript {
|
|||
|
||||
i.fa {
|
||||
color: $darker-text-color;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.label {
|
||||
flex: 1;
|
||||
margin: 0 8px;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
.filters-list__item{ class: [(antenna.expired? || !antenna.enabled_config?) && 'expired'] }
|
||||
= link_to edit_antenna_path(antenna), class: 'filters-list__item__title' do
|
||||
= antenna.title
|
||||
|
||||
- if !antenna.enabled_config? && !antenna.stl
|
||||
.expiration{ title: t('antennas.index.disabled') }
|
||||
= t('antennas.index.disabled')
|
||||
- elsif antenna.expires?
|
||||
.expiration{ title: t('antennas.index.expires_on', date: l(antenna.expires_at)) }
|
||||
- if antenna.expired?
|
||||
= t('invites.expired')
|
||||
- else
|
||||
= t('antennas.index.expires_in', distance: distance_of_time_in_words_to_now(antenna.expires_at))
|
||||
|
||||
.listname
|
||||
= antenna.list&.title || '[Insert to Home]'
|
||||
|
||||
.filters-list__item__permissions
|
||||
%ul.permissions-list
|
||||
- unless antenna.stl
|
||||
- unless antenna.antenna_domains.empty?
|
||||
%li.permissions-list__item
|
||||
.permissions-list__item__icon
|
||||
= material_symbol('cloud')
|
||||
.permissions-list__item__text
|
||||
.permissions-list__item__text__title
|
||||
= t('antennas.index.domains', count: antenna.antenna_domains.size)
|
||||
.permissions-list__item__text__type
|
||||
- domains = antenna.antenna_domains.map(&:name)
|
||||
- domains = domains.take(5) + ['…'] if domains.size > 5 # TODO
|
||||
= domains.join(', ')
|
||||
- unless antenna.antenna_accounts.empty?
|
||||
%li.permissions-list__item
|
||||
.permissions-list__item__icon
|
||||
= material_symbol('groups')
|
||||
.permissions-list__item__text
|
||||
.permissions-list__item__text__title
|
||||
= t('antennas.index.accounts', count: antenna.antenna_accounts.size)
|
||||
.permissions-list__item__text__type
|
||||
- accounts = antenna.antenna_accounts.map { |account| account.account.domain ? "@#{account.account.username}@#{account.account.domain}" : "@#{account.account.username}" }
|
||||
- accounts = accounts.take(5) + ['…'] if accounts.size > 5 # TODO
|
||||
= accounts.join(', ')
|
||||
- if antenna.keywords.present?
|
||||
%li.permissions-list__item
|
||||
.permissions-list__item__icon
|
||||
= material_symbol('format_paragraph')
|
||||
.permissions-list__item__text
|
||||
.permissions-list__item__text__title
|
||||
= t('antennas.index.keywords', count: antenna.keywords.size)
|
||||
.permissions-list__item__text__type
|
||||
- keywords = antenna.keywords
|
||||
- keywords = keywords.take(5) + ['…'] if keywords.size > 5 # TODO
|
||||
= keywords.join(', ')
|
||||
- unless antenna.antenna_tags.empty?
|
||||
%li.permissions-list__item
|
||||
.permissions-list__item__icon
|
||||
= material_symbol('tag')
|
||||
.permissions-list__item__text
|
||||
.permissions-list__item__text__title
|
||||
= t('antennas.index.tags', count: antenna.antenna_tags.size)
|
||||
.permissions-list__item__text__type
|
||||
- tags = antenna.antenna_tags.map { |tag| tag.tag.name }
|
||||
- tags = tags.take(5) + ['…'] if tags.size > 5 # TODO
|
||||
= tags.join(', ')
|
||||
|
||||
.announcements-list__item__action-bar
|
||||
.announcements-list__item__meta
|
||||
- if antenna.stl
|
||||
= t('antennas.index.stl')
|
||||
- elsif antenna.enabled_config_raws?
|
||||
= t('antennas.index.contexts', contexts: antenna.context.map { |context| I18n.t("antennas.contexts.#{context}") }.join(', '))
|
||||
- else
|
||||
= t('antennas.errors.empty_contexts')
|
||||
|
||||
%div
|
||||
= table_link_to 'edit', t('antennas.edit.title'), edit_antenna_path(antenna)
|
||||
= table_link_to 'close', t('antennas.index.delete'), antenna_path(antenna), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }
|
|
@ -1,11 +0,0 @@
|
|||
%p= t 'antennas.edit.description'
|
||||
%hr.spacer/
|
||||
|
||||
.fields-row
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :title, as: :string, wrapper: :with_label, hint: false
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :expires_in, wrapper: :with_label, collection: [30.minutes, 1.hour, 6.hours, 12.hours, 1.day, 1.week].map(&:to_i), label_method: ->(i) { I18n.t("invites.expires_in.#{i}") }, include_blank: I18n.t('invites.expires_in_prompt')
|
||||
|
||||
.fields-row
|
||||
= f.input :available, wrapper: :with_label, label: t('antennas.edit.available'), hint: false
|
|
@ -1,9 +0,0 @@
|
|||
- content_for :page_title do
|
||||
= t('antennas.edit.title')
|
||||
|
||||
= simple_form_for @antenna, url: antenna_path(@antenna), method: :put do |f|
|
||||
= render 'shared/error_messages', object: @antenna
|
||||
= render 'antenna_fields', f: f, lists: @lists
|
||||
|
||||
.actions
|
||||
= f.button :button, t('generic.save_changes'), type: :submit
|
|
@ -1,8 +0,0 @@
|
|||
- content_for :page_title do
|
||||
= t('antennas.index.title')
|
||||
|
||||
- if @antennas.empty?
|
||||
.muted-hint.center-text= t 'antennas.index.empty'
|
||||
- else
|
||||
.applications-list
|
||||
= render partial: 'antenna', collection: @antennas
|
|
@ -28,8 +28,7 @@ Rails.application.routes.draw do
|
|||
/public/remote
|
||||
/conversations
|
||||
/lists/(*any)
|
||||
/antennasw/(*any)
|
||||
/antennast/(*any)
|
||||
/antennas/(*any)
|
||||
/circles/(*any)
|
||||
/links/(*any)
|
||||
/notifications/(*any)
|
||||
|
@ -213,7 +212,6 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
end
|
||||
resources :antennas, except: [:show]
|
||||
|
||||
resource :relationships, only: [:show, :update]
|
||||
resources :severed_relationships, only: [:index] do
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue