From eb591da80768c0d49e48f2fe2f939465c1f089f2 Mon Sep 17 00:00:00 2001 From: nick-funk Date: Wed, 27 Apr 2022 10:42:42 -0600 Subject: [PATCH 01/72] Create a simple import blocker that checks for cross imports Prevents you from import `coral-server` into `src/core/client` source files and vice versa for `coral-client` into `src/core/server`. Runs as part of our linting. --- importBlocker.json | 20 ++++++++ package.json | 1 + scripts/importBlocker.ts | 107 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 importBlocker.json create mode 100644 scripts/importBlocker.ts diff --git a/importBlocker.json b/importBlocker.json new file mode 100644 index 0000000000..bb817cc4f8 --- /dev/null +++ b/importBlocker.json @@ -0,0 +1,20 @@ +{ + "sources": [ + { + "name": "client", + "directory": "src/core/client", + "blockedImports": [ + "coral-server/" + ], + "extensions": [ ".ts", ".tsx" ] + }, + { + "name": "server", + "directory": "src/core/server", + "blockedImports": [ + "coral-client/" + ], + "extensions": [ ".ts" ] + } + ] +} \ No newline at end of file diff --git a/package.json b/package.json index 39c7ee4706..5249ef6c7e 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "lint:graphql": "graphql-schema-linter src/core/server/graph/schema/schema.graphql", "lint:scripts": "eslint 'scripts/**/*.{js,ts,tsx}'", "lint:server": "eslint 'src/**/*.{js,ts,tsx}' --ignore-pattern 'src/core/client/**'", + "lint:imports": "ts-node --transpile-only ./scripts/importBlocker.ts", "lint": "npm-run-all --parallel lint:* tscheck:*", "migration:create": "ts-node --transpile-only ./scripts/migration/create.ts", "start:development": "NODE_ENV=development TS_NODE_PROJECT=./src/tsconfig.json ts-node-dev --inspect --transpile-only --no-notify -r tsconfig-paths/register --ignore-watch ./docs/ ./src/index.ts", diff --git a/scripts/importBlocker.ts b/scripts/importBlocker.ts new file mode 100644 index 0000000000..fc4b7b1cc9 --- /dev/null +++ b/scripts/importBlocker.ts @@ -0,0 +1,107 @@ +/* eslint-disable no-console */ + +import fs from "fs"; +import path from "path"; +import readLine from "readline"; + +const CONFIG_FILE = "importBlocker.json"; + +interface Source { + name: string; + directory: string; + blockedImports: string[]; + extensions: string[]; +} + +interface Config { + sources: Source[]; +} + +interface Error { + path: string; + lineNumber: number; + line: string; +} + +const loadConfig = (): Config => { + const configRaw = fs.readFileSync(CONFIG_FILE).toString(); + const config = JSON.parse(configRaw) as Config; + + return config; +}; + +const errors: Error[] = []; + +const processFile = async ( + source: Source, + filePath: string, + filters: string[] +) => { + const stream = fs.createReadStream(filePath); + const reader = readLine.createInterface({ + input: stream, + crlfDelay: Infinity, + }); + + let lineCounter = 0; + for await (const line of reader) { + for (const filter of filters) { + if (line.includes(filter)) { + errors.push({ + path: filePath, + lineNumber: lineCounter, + line, + }); + } + } + + lineCounter++; + } +}; + +const processDir = async (source: Source, dir: string, filters: string[]) => { + const items = fs.readdirSync(dir); + + for (const item of items) { + const fullPath = path.join(dir, item); + const stats = fs.lstatSync(fullPath); + + if (stats.isDirectory()) { + await processDir(source, fullPath, filters); + } else if (stats.isFile()) { + const ext = path.extname(item); + + if (source.extensions.includes(ext)) { + await processFile(source, fullPath, filters); + } + } + } +}; + +const run = async () => { + const config = loadConfig(); + + for (const source of config.sources) { + const filters = source.blockedImports.map( + (blockedImport) => `from "${blockedImport}` + ); + + await processDir(source, source.directory, filters); + } + + if (errors.length > 0) { + console.error("Blocked imports linter found the following errors:"); + + for (const error of errors) { + console.error( + ` Blocked import found in '${error.path}' on line ${error.lineNumber}: ${error.line}` + ); + } + + process.exit(1); + } else { + console.log("Blocked imports linter found 0 errors."); + } +}; + +run().finally(() => {}); From f5b0e28215134213549ec14a5aa999d2e0fe9eae Mon Sep 17 00:00:00 2001 From: nick-funk Date: Tue, 10 May 2022 14:35:59 -0600 Subject: [PATCH 02/72] Add further blocked imports to coral-server config --- importBlocker.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/importBlocker.json b/importBlocker.json index bb817cc4f8..5f9074e1ad 100644 --- a/importBlocker.json +++ b/importBlocker.json @@ -12,7 +12,9 @@ "name": "server", "directory": "src/core/server", "blockedImports": [ - "coral-client/" + "coral-client/", + "coral-stream/", + "coral-framework/" ], "extensions": [ ".ts" ] } From 8f05376b9d4755821e5ec48e9b18bb91e73029dd Mon Sep 17 00:00:00 2001 From: Marcus Haddon Date: Tue, 7 Feb 2023 14:40:19 -0800 Subject: [PATCH 03/72] get username of tag creator for featured comments --- .../Stream/FeaturedComments/FeaturedCommentContainer.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedCommentContainer.tsx b/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedCommentContainer.tsx index 3a83c78f6a..c73718a146 100644 --- a/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedCommentContainer.tsx +++ b/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedCommentContainer.tsx @@ -253,6 +253,11 @@ const enhanced = withFragmentContainer({ username } } + tags { + createdBy { + username + } + } rating body createdAt From 05b0d90b6985abf7c4e59d6780463e192b402e26 Mon Sep 17 00:00:00 2001 From: Marcus Haddon Date: Thu, 9 Feb 2023 10:54:59 -0800 Subject: [PATCH 04/72] create FeaturedBy component --- .../Stream/FeaturedComments/FeaturedBy.css | 14 ++++++++++++++ .../Stream/FeaturedComments/FeaturedBy.tsx | 17 +++++++++++++++++ .../FeaturedCommentContainer.tsx | 10 ++++++++++ 3 files changed, 41 insertions(+) create mode 100644 src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.css create mode 100644 src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx diff --git a/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.css b/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.css new file mode 100644 index 0000000000..13c025ba8e --- /dev/null +++ b/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.css @@ -0,0 +1,14 @@ +$status-modal-username: $colors-mono-900; + +.root { + font-weight: var(--font-weight-secondary-regular); + font-family: var(--font-family-secondary); + color: --pallete-primary-400; + font-size: var(--font-size-1); + text-transform: uppercase; +} + +.name { + font-size: var(--font-size-1); + font-weight: var(--font-weight-primary-bold); +} diff --git a/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx b/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx new file mode 100644 index 0000000000..a122e5bfe8 --- /dev/null +++ b/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx @@ -0,0 +1,17 @@ +import React, { FunctionComponent } from "react"; + +import styles from "./FeaturedBy.css"; + +interface Props { + username: string; +} + +const FeaturedBy: FunctionComponent = ({ username }) => { + return ( + + FEATURED BY {username} + + ); +}; + +export default FeaturedBy; diff --git a/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedCommentContainer.tsx b/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedCommentContainer.tsx index c73718a146..e39fce034f 100644 --- a/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedCommentContainer.tsx +++ b/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedCommentContainer.tsx @@ -34,6 +34,8 @@ import ReactionButtonContainer from "../../Comment/ReactionButton"; import { UsernameWithPopoverContainer } from "../../Comment/Username"; import IgnoredTombstoneOrHideContainer from "../../IgnoredTombstoneOrHideContainer"; +import FeaturedBy from "./FeaturedBy"; + import styles from "./FeaturedCommentContainer.css"; interface Props { @@ -72,6 +74,10 @@ const FeaturedCommentContainer: FunctionComponent = (props) => { [emitViewConversationEvent, comment.id, setCommentID] ); + const featuringUser = comment.tags.find( + (tag) => tag.code === "FEATURED" + )?.createdBy; + const gotoConvAriaLabelId = comment.author?.username ? "comments-featured-gotoConversation-label-with-username" : "comments-featured-gotoConversation-label-without-username"; @@ -94,6 +100,9 @@ const FeaturedCommentContainer: FunctionComponent = (props) => { + {featuringUser?.username && ( + + )} {isRatingsAndReviews && comment.rating && ( )} @@ -254,6 +263,7 @@ const enhanced = withFragmentContainer({ } } tags { + code createdBy { username } From 5f9e1685ac4f48712cab4f56d6a352fae60c7056 Mon Sep 17 00:00:00 2001 From: Marcus Haddon Date: Fri, 10 Feb 2023 09:19:51 -0800 Subject: [PATCH 05/72] lowercase featured by --- .../stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx b/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx index a122e5bfe8..d4f828513d 100644 --- a/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx +++ b/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx @@ -9,7 +9,7 @@ interface Props { const FeaturedBy: FunctionComponent = ({ username }) => { return ( - FEATURED BY {username} + featured by {username} ); }; From 1e25ec5673b085c70dae35be1414b34849e838f9 Mon Sep 17 00:00:00 2001 From: Marcus Haddon Date: Fri, 10 Feb 2023 10:19:02 -0800 Subject: [PATCH 06/72] add todo --- .../stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx b/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx index d4f828513d..aa9cfb13a6 100644 --- a/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx +++ b/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx @@ -6,6 +6,7 @@ interface Props { username: string; } +// TODO (marcushaddon): localize! const FeaturedBy: FunctionComponent = ({ username }) => { return ( From 1d69c95252ea758e5dc681c44d2b0b10c364c19d Mon Sep 17 00:00:00 2001 From: Marcus Haddon Date: Tue, 14 Feb 2023 16:17:28 -0800 Subject: [PATCH 07/72] localize featured by --- .../tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx | 9 ++++++--- src/locales/en-US/stream.ftl | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx b/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx index aa9cfb13a6..50af326735 100644 --- a/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx +++ b/src/core/client/stream/tabs/Comments/Stream/FeaturedComments/FeaturedBy.tsx @@ -1,3 +1,4 @@ +import { Localized } from "@fluent/react/compat"; import React, { FunctionComponent } from "react"; import styles from "./FeaturedBy.css"; @@ -9,9 +10,11 @@ interface Props { // TODO (marcushaddon): localize! const FeaturedBy: FunctionComponent = ({ username }) => { return ( - - featured by {username} - + + + featured by {username} + + ); }; diff --git a/src/locales/en-US/stream.ftl b/src/locales/en-US/stream.ftl index 041a35713b..4513840640 100644 --- a/src/locales/en-US/stream.ftl +++ b/src/locales/en-US/stream.ftl @@ -286,6 +286,7 @@ comments-moderationRejectedTombstone-moderateLink = Go to moderate to review this decision comments-featuredTag = Featured +comments-featuredBy = Featured by {$username} # $reaction could be "Respect" as an example. Be careful when translating to other languages with different grammar cases. comments-react = From 301b426335e3c297d9caee22ab696dd3060d21c6 Mon Sep 17 00:00:00 2001 From: Marcus Haddon Date: Wed, 15 Mar 2023 11:58:54 -0700 Subject: [PATCH 08/72] adjustments to match design --- src/core/client/admin/components/BanModal.css | 16 ++ src/core/client/admin/components/BanModal.tsx | 146 ++++++++++-------- 2 files changed, 97 insertions(+), 65 deletions(-) diff --git a/src/core/client/admin/components/BanModal.css b/src/core/client/admin/components/BanModal.css index 2a2439b7b7..aa213aebb5 100644 --- a/src/core/client/admin/components/BanModal.css +++ b/src/core/client/admin/components/BanModal.css @@ -15,3 +15,19 @@ $ban-modal-text: var(--palette-text-500); .sitesToggle { margin-bottom: var(--spacing-3); } + +.banFrom { + margin-bottom: var(--spacing-1); + +} + +.customizeMessage { + color: -var(--palette-grey-800); +} +.toggleButton { + +} + +.toggleIcon { + +} diff --git a/src/core/client/admin/components/BanModal.tsx b/src/core/client/admin/components/BanModal.tsx index e209a2f4f1..32791a0288 100644 --- a/src/core/client/admin/components/BanModal.tsx +++ b/src/core/client/admin/components/BanModal.tsx @@ -15,6 +15,7 @@ import { useMutation } from "coral-framework/lib/relay"; import { GQLUSER_ROLE } from "coral-framework/schema"; import { Button, + ButtonIcon, CheckBox, Flex, FormField, @@ -37,6 +38,7 @@ import ChangeStatusModal from "./UserStatus/ChangeStatusModal"; import { getTextForUpdateType } from "./UserStatus/helpers"; import UserStatusSitesList, { Scopes } from "./UserStatus/UserStatusSitesList"; +import { header4 } from "coral-ui/components/v2/Typography/Typography.css"; import styles from "./BanModal.css"; export enum UpdateType { @@ -291,70 +293,13 @@ const BanModal: FunctionComponent = ({
{({ handleSubmit, submitError }) => ( - - {updateType !== UpdateType.NO_SITES && ( - - - setRejectExistingComments(event.target.checked) - } - > - {viewerIsSingleSiteMod - ? "Reject all comments on this site" - : rejectExistingCommentsMessage} - - - )} - {updateType !== UpdateType.NO_SITES && - emailDomain && - !domainIsConfigured && ( - - { - setBanDomain(target.checked); - }} - > - Ban all new accounts on {emailDomain} - - - )} - {updateType !== UpdateType.NO_SITES && ( - - - setCustomizeMessage(event.target.checked) - } - > - Customize ban email message - - - )} - {updateType !== UpdateType.NO_SITES && customizeMessage && ( -