Skip to content

Commit

Permalink
Merge branch 'main' into chore-node-20
Browse files Browse the repository at this point in the history
  • Loading branch information
ajohn25 authored Sep 25, 2024
2 parents f504daa + 28a793f commit 89fc921
Show file tree
Hide file tree
Showing 38 changed files with 2,184 additions and 1,547 deletions.
1 change: 0 additions & 1 deletion .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ jobs:
matrix:
node-version:
- 20.16.0-bullseye

container:
image: node:${{ matrix.node-version }}

Expand Down
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,41 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

### [8.1.6-rc.0](https://github.com/politics-rewired/spoke/compare/v8.1.5...v8.1.6-rc.0) (2024-09-23)

### [8.1.5](https://github.com/politics-rewired/spoke/compare/v8.1.4-rc.1...v8.1.5) (2024-09-19)


### Bug Fixes

* **column mapping:** remove create as from custom field value ([#5](https://github.com/politics-rewired/spoke/issues/5)) ([13730d5](https://github.com/politics-rewired/spoke/commit/13730d576b8e262e7947a851844b99c3739606e8))
* **send-message:** await service method ([#7](https://github.com/politics-rewired/spoke/issues/7)) ([dc4421d](https://github.com/politics-rewired/spoke/commit/dc4421d997b76bb86b02d3526b9e1ceed317262d))
* only mark contact as messaged after initial ([#42](https://github.com/politics-rewired/spoke/issues/42)) ([c16398e](https://github.com/politics-rewired/spoke/commit/c16398ed45a580101265b93fd3017f83a50d3851))


### Backend Changes

* **campaign-operations:** use codegen, typescript, react fcs ([#43](https://github.com/politics-rewired/spoke/issues/43)) ([9c760df](https://github.com/politics-rewired/spoke/commit/9c760df845ab836f17beb298a1f9a24ed22a0389))
* **email:** use with the ranks info ([#13](https://github.com/politics-rewired/spoke/issues/13)) ([b1ea23d](https://github.com/politics-rewired/spoke/commit/b1ea23de40453cf72c46ffe9955039050e2cd646))
* **export-campaign:** extract payload types ([#44](https://github.com/politics-rewired/spoke/issues/44)) ([5df2d21](https://github.com/politics-rewired/spoke/commit/5df2d217e56f91670542839f5ed481c6558866ea))
* **second-pass:** implement as task ([#46](https://github.com/politics-rewired/spoke/issues/46)) ([d575a0b](https://github.com/politics-rewired/spoke/commit/d575a0beee71a82e1b8ccc7407c70f291b9c07db))
* **user menu:** rename teams to organizations ([#11](https://github.com/politics-rewired/spoke/issues/11)) ([66cd60c](https://github.com/politics-rewired/spoke/commit/66cd60cbcca24a39816a51a2ce47f2d9094aa398))
* remove bernie sms references ([#8](https://github.com/politics-rewired/spoke/issues/8)) ([241960c](https://github.com/politics-rewired/spoke/commit/241960c7505bbcf4687f73211aa31a609a385205))

### [8.1.4-rc.1](https://github.com/politics-rewired/spoke/compare/v8.1.4-rc.0...v8.1.4-rc.1) (2024-08-07)


### Bug Fixes

* **exports:** use name of materialized cte ([#40](https://github.com/politics-rewired/spoke/issues/40)) ([6b2cafd](https://github.com/politics-rewired/spoke/commit/6b2cafdcded8535481b00cc3fe4d9555d6771fd1))

### [8.1.4-rc.0](https://github.com/politics-rewired/spoke/compare/v8.1.3...v8.1.4-rc.0) (2024-08-07)


### Bug Fixes

* **exports:** materialize campaign contacts ([#39](https://github.com/politics-rewired/spoke/issues/39)) ([909db41](https://github.com/politics-rewired/spoke/commit/909db41f1e24a16e307db6b773835c6f39fec140))

### [8.1.3](https://github.com/politics-rewired/spoke/compare/v8.1.2...v8.1.3) (2024-07-24)


Expand Down
2 changes: 1 addition & 1 deletion libs/gql-schema/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const schema = `
textRequestMaxCount: Int
textsAvailable: Boolean
pendingAssignmentRequestCount: Int!
currentAssignmentTargets: [AssignmentTarget]!
currentAssignmentTargets: [AssignmentTarget!]!
myCurrentAssignmentTarget: AssignmentTarget
myCurrentAssignmentTargets: [AssignmentTarget]!
escalatedConversationCount: Int!
Expand Down
6 changes: 4 additions & 2 deletions libs/gql-schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ const rootSchema = `
input CampaignExportInput {
campaignId: String!
# For Spoke Exports
campaignTitle: String
exportType: CampaignExportType!
spokeOptions: ExportForSpokeInput
vanOptions: ExportForVanInput
Expand Down Expand Up @@ -333,11 +335,11 @@ const rootSchema = `
requestTexts(count: Int!, email: String!, organizationId: String!, preferredTeamId: String!): String!
releaseMessages(campaignId: String!, target: ReleaseActionTarget!, ageInHours: Float): String!
releaseAllUnhandledReplies(organizationId: String!, ageInHours: Float, releaseOnRestricted: Boolean, limitToCurrentlyTextableContacts: Boolean): ReleaseAllUnhandledRepliesResult!
markForSecondPass(campaignId: String!, input: SecondPassInput!): String!
markForSecondPass(campaignId: String!, campaignTitle: String!, input: SecondPassInput!): String!
startAutosending(campaignId: String!): Campaign!
pauseAutosending(campaignId: String!): Campaign!
updateCampaignAutosendingLimit(campaignId: String!, limit: Int): Campaign!
unMarkForSecondPass(campaignId: String!): String!
unMarkForSecondPass(campaignId: String!, campaignTitle: String!): String!
deleteNeedsMessage(campaignId: String!): String!
insertLinkDomain(organizationId: String!, domain: String!, maxUsageCount: Int!): LinkDomain!
updateLinkDomain(organizationId: String!, domainId: String!, payload: UpdateLinkDomain!): LinkDomain!
Expand Down
67 changes: 67 additions & 0 deletions libs/spoke-codegen/src/graphql/campaign-operations.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
fragment CurrentAssignmentTarget on AssignmentTarget {
type
campaign {
id
title
}
teamTitle
countLeft
enabled
}

fragment CampaignInfo on Campaign {
id
title
isStarted
isApproved
isArchived
hasUnassignedContacts
hasUnsentInitialMessages
hasUnhandledMessages
description
dueBy
}

query GetAdminAssignmentTargets($organizationId: String!) {
organization(id: $organizationId) {
id
currentAssignmentTargets {
...CurrentAssignmentTarget
}
}
}

mutation archiveCampaign($campaignId: String!) {
archiveCampaign(id: $campaignId) {
...CampaignInfo
}
}

mutation unarchiveCampaign($campaignId: String!) {
unarchiveCampaign(id: $campaignId) {
...CampaignInfo
}
}

mutation releaseMessages($campaignId: String!, $target: ReleaseActionTarget!, $ageInHours: Float) {
releaseMessages(campaignId: $campaignId, target: $target, ageInHours: $ageInHours)
}

mutation deleteNeedsMessage($campaignId: String!) {
deleteNeedsMessage(campaignId: $campaignId)
}

mutation markForSecondPass($campaignId: String!, $campaignTitle: String!, $input: SecondPassInput!) {
markForSecondPass(campaignId: $campaignId, campaignTitle: $campaignTitle, input: $input)
}

mutation unMarkForSecondPass($campaignId: String!, $campaignTitle: String!) {
unMarkForSecondPass(campaignId: $campaignId, campaignTitle: $campaignTitle)
}

mutation toggleAutoAssign($campaignId: String!, $enabled: Boolean!) {
editCampaign(id: $campaignId, campaign: { isAutoassignEnabled: $enabled }) {
id
isAutoassignEnabled
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "spoke",
"version": "8.1.3",
"version": "8.1.6-rc.0",
"description": "Spoke",
"main": "src/server",
"engines": {
Expand Down
12 changes: 4 additions & 8 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,6 @@ const validators = {
dec: "Disable use of has unassigned contacts variable",
default: false
}),
BAD_WORD_TOKEN: str({
desc: "Bearer token used for authorization with BAD_WORD_URL.",
default: undefined
}),
BAD_WORD_URL: url({
desc: "URL to notify with message text whenever a message is sent.",
default: undefined
}),
BASE_URL: url({
desc:
"The base URL of the website, without trailing slash, used to construct various URLs.",
Expand Down Expand Up @@ -736,6 +728,10 @@ const validators = {
"A JSON blob passed directly to express-basic-auth for locking campaign previews",
default: undefined
}),
MARK_SECOND_PASS_CHUNK_SIZE: num({
desc: "Chunk size to use when marking a campaign for a second pass",
default: 1000
}),
SKIP_TWILIO_VALIDATION: bool({
desc: "Whether to bypass Twilio header validation altogether.",
default: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,11 @@ const ConfigureColumnMappingDialog: React.FC<ConfigureColumnMappingDialogProps>
<Autocomplete
value={value}
onChange={(_event, newValue) => {
onChange(newValue);
const quotedWord = newValue?.match(
/"([^"]+)"/
)?.[1];
const valueToSet = quotedWord ?? newValue;
onChange(valueToSet);
}}
selectOnFocus
clearOnBlur
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,21 @@ import React, { useState } from "react";
interface CampaignExportModalProps {
open: boolean;
campaignId: string;
campaignTitle: string;
onError(errorMessage: string): void;
onClose(): void;
onComplete(): void;
}

const CampaignExportModal: React.FC<CampaignExportModalProps> = (props) => {
const { campaignId, open, onClose, onComplete, onError } = props;
const {
campaignId,
campaignTitle,
open,
onClose,
onComplete,
onError
} = props;
const [exportCampaign, setExportCampaign] = useState<boolean>(true);
const [exportMessages, setExportMessages] = useState<boolean>(true);
const [exportOptOut, setExportOptOut] = useState<boolean>(false);
Expand All @@ -39,6 +47,7 @@ const CampaignExportModal: React.FC<CampaignExportModalProps> = (props) => {
variables: {
options: {
campaignId,
campaignTitle,
exportType: CampaignExportType.Spoke,
spokeOptions: {
campaign: exportCampaign,
Expand Down
13 changes: 1 addition & 12 deletions src/containers/AdminCampaignStats/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ class AdminCampaignStats extends React.Component {
/>
<CampaignExportModal
campaignId={campaignId}
campaignTitle={campaign.title}
open={this.state.exportDialogOpen}
onClose={this.handleCloseCampaignExport}
onComplete={this.handleCompleteCampaignExport}
Expand Down Expand Up @@ -536,18 +537,6 @@ const mutations = {
`,
variables: { campaignId: ownProps.match.params.campaignId }
}),
exportCampaign: (ownProps) => () => ({
mutation: gql`
mutation exportCampaign($campaignId: String!) {
exportCampaign(
options: { campaignId: $campaignId, exportType: SPOKE }
) {
id
}
}
`,
variables: { campaignId: ownProps.match.params.campaignId }
}),
copyCampaign: (ownProps) => () => ({
mutation: gql`
mutation copyCampaign($campaignId: String!) {
Expand Down
47 changes: 27 additions & 20 deletions src/containers/CampaignList/components/AssignmentHUD.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Chip from "@material-ui/core/Chip";
import { useTheme } from "@material-ui/core/styles";
import type { AssignmentTarget } from "@spoke/spoke-codegen";
import type { CurrentAssignmentTargetFragment } from "@spoke/spoke-codegen";
import { css, StyleSheet } from "aphrodite";
import { Card, CardHeader, CardText } from "material-ui/Card";
import React from "react";
Expand All @@ -16,7 +16,7 @@ const styles = StyleSheet.create({
});

interface Props {
assignmentTargets: AssignmentTarget[];
assignmentTargets: CurrentAssignmentTargetFragment[];
}

const AssignmentHUD: React.FC<Props> = (props) => {
Expand All @@ -34,24 +34,31 @@ const AssignmentHUD: React.FC<Props> = (props) => {
showExpandableButton
/>
<CardText expandable>
{assignmentTargets.map((target) => (
<div key={target.teamTitle} className={css(styles.row)}>
{!target.enabled && (
<Chip
label="Disabled"
className={css(styles.disabledChip)}
style={disabledStyle}
/>
)}
<Chip className={css(styles.chip)} label={target.teamTitle} />
<div className={css(styles.prefix)}>{target.type} &#8594;</div>
<div className={css(styles.title)}>
{target.campaign.id}: {target.campaign.title}
</div>
<div className={css(styles.spacer)} />
<div className={css(styles.count)}>({target.countLeft} left)</div>
</div>
))}
{assignmentTargets.map((target) => {
const { campaign } = target;
return (
target && (
<div key={target.teamTitle} className={css(styles.row)}>
{!target.enabled && (
<Chip
label="Disabled"
className={css(styles.disabledChip)}
style={disabledStyle}
/>
)}
<Chip className={css(styles.chip)} label={target.teamTitle} />
<div className={css(styles.prefix)}>{target.type} &#8594;</div>
<div className={css(styles.title)}>
{campaign?.id}: {campaign?.title}
</div>
<div className={css(styles.spacer)} />
<div className={css(styles.count)}>
({target.countLeft} left)
</div>
</div>
)
);
})}
</CardText>
</Card>
);
Expand Down
4 changes: 2 additions & 2 deletions src/containers/CampaignList/components/CampaignList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import type { CampaignListEntryFragment } from "@spoke/spoke-codegen";
import React from "react";

import Empty from "../../../components/Empty";
import type { CampaignOperations } from "./CampaignListMenu";
import type { CampaignOperationsProps } from "../utils";
import CampaignListRow from "./CampaignListRow";

interface Props extends CampaignOperations {
interface Props extends CampaignOperationsProps {
organizationId: string;
campaigns: CampaignListEntryFragment[];
isAdmin: boolean;
Expand Down
6 changes: 2 additions & 4 deletions src/containers/CampaignList/components/CampaignListLoader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,15 @@ import React from "react";

import LoadingIndicator from "../../../components/LoadingIndicator";
import { useAuthzContext } from "../../AuthzProvider";
import type { CampaignOperationsProps } from "../utils";
import { isCampaignGroupsPermissionError } from "../utils";
import CampaignList from "./CampaignList";

interface Props {
interface Props extends CampaignOperationsProps {
organizationId: string;
pageSize: number;
campaignsFilter: CampaignsFilter;
isAdmin: boolean;
startOperation: (...args: any[]) => any;
archiveCampaign: (...args: any[]) => any;
unarchiveCampaign: (...args: any[]) => any;
}

const CampaignListLoader: React.FC<Props> = (props) => {
Expand Down
Loading

0 comments on commit 89fc921

Please sign in to comment.