Upgrade Admin to Stimulus 2.0 (#11776)
* Upgrade Stimulus to 2.0 * Convert ArticleController to use Stimulus 2 * Convert ModalController to Stimulus 2 * Convert BufferController to Stimulus 2 * Convert ConfigController to use Stimuus 2 * Convert ImageUploadController to Stimulus 2 * Convert Reaction controller to Stimulus 2
This commit is contained in:
parent
9bb62598a4
commit
7eb7cef1b9
20 changed files with 225 additions and 140 deletions
|
|
@ -3,12 +3,15 @@ import ArticleController from '../../controllers/article_controller';
|
|||
|
||||
describe('ArticleController', () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = `<div data-controller="article">
|
||||
<div class="card-body">
|
||||
document.body.innerHTML = `
|
||||
<div data-controller="article"
|
||||
data-article-bg-highlighted-class="bg-highlighted"
|
||||
data-article-border-highlighted-class="border-highlighted">
|
||||
<div class="card-body" data-article-target="cardBody">
|
||||
<button data-action="article#increaseFeaturedNumber"></button>
|
||||
<button data-action="article#decreaseFeaturedNumber"></button>
|
||||
<button data-action="article#highlightElement"></button>
|
||||
<input data-target="article.featuredNumber"></input>
|
||||
<input data-article-target="featuredNumber"></input>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
|
|
@ -23,7 +26,7 @@ describe('ArticleController', () => {
|
|||
it('increases the featured number input', () => {
|
||||
const button = document.getElementsByTagName('button')[0];
|
||||
const input = document.querySelector(
|
||||
"[data-target='article.featuredNumber']",
|
||||
"[data-article-target='featuredNumber']",
|
||||
);
|
||||
|
||||
input.value = initialValue;
|
||||
|
|
@ -37,7 +40,7 @@ describe('ArticleController', () => {
|
|||
it('increases the featured number input', () => {
|
||||
const button = document.getElementsByTagName('button')[1];
|
||||
const input = document.querySelector(
|
||||
"[data-target='article.featuredNumber']",
|
||||
"[data-article-target='featuredNumber']",
|
||||
);
|
||||
|
||||
input.value = initialValue;
|
||||
|
|
|
|||
|
|
@ -3,8 +3,11 @@ import BufferController from '../../controllers/buffer_controller';
|
|||
|
||||
describe('BufferController', () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = `<div data-controller="buffer">
|
||||
<h2 data-target="buffer.header"></h2>
|
||||
document.body.innerHTML = `
|
||||
<div data-controller="buffer"
|
||||
data-buffer-bg-highlighted-class="bg-highlighted"
|
||||
data-buffer-border-highlighted-class="border-highlighted">
|
||||
<h2 data-buffer-target="header"></h2>
|
||||
<button data-action="buffer#tagBufferUpdateConfirmed"></button>
|
||||
<button data-action="buffer#tagBufferUpdateDismissed"></button>
|
||||
<button data-action="buffer#highlightElement"></button>
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ import ConfigController from '../../controllers/config_controller';
|
|||
|
||||
describe('ConfigController', () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = `<div data-controller="config">
|
||||
document.body.innerHTML = `
|
||||
<div data-controller="config">
|
||||
<button data-action="click->config#activateEmailAuthModal">
|
||||
Disable
|
||||
</button>
|
||||
<div data-target="config.configModalAnchor"></div>
|
||||
<div data-config-target="configModalAnchor"></div>
|
||||
</div>`;
|
||||
|
||||
global.scrollTo = jest.fn();
|
||||
|
|
@ -20,7 +21,7 @@ describe('ConfigController', () => {
|
|||
it('builds and adds a Modal to the page', () => {
|
||||
const button = document.getElementsByTagName('button')[0];
|
||||
const modalAnchor = document.querySelector(
|
||||
'[data-target="config.configModalAnchor"]',
|
||||
'[data-config-target="configModalAnchor"]',
|
||||
);
|
||||
|
||||
button.click();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { Controller } from 'stimulus';
|
||||
|
||||
export default class ArticleController extends Controller {
|
||||
static targets = ['featuredNumber'];
|
||||
static classes = ['bgHighlighted', 'borderHighlighted'];
|
||||
static targets = ['featuredNumber', 'cardBody'];
|
||||
|
||||
increaseFeaturedNumber() {
|
||||
// Increases the article's chances of being seen
|
||||
|
|
@ -16,18 +17,12 @@ export default class ArticleController extends Controller {
|
|||
}
|
||||
|
||||
highlightElement() {
|
||||
const card = this.element.getElementsByClassName('card-body')[0];
|
||||
card.classList.add('bg-highlighted', 'border-highlighted');
|
||||
const card = this.cardBodyTarget;
|
||||
|
||||
card.classList.add(this.bgHighlightedClass, this.borderHighlightedClass);
|
||||
|
||||
setTimeout(() => {
|
||||
card.classList.remove('bg-highlighted');
|
||||
card.classList.remove(this.bgHighlightedClass);
|
||||
}, 350);
|
||||
}
|
||||
|
||||
get articleId() {
|
||||
return parseInt(this.data.get('id'), 10);
|
||||
}
|
||||
|
||||
set articleId(value) {
|
||||
this.data.set('id', value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,33 @@
|
|||
import { Controller } from 'stimulus';
|
||||
|
||||
const CONFIRM_BADGE_HTML =
|
||||
'<span class="ml-2 badge badge-success">Confirm</span>';
|
||||
const DISMISS_BADGE_HTML =
|
||||
'<span class="ml-2 badge badge-danger">Dismiss</span>';
|
||||
|
||||
export default class BufferController extends Controller {
|
||||
static classes = ['bgHighlighted', 'borderHighlighted'];
|
||||
static targets = ['header', 'bodyText'];
|
||||
|
||||
tagBufferUpdateConfirmed() {
|
||||
this.clearPreviousBadge();
|
||||
|
||||
this.headerTarget.innerHTML +=
|
||||
'<span class="ml-2 badge badge-success">Confirm</span>';
|
||||
this.headerTarget.innerHTML += CONFIRM_BADGE_HTML;
|
||||
}
|
||||
|
||||
tagBufferUpdateDismissed() {
|
||||
this.clearPreviousBadge();
|
||||
|
||||
this.headerTarget.innerHTML +=
|
||||
'<span class="ml-2 badge badge-danger">Dismiss</span>';
|
||||
this.headerTarget.innerHTML += DISMISS_BADGE_HTML;
|
||||
}
|
||||
|
||||
highlightElement() {
|
||||
this.element.classList.add('bg-highlighted', 'border-highlighted');
|
||||
this.element.classList.add(
|
||||
this.bgHighlightedClass,
|
||||
this.borderHighlightedClass,
|
||||
);
|
||||
setTimeout(() => {
|
||||
this.element.classList.remove('bg-highlighted');
|
||||
this.element.classList.remove(this.bgHighlightedClass);
|
||||
}, 350);
|
||||
}
|
||||
|
||||
|
|
@ -36,12 +43,4 @@ export default class BufferController extends Controller {
|
|||
badge.remove();
|
||||
}
|
||||
}
|
||||
|
||||
get bufferUpdateId() {
|
||||
return parseInt(this.data.get('id'), 10);
|
||||
}
|
||||
|
||||
set bufferUpdateId(value) {
|
||||
this.data.set('id', value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@ const emailAuthSettingsSection = document.getElementById(
|
|||
const emailAuthModalTitle = 'Disable Email address registration';
|
||||
// TODO: Remove the sentence "You must update site config to save this action!"
|
||||
// once we build more robust flow for Admin/Config
|
||||
const emailAuthModalBody =
|
||||
'<p>If you disable Email address as a registration option, people cannot create an account with their email address.</p><p>However, people who have already created an account using their email address can continue to login.</p><p><strong>You must confirm and update site config to save below this action.</strong></p>';
|
||||
const emailAuthModalBody = `
|
||||
<p>If you disable Email address as a registration option, people cannot create an account with their email address.</p>
|
||||
<p>However, people who have already created an account using their email address can continue to login.</p>
|
||||
<p><strong>You must confirm and update site config to save below this action.</strong></p>`;
|
||||
|
||||
export default class ConfigController extends Controller {
|
||||
static targets = [
|
||||
|
|
|
|||
|
|
@ -2,20 +2,22 @@ import { Controller } from 'stimulus';
|
|||
|
||||
export default class ImageUploadController extends Controller {
|
||||
static targets = ['fileField', 'imageResult'];
|
||||
static values = { url: String };
|
||||
|
||||
onFormSubmit(event) {
|
||||
event.preventDefault();
|
||||
let token = document.getElementsByName('authenticity_token')[0].value;
|
||||
let image = this.fileFieldTarget.files[0];
|
||||
|
||||
const token = document.getElementsByName('authenticity_token')[0].value;
|
||||
const image = this.fileFieldTarget.files[0];
|
||||
let formData = new FormData();
|
||||
|
||||
formData.append('authenticity_token', token);
|
||||
formData.append('image', image);
|
||||
|
||||
fetch('/image_uploads', {
|
||||
fetch(this.urlValue, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF_Token': window.csrfToken,
|
||||
'X-CSRF-Token': window.csrfToken,
|
||||
},
|
||||
body: formData,
|
||||
credentials: 'same-origin',
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { Controller } from 'stimulus';
|
||||
|
||||
export default class ModalController extends Controller {
|
||||
static classes = ['hidden'];
|
||||
static targets = ['toggle'];
|
||||
|
||||
toggleModal() {
|
||||
if (this.toggleTarget) {
|
||||
this.toggleTarget.classList.toggle('hidden');
|
||||
if (this.hasToggleTarget) {
|
||||
this.toggleTarget.classList.toggle(this.hiddenClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
/* eslint-disable no-alert */
|
||||
import { Controller } from 'stimulus';
|
||||
|
||||
export default class ReactionController extends Controller {
|
||||
static targets = ['invalid', 'confirmed'];
|
||||
static values = {
|
||||
id: Number,
|
||||
url: String,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
/* eslint no-alert: "error" */
|
||||
updateReaction(id, status) {
|
||||
fetch(`/admin/reactions/${id}`, {
|
||||
updateReaction(status) {
|
||||
const id = this.idValue;
|
||||
|
||||
fetch(this.urlValue, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
|
|
@ -28,46 +31,45 @@ export default class ReactionController extends Controller {
|
|||
this.element.remove();
|
||||
document.getElementById(`js__reaction__div__hr__${id}`).remove();
|
||||
} else {
|
||||
alert(json.error);
|
||||
window.alert(json.error);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
alert(error);
|
||||
window.alert(error);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
updateReactionInvalid() {
|
||||
this.updateReaction(this.reactionId, this.invalidStatus);
|
||||
this.updateReaction(this.invalidStatus);
|
||||
}
|
||||
|
||||
updateReactionConfirmed() {
|
||||
this.updateReaction(this.reactionId, this.confirmedStatus);
|
||||
this.updateReaction(this.confirmedStatus);
|
||||
}
|
||||
|
||||
reactableUserCheck() {
|
||||
if (this.reactableType === 'user') {
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
if (confirm('You are confirming a User vomit reaction; are you sure?')) {
|
||||
this.updateReaction(this.reactionId, this.confirmedStatus);
|
||||
if (
|
||||
window.confirm(
|
||||
'You are confirming a User vomit reaction; are you sure?',
|
||||
)
|
||||
) {
|
||||
this.updateReaction(this.confirmedStatus);
|
||||
}
|
||||
} else {
|
||||
this.updateReaction(this.reactionId, this.confirmedStatus);
|
||||
this.updateReaction(this.confirmedStatus);
|
||||
}
|
||||
}
|
||||
|
||||
get reactionId() {
|
||||
return parseInt(this.data.get('id'), 10);
|
||||
}
|
||||
|
||||
get confirmedStatus() {
|
||||
return this.confirmedTarget.dataset.status;
|
||||
}
|
||||
|
||||
get reactableType() {
|
||||
return this.confirmedTarget.dataset.reactable;
|
||||
}
|
||||
|
||||
get confirmedStatus() {
|
||||
return this.confirmedTarget.dataset.status;
|
||||
}
|
||||
|
||||
get invalidStatus() {
|
||||
return this.invalidTarget.dataset.altstatus;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,19 +4,29 @@
|
|||
}
|
||||
</style>
|
||||
|
||||
<div class="card my-3" data-controller="article" data-article-id="<%= article.id %>">
|
||||
<div class="card my-3"
|
||||
data-controller="article"
|
||||
data-article-bg-highlighted-class="bg-highlighted"
|
||||
data-article-border-highlighted-class="border-highlighted">
|
||||
|
||||
<div class="card-header">
|
||||
<h2>
|
||||
<a href="<%= article.path %>" target="_blank" rel="noopener">
|
||||
<%= article.title %>
|
||||
</a>
|
||||
</h2>
|
||||
|
||||
<div>
|
||||
<a href="<%= article.path %>/edit" target="_blank" rel="noopener"><span class="btn btn-sm btn-primary">Edit</span></a>
|
||||
|
||||
<button class="btn btn-sm btn-success" data-action="article#increaseFeaturedNumber">Boost</button>
|
||||
<a class="btn btn-sm btn-secondary" href="/admin/users/<%= article.user_id %>" target="_blank" rel="noopener">Manage User</a>
|
||||
<a href="/admin/users/<%= article.user_id %>" class="badge badge-light">@<%= article.user&.username %></a>
|
||||
|
||||
<a class="btn btn-sm btn-secondary" href="<%= admin_user_path(article.user_id) %>" target="_blank" rel="noopener">Manage User</a>
|
||||
|
||||
<a href="<%= admin_user_path(article.user_id) %>" class="badge badge-light">@<%= article.user&.username %></a>
|
||||
|
||||
<span class="badge badge-light">❤️ <%= article.public_reactions_count %> 💬 <%= article.comments_count %></span>
|
||||
|
||||
<span class="badge badge-light">
|
||||
<% if article.published_from_feed? && !article.published? %>
|
||||
RSS Import <%= article.created_at.strftime("%b %d, %Y") %>
|
||||
|
|
@ -28,10 +38,10 @@
|
|||
<%= article.published_at&.strftime("%b %d, %Y") %>
|
||||
<% end %>
|
||||
</span>
|
||||
<% article.decorate.cached_tag_list_array.each do |tag| %>
|
||||
<a class="badge badge-secondary" href='/t/<%= tag %>'>#<%= tag %></a>
|
||||
<% end %>
|
||||
|
||||
<% article.decorate.cached_tag_list_array.each do |tag| %>
|
||||
<a class="badge badge-secondary" href='<%= tag_path(tag) %>'>#<%= tag %></a>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -40,6 +50,7 @@
|
|||
<% background_color = approved %>
|
||||
|
||||
<div
|
||||
data-article-target="cardBody"
|
||||
class="card-body <%= background_color %> <%= "bg-danger" if !article.published? && article.published_from_feed? && !article.user&.feed_admin_publish_permission? %>">
|
||||
|
||||
<% if article.video %>
|
||||
|
|
@ -60,7 +71,7 @@
|
|||
<%= note.author_id ? User.find(note.author_id).username : "No Author" %></em> - <%= note.content %>
|
||||
</p>
|
||||
<% end %>
|
||||
<p><a href="/admin/users/<%= article.user_id %>">View All</a></p>
|
||||
<p><a href="<%= admin_user_path(article.user_id) %>">View All</a></p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% if article.main_image.present? %>
|
||||
|
|
@ -77,8 +88,11 @@
|
|||
<div class="row">
|
||||
<div class="form-group col">
|
||||
<label for="featured_number_<%= article.id %>">Featured Number:</label>
|
||||
<input id="featured_number_<%= article.id %>" class="form-control" name="article[featured_number]"
|
||||
value="<%= article.featured_number %>" data-target="article.featuredNumber">
|
||||
<input id="featured_number_<%= article.id %>"
|
||||
class="form-control"
|
||||
name="article[featured_number]"
|
||||
value="<%= article.featured_number %>"
|
||||
data-article-target="featuredNumber">
|
||||
</div>
|
||||
<div class="form-group col">
|
||||
<label for="author_id_<%= article.id %>">Author ID:</label>
|
||||
|
|
|
|||
|
|
@ -18,28 +18,40 @@
|
|||
<div class="col-12">
|
||||
<ul class="nav nav-tabs nav-fill">
|
||||
<li class="nav-item">
|
||||
<a href="/admin/articles" class="nav-link <%= "active" if params[:state].blank? %>">Hot</a>
|
||||
<a href="<%= admin_articles_path %>" class="nav-link <%= "active" if params[:state].blank? %>">Hot</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/admin/articles?state=chronological" class="nav-link <%= "active" if params[:state] == "chronological" %>">Chronological</a>
|
||||
<a
|
||||
href="<%= admin_articles_path(state: :chronological) %>"
|
||||
class="nav-link <%= "active" if params[:state] == "chronological" %>">Chronological</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/admin/articles?state=satellite" class="nav-link <%= "active" if params[:state] == "satellite" %>">Satellite</a>
|
||||
<a
|
||||
href="<%= admin_articles_path(state: :satellite) %>"
|
||||
class="nav-link <%= "active" if params[:state] == "satellite" %>">Satellite</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<span class="nav-link disabled">Not Buffered:</span>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/admin/articles?state=not-buffered-0.25" class="nav-link <%= "active" if params[:state] == "not-buffered-0.25" %>">6hr</a>
|
||||
<a
|
||||
href="<%= admin_articles_path(state: "not-buffered-0.25") %>"
|
||||
class="nav-link <%= "active" if params[:state] == "not-buffered-0.25" %>">6hr</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/admin/articles?state=not-buffered-1" class="nav-link <%= "active" if params[:state] == "not-buffered-1" %>">1d</a>
|
||||
<a
|
||||
href="<%= admin_articles_path(state: "not-buffered-1") %>"
|
||||
class="nav-link <%= "active" if params[:state] == "not-buffered-1" %>">1d</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/admin/articles?state=not-buffered-7" class="nav-link <%= "active" if params[:state] == "not-buffered-7" %>">7d</a>
|
||||
<a
|
||||
href="<%= admin_articles_path(state: "not-buffered-7") %>"
|
||||
class="nav-link <%= "active" if params[:state] == "not-buffered-7" %>">7d</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/admin/articles?state=satellite-not-buffered" class="nav-link <%= "active" if params[:state] == "satellite-not-buffered" %>">Satellite</a>
|
||||
<a
|
||||
href="href="<%= admin_articles_path(state: "satellite-not-buffered") %>""
|
||||
class="nav-link <%= "active" if params[:state] == "satellite-not-buffered" %>">Satellite</a>
|
||||
</li>
|
||||
</ul>
|
||||
<% if params[:state] && params[:state].include?("top-") && params[:state] != "top-3" && params[:state] != "top-6" %>
|
||||
|
|
@ -54,31 +66,53 @@
|
|||
<summary style="font-size: 1.3em; cursor: pointer;">Suggested Tweets (<%= @pending_buffer_updates.size %>)</summary>
|
||||
<% @pending_buffer_updates.each do |buffer_update| %>
|
||||
<% next unless buffer_update.article %>
|
||||
<div class="card my-3" id="suggested-tweet-<%= buffer_update.id %>" data-controller="buffer" data-action="load@window->buffer#autosizeBodyText">
|
||||
<div
|
||||
class="card my-3"
|
||||
id="suggested-tweet-<%= buffer_update.id %>"
|
||||
data-controller="buffer"
|
||||
data-action="load@window->buffer#autosizeBodyText"
|
||||
data-buffer-bg-highlighted-class="bg-highlighted"
|
||||
data-buffer-border-highlighted-class="border-highlighted">
|
||||
<div class="card-header">
|
||||
<h2 class="my-0" data-target="buffer.header"><%= buffer_update.article.title %></h2>
|
||||
<h2 class="my-0" data-buffer-target="header"><%= buffer_update.article.title %></h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h4>Score: <%= buffer_update.article.score %></h4>
|
||||
<div class="blockquote">
|
||||
<%= HTML_Truncator.truncate(buffer_update.article.processed_html, 50, ellipsis: "<a class=\"comment-read-more\" href=\"#{buffer_update.article.path}\">... Read Entire Post</a>").html_safe %>
|
||||
<%= HTML_Truncator.truncate(
|
||||
buffer_update.article.processed_html,
|
||||
50,
|
||||
ellipsis: "<a class=\"comment-read-more\" href=\"#{buffer_update.article.path}\">... Read Entire Post</a>",
|
||||
).html_safe %>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<code><b><%= Tag.find_by(id: buffer_update.tag_id)&.name || buffer_update.social_service_name %>:</b></code>
|
||||
|
||||
<%= form_with url: admin_buffer_update_path(buffer_update.id), class: "buffer-form buffer-confirm", html: { data: { action: "submit->buffer#highlightElement" } } do |f| %>
|
||||
<%= form_with(
|
||||
url: admin_buffer_update_path(buffer_update.id),
|
||||
class: "buffer-form buffer-confirm",
|
||||
html: { data: { action: "submit->buffer#highlightElement" } },
|
||||
) do |f| %>
|
||||
<div class="form-group">
|
||||
<input name="utf8" type="hidden" value="✓">
|
||||
<input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>" />
|
||||
<input type="hidden" name="_method" value="patch" />
|
||||
<input type="hidden" name="status" value="confirmed" />
|
||||
<textarea class="w-100 suggested-tweet-body-text" name="body_text" class="form-control" data-target="buffer.bodyText"><%= buffer_update.body_text %></textarea>
|
||||
<textarea
|
||||
class="w-100 suggested-tweet-body-text"
|
||||
name="body_text"
|
||||
class="form-control"
|
||||
data-buffer-target="bodyText"><%= buffer_update.body_text %></textarea>
|
||||
</div>
|
||||
<button value="confirmed" name="status" class="btn btn-success" data-action="buffer#tagBufferUpdateConfirmed">Confirm</button>
|
||||
<% end %>
|
||||
|
||||
<%= form_with url: admin_buffer_update_path(buffer_update.id), class: "buffer-form buffer-dismiss", html: { data: { action: "submit->buffer#highlightElement" } } do |f| %>
|
||||
<%= form_with(
|
||||
url: admin_buffer_update_path(buffer_update.id),
|
||||
class: "buffer-form buffer-dismiss",
|
||||
html: { data: { action: "submit->buffer#highlightElement" } },
|
||||
) do |f| %>
|
||||
<div class="form-group">
|
||||
<input name="utf8" type="hidden" value="✓">
|
||||
<input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>" />
|
||||
|
|
|
|||
|
|
@ -135,7 +135,9 @@
|
|||
<h3 class="crayons-subtitle-3 mb-3">
|
||||
General settings
|
||||
</h3>
|
||||
<div class="crayons-field crayons-field--checkbox <%= invite_only_mode_or_no_enabled_auth_options ? "crayons-tooltip" : "" %>" data-tooltip="Unchecking this will enable Email Registration">
|
||||
<div
|
||||
class="crayons-field crayons-field--checkbox <%= invite_only_mode_or_no_enabled_auth_options ? "crayons-tooltip" : "" %>"
|
||||
data-tooltip="Unchecking this will enable Email Registration">
|
||||
<%= f.check_box :invite_only_mode,
|
||||
checked: invite_only_mode_or_no_enabled_auth_options,
|
||||
data: { action: "config#adjustAuthenticationOptions", target: "config.inviteOnlyMode" },
|
||||
|
|
@ -171,7 +173,7 @@
|
|||
</p>
|
||||
<div
|
||||
class="enabled-indicator <%= SiteConfig.allow_email_password_registration ? "visible" : "" %>"
|
||||
data-target="config.enabledIndicator">
|
||||
data-config-target="enabledIndicator">
|
||||
<%= inline_svg_tag("checkmark.svg", aria: true, class: "crayons-icon admin-config-checkmark", title: "Checkmark") %>
|
||||
<small class="crayons-field__description ml-1">Enabled</small>
|
||||
</div>
|
||||
|
|
@ -181,7 +183,7 @@
|
|||
class="crayons-btn crayons-btn--secondary"
|
||||
id="email-auth-enable-edit-btn"
|
||||
data-button-text="<%= SiteConfig.allow_email_password_registration ? "edit" : "enable" %>"
|
||||
data-target="config.emailAuthSettingsBtn"
|
||||
data-config-target="emailAuthSettingsBtn"
|
||||
data-action="click->config#enableOrEditEmailAuthSettings"
|
||||
<%= disabled_attr_on_auth_provider_enablebtn %>>
|
||||
<%= SiteConfig.allow_email_password_registration ? "Edit" : "Enable" %>
|
||||
|
|
@ -217,7 +219,10 @@
|
|||
<div class="crayons-field--checkbox">
|
||||
<%= f.check_box :require_captcha_for_email_password_registration,
|
||||
checked: SiteConfig.require_captcha_for_email_password_registration,
|
||||
data: { action: "config#toggleGoogleRecaptchaFields", target: "config.requireCaptchaForEmailPasswordRegistration" },
|
||||
data: {
|
||||
action: "config#toggleGoogleRecaptchaFields",
|
||||
"config-target": "requireCaptchaForEmailPasswordRegistration"
|
||||
},
|
||||
class: "crayons-checkbox mt-2" %>
|
||||
<div>
|
||||
<%= admin_config_label :require_captcha_for_email_password_registration, "Enable Google reCAPTCHA for email password registration" %>
|
||||
|
|
|
|||
|
|
@ -23,16 +23,21 @@
|
|||
<div class="card-body" style="overflow: scroll; max-height: 500px;">
|
||||
<% @vomits.each do |reaction| %>
|
||||
<% next if (reaction.reactable_type == "Article" && !reaction.reactable.published) || (reaction.reactable_type == "User" && reaction.reactable&.banished?) %>
|
||||
<div class="d-flex justify-content-between" data-controller="reaction" data-reaction-id="<%= reaction.id %>">
|
||||
|
||||
<div
|
||||
class="d-flex justify-content-between"
|
||||
data-controller="reaction"
|
||||
data-reaction-id-value="<%= reaction.id %>"
|
||||
data-reaction-url-value="<%= admin_reaction_path(reaction.id) %>">
|
||||
<span>
|
||||
🤢 <a href="<%= reaction.user.path %>">@<%= reaction.user.username %></a>
|
||||
🤢 <a href="<%= reaction.user.path %>" target="_blank" rel="noopener">@<%= reaction.user.username %></a>
|
||||
<% if reaction.user_id == SiteConfig.mascot_user_id %>
|
||||
<strong>(auto-generated)</strong>
|
||||
<% end %>
|
||||
</span>
|
||||
<span>
|
||||
<strong><%= reaction.reactable_type %>:</strong>
|
||||
<a href="<%= reaction.reactable.path %>"><%= reaction.reactable_type == "User" ? reaction.reactable.username : reaction.reactable.title %></a>
|
||||
<a href="<%= reaction.reactable.path %>" target="_blank" rel="noopener"><%= reaction.reactable_type == "User" ? reaction.reactable.username : reaction.reactable.title %></a>
|
||||
<% if reaction.reactable_type == "User" && reaction.reactable.banned %>
|
||||
<span class="badge badge-danger">Suspended</span>
|
||||
<% end %>
|
||||
|
|
@ -48,7 +53,7 @@
|
|||
type="button"
|
||||
data-reactable="user"
|
||||
data-status="confirmed"
|
||||
data-target="reaction.confirmed"
|
||||
data-reaction-target="confirmed"
|
||||
data-action="reaction#reactableUserCheck">
|
||||
CONFIRM
|
||||
</button>
|
||||
|
|
@ -58,7 +63,7 @@
|
|||
type="button"
|
||||
data-reactable="non-user"
|
||||
data-status="confirmed"
|
||||
data-target="reaction.confirmed"
|
||||
data-reaction-target="confirmed"
|
||||
data-action="reaction#reactableUserCheck">
|
||||
CONFIRM
|
||||
</button>
|
||||
|
|
@ -67,7 +72,7 @@
|
|||
class="btn btn-danger btn-sm"
|
||||
type="button"
|
||||
data-altstatus="invalid"
|
||||
data-target="reaction.invalid"
|
||||
data-reaction-target="invalid"
|
||||
data-action="reaction#updateReactionInvalid">
|
||||
INVALID
|
||||
</button>
|
||||
|
|
@ -77,7 +82,7 @@
|
|||
class="btn btn-warning text-white btn-sm"
|
||||
type="button"
|
||||
data-altstatus="invalid"
|
||||
data-target="reaction.invalid"
|
||||
data-reaction-target="invalid"
|
||||
data-action="reaction#updateReactionInvalid">
|
||||
INVALIDATE
|
||||
</button>
|
||||
|
|
@ -86,7 +91,7 @@
|
|||
class="btn btn-success btn-sm"
|
||||
type="button"
|
||||
data-status="confirmed"
|
||||
data-target="reaction.confirmed"
|
||||
data-reaction-target="confirmed"
|
||||
data-action="reaction#updateReactionConfirmed">
|
||||
MARK AS VALID
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
|
||||
<header class="flex items-center mb-6">
|
||||
<h2 class="crayons-title mb-4">Listings</h2>
|
||||
<a href="/admin/listings/categories"
|
||||
aria-label="Listing Categories"
|
||||
class="ml-auto crayons-btn">
|
||||
|
||||
<a
|
||||
href="<%= admin_listing_categories_path %>"
|
||||
aria-label="Listing Categories"
|
||||
class="ml-auto crayons-btn">
|
||||
Listing Categories
|
||||
</a>
|
||||
</header>
|
||||
|
|
@ -57,8 +59,19 @@
|
|||
<td><%= listing.bumped_at ? "#{time_ago_in_words(listing.bumped_at)} ago" : "Draft" %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="buffer-cell border-0" colspan="7" data-controller="buffer" data-action="load@window->buffer#autosizeBodyText">
|
||||
<button class="btn btn-secondary" data-toggle="collapse" data-target="#buffering-area-for-listing-<%= listing.id %>" aria-expanded="false" aria-controls="buffering-area-for-listing-<%= listing.id %>">
|
||||
<td
|
||||
class="buffer-cell border-0"
|
||||
colspan="7"
|
||||
data-controller="buffer"
|
||||
data-action="load@window->buffer#autosizeBodyText"
|
||||
data-buffer-bg-highlighted-class="bg-highlighted"
|
||||
data-buffer-border-highlighted-class="border-highlighted">
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
data-toggle="collapse"
|
||||
data-target="#buffering-area-for-listing-<%= listing.id %>"
|
||||
aria-expanded="false"
|
||||
aria-controls="buffering-area-for-listing-<%= listing.id %>">
|
||||
Share to Buffer
|
||||
</button>
|
||||
|
||||
|
|
@ -73,7 +86,7 @@
|
|||
<%= form_with url: admin_buffer_updates_path, html: { data: { action: "submit->buffer#highlightElement" } } do %>
|
||||
<input type="hidden" name="social_channel" value="listings_twitter" />
|
||||
<input type="hidden" name="listing_id" value="<%= listing.id %>" />
|
||||
<textarea class="form-control" wrap="hard" name="tweet" maxlength="255" data-target="buffer.bodyText">
|
||||
<textarea class="form-control" wrap="hard" name="tweet" maxlength="255" data-buffer-target="bodyText">
|
||||
📋 New <%= community_name %> Listing!

Category: <%= listing.category %>

<%= listing.title %>

|
||||
<% if listing.user.twitter_username? %>
|
||||
Posted by @<%= listing.user.twitter_username %>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<span data-controller="modal">
|
||||
<span data-controller="modal" data-modal-hidden-class="hidden">
|
||||
<button class="crayons-btn" type="button" data-action="modal#toggleModal">
|
||||
Add group
|
||||
</button>
|
||||
|
||||
<div id="add-group-modal" class="hidden" data-target="modal.toggle">
|
||||
<div id="add-group-modal" class="hidden" data-modal-target="toggle">
|
||||
<div class="crayons-modal crayons-modal--s absolute">
|
||||
<div class="crayons-modal__box">
|
||||
<header class="crayons-modal__box__header">
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<span data-controller="modal" class="mx-1">
|
||||
<span data-controller="modal" class="mx-1" data-modal-hidden-class="hidden">
|
||||
<button data-action="modal#toggleModal" class="crayons-btn">
|
||||
Add Field
|
||||
</button>
|
||||
|
||||
<div id="add-<%= group_name %>-profile-field-modal" class="hidden" data-target="modal.toggle">
|
||||
<div id="add-<%= group_name %>-profile-field-modal" class="hidden" data-modal-target="toggle">
|
||||
<div class="crayons-modal crayons-modal--s">
|
||||
<div class="crayons-modal__box">
|
||||
<header class="crayons-modal__box__header">
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<span data-controller="modal" class="mx-1">
|
||||
<span data-controller="modal" class="mx-1" data-modal-hidden-class="hidden">
|
||||
<button data-action="modal#toggleModal" class="crayons-btn crayons-btn--secondary">
|
||||
Edit group
|
||||
</button>
|
||||
|
||||
<div id="edit-group-<%= group_name %>-modal" class="hidden" data-target="modal.toggle">
|
||||
<div id="edit-group-<%= group_name %>-modal" class="hidden" data-modal-target="toggle">
|
||||
<div class="crayons-modal crayons-modal--s">
|
||||
<div class="crayons-modal__box">
|
||||
<header class="crayons-modal__box__header">
|
||||
|
|
|
|||
|
|
@ -1,15 +1,21 @@
|
|||
<div class="crayons-card p-6" data-controller="image-upload">
|
||||
<div class="crayons-card p-6" data-controller="image-upload" data-image-upload-url-value="<%= image_uploads_path %>">
|
||||
<h2 class="crayons-title mb-4">Upload an Image</h2>
|
||||
<p class="mb-6">Quickly upload an image.</p>
|
||||
<% # Multipart, remote forms are tricky, the data is actually sent in the Stimulus controller. %>
|
||||
# Multipart, remote forms are tricky, the data is actually sent in the Stimulus controller. %>
|
||||
<%= form_with(url: image_uploads_path, multipart: true) do |f| %>
|
||||
<div class="form-group">
|
||||
<%= f.label(:image, "Image:") %>
|
||||
<%= f.file_field "image", class: "form-control", required: true, data: { target: "image-upload.fileField" } %>
|
||||
<%= f.file_field(
|
||||
"image",
|
||||
class: "form-control",
|
||||
required: true,
|
||||
accept: "image/*",
|
||||
data: { "image-upload-target": "fileField" },
|
||||
) %>
|
||||
</div>
|
||||
<%= f.submit "Upload", class: "btn btn-primary", data: { action: "image-upload#onFormSubmit" } %>
|
||||
<% end %>
|
||||
|
||||
<div class="mt-4 d-none" data-target="image-upload.imageResult">
|
||||
<div class="mt-4 d-none" data-image-upload-target="imageResult">
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@
|
|||
"prop-types": "^15.7.2",
|
||||
"pusher-js": "^7.0.2",
|
||||
"rails-erb-loader": "^5.5.2",
|
||||
"stimulus": "^1.1.1",
|
||||
"stimulus": "^2.0.0",
|
||||
"twilio-video": "^2.9.0",
|
||||
"web-share-wrapper": "^0.2.1"
|
||||
},
|
||||
|
|
|
|||
48
yarn.lock
48
yarn.lock
|
|
@ -1608,29 +1608,29 @@
|
|||
dependencies:
|
||||
"@sinonjs/commons" "^1.7.0"
|
||||
|
||||
"@stimulus/core@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@stimulus/core/-/core-1.1.1.tgz#42b0cfe5b73ca492f41de64b77a03980bae92c82"
|
||||
integrity sha512-PVJv7IpuQx0MVPCBblXc6O2zbCmU8dlxXNH4bC9KK6LsvGaE+PCXXrXQfXUwAsse1/CmRu/iQG7Ov58himjiGg==
|
||||
"@stimulus/core@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@stimulus/core/-/core-2.0.0.tgz#140c85318d6a8a8210c0faf182223b8459348877"
|
||||
integrity sha512-ff70GafKtzc8zQ1/cG+UvL06GcifPWovf2wBEdjLMh9xO2GOYURO3y2RYgzIGYUIBefQwyfX2CLfJdZFJrEPTw==
|
||||
dependencies:
|
||||
"@stimulus/mutation-observers" "^1.1.1"
|
||||
"@stimulus/mutation-observers" "^2.0.0"
|
||||
|
||||
"@stimulus/multimap@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@stimulus/multimap/-/multimap-1.1.1.tgz#b95e3fd607345ab36e5d5b55486ee1a12d56b331"
|
||||
integrity sha512-26R1fI3a8uUj0WlMmta4qcfIQGlagegdP4PTz6lz852q/dXlG6r+uPS/bx+H8GtfyS+OOXVr3SkZ0Zg0iRqRfQ==
|
||||
"@stimulus/multimap@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@stimulus/multimap/-/multimap-2.0.0.tgz#420cfa096ed6538df4a91dbd2b2842c1779952b2"
|
||||
integrity sha512-pMBCewkZCFVB3e5mEMoyO9+9aKzHDITmf3OnPun51YWxlcPdHcwbjqm1ylK63fsoduIE+RowBpFwFqd3poEz4w==
|
||||
|
||||
"@stimulus/mutation-observers@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@stimulus/mutation-observers/-/mutation-observers-1.1.1.tgz#0f6c6f081308427fed2a26360dda0c173b79cfc0"
|
||||
integrity sha512-/zCnnw1KJlWO2mrx0yxYaRFZWMGnDMdOgSnI4hxDLxdWVuL2HMROU8FpHWVBLjKY3T9A+lGkcrmPGDHF3pfS9w==
|
||||
"@stimulus/mutation-observers@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@stimulus/mutation-observers/-/mutation-observers-2.0.0.tgz#3dbe37453bda47a6c795a90204ee8d77a799fb87"
|
||||
integrity sha512-kx4VAJdPhIGBQKGIoUDC2tupEKorG3A+ckc2b1UiwInKTMAC1axOHU8ebcwhaJIxRqIrs8//4SJo9YAAOx6FEg==
|
||||
dependencies:
|
||||
"@stimulus/multimap" "^1.1.1"
|
||||
"@stimulus/multimap" "^2.0.0"
|
||||
|
||||
"@stimulus/webpack-helpers@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@stimulus/webpack-helpers/-/webpack-helpers-1.1.1.tgz#eff60cd4e58b921d1a2764dc5215f5141510f2c2"
|
||||
integrity sha512-XOkqSw53N9072FLHvpLM25PIwy+ndkSSbnTtjKuyzsv8K5yfkFB2rv68jU1pzqYa9FZLcvZWP4yazC0V38dx9A==
|
||||
"@stimulus/webpack-helpers@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@stimulus/webpack-helpers/-/webpack-helpers-2.0.0.tgz#54296d2a2dffd4f962d2e802d99a3fdd84b8845f"
|
||||
integrity sha512-D6tJWsAC024MwGEIKlUVYU8Ln87mlrmiwHvYAjipg+s8H4eLxUMQ3PZkWyPevfipH+oR3leuHsjYsK1gN5ViQA==
|
||||
|
||||
"@stoplight/better-ajv-errors@0.0.3":
|
||||
version "0.0.3"
|
||||
|
|
@ -17206,13 +17206,13 @@ stickyfill@^1.1.1:
|
|||
resolved "https://registry.yarnpkg.com/stickyfill/-/stickyfill-1.1.1.tgz#39413fee9d025c74a7e59ceecb23784cc0f17f02"
|
||||
integrity sha1-OUE/7p0CXHSn5ZzuyyN4TMDxfwI=
|
||||
|
||||
stimulus@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/stimulus/-/stimulus-1.1.1.tgz#53c2fded6849e7b85eed3ed8dd76e33abd74bec5"
|
||||
integrity sha512-R0mBqKp48YnRDZOxZ8hiOH4Ilph3Yj78CIFTBkCwyHs4iGCpe7xlEdQ7cjIxb+7qVCSxFKgxO+mAQbsNgt/5XQ==
|
||||
stimulus@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/stimulus/-/stimulus-2.0.0.tgz#713c8b91a72ef90914b90955f0e705f004403047"
|
||||
integrity sha512-xipy7BS5TVpg4fX6S8LhrYZp7cmHGjmk09WSAiVx1gF5S5g43IWsuetfUhIk8HfHUG+4MQ9nY0FQz4dRFLs/8w==
|
||||
dependencies:
|
||||
"@stimulus/core" "^1.1.1"
|
||||
"@stimulus/webpack-helpers" "^1.1.1"
|
||||
"@stimulus/core" "^2.0.0"
|
||||
"@stimulus/webpack-helpers" "^2.0.0"
|
||||
|
||||
store2@^2.7.1:
|
||||
version "2.12.0"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue