proca 1.8.2 → 1.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +190 -25
  2. package/package.json +2 -1
  3. package/proca-cli +2 -2
  4. package/src/commands/action/add.mjs +131 -131
  5. package/src/commands/action/confirm.mjs +44 -44
  6. package/src/commands/action/count.mjs +41 -41
  7. package/src/commands/action/list.mjs +130 -130
  8. package/src/commands/action/replay.mjs +30 -30
  9. package/src/commands/action/requeue.mjs +110 -110
  10. package/src/commands/campaign/add.mjs +95 -83
  11. package/src/commands/campaign/copy.mjs +91 -0
  12. package/src/commands/campaign/delete.mjs +36 -56
  13. package/src/commands/campaign/get.mjs +5 -0
  14. package/src/commands/campaign/list.mjs +128 -123
  15. package/src/commands/campaign/queries.graphql +14 -14
  16. package/src/commands/campaign/status.mjs +39 -39
  17. package/src/commands/campaign/widget/archive.mjs +124 -0
  18. package/src/commands/campaign/widget/copy.mjs +175 -0
  19. package/src/commands/config/add.mjs +78 -78
  20. package/src/commands/config/folder.mjs +30 -30
  21. package/src/commands/config/server.mjs +15 -15
  22. package/src/commands/config/set.mjs +84 -84
  23. package/src/commands/config/user.mjs +50 -48
  24. package/src/commands/contact/count.mjs +0 -1
  25. package/src/commands/contact/list.mjs +131 -131
  26. package/src/commands/org/add.mjs +51 -51
  27. package/src/commands/org/crm.mjs +61 -61
  28. package/src/commands/org/delete.mjs +31 -31
  29. package/src/commands/org/email.mjs +94 -66
  30. package/src/commands/org/get.mjs +9 -1
  31. package/src/commands/service/add.mjs +59 -59
  32. package/src/commands/service/list.mjs +15 -15
  33. package/src/commands/target/add.mjs +52 -52
  34. package/src/commands/template/add.mjs +67 -67
  35. package/src/commands/template/list.mjs +33 -33
  36. package/src/commands/user/get.mjs +60 -60
  37. package/src/commands/user/invite.mjs +37 -37
  38. package/src/commands/user/join.mjs +51 -51
  39. package/src/commands/user/leave.mjs +47 -47
  40. package/src/commands/user/reset.mjs +72 -72
  41. package/src/commands/widget/add.mjs +61 -70
  42. package/src/commands/widget/delete.mjs +27 -27
  43. package/src/commands/widget/get.mjs +5 -0
  44. package/src/commands/widget/list.mjs +7 -5
  45. package/src/commands/widget/update.mjs +174 -0
  46. package/src/config.mjs +31 -31
  47. package/src/generated/schema.json +10675 -10675
  48. package/src/hooks/help.mjs +9 -9
  49. package/src/hooks/init.mjs +26 -26
  50. package/src/procaCommand.mjs +22 -1
  51. package/src/urql.mjs +39 -39
  52. package/src/util/twitter.mjs +19 -19
  53. package/theme.json +27 -27
@@ -2,46 +2,51 @@ import { Args, Flags } from "@oclif/core";
2
2
  import { error, stdout, ux } from "@oclif/core/ux";
3
3
  import Command from "#src/procaCommand.mjs";
4
4
  import {
5
- FragmentOrg,
6
- FragmentStats,
7
- FragmentSummary,
5
+ FragmentOrg,
6
+ FragmentStats,
7
+ FragmentSummary,
8
8
  } from "#src/queries/campaign.mjs";
9
9
  import { gql, query } from "#src/urql.mjs";
10
10
 
11
+ export const getCampaignList = (params) => {
12
+ const d = new CampaignList([]);
13
+ return d.fetch(params);
14
+ };
15
+
11
16
  export default class CampaignList extends Command {
12
- actionTypes = new Set();
13
-
14
- static args = {
15
- title: Args.string({ description: "name of the campaign, % for wildchar" }),
16
- };
17
-
18
- static description = "list all the campaigns";
19
-
20
- static examples = ["<%= config.bin %> <%= command.id %> %pizza%"];
21
-
22
- static flags = {
23
- // flag with no value (-f, --force)
24
- ...super.globalFlags,
25
- org: Flags.string({
26
- char: "o",
27
- description: "campaigns of the organisation (coordinator or partner)",
28
- exactlyOne: ["org", "title"],
29
- helpValue: "<organisation name>",
30
- }),
31
- title: Flags.string({
32
- char: "t",
33
- description: "name of the campaign, % for wildchar",
34
- helpValue: "<campaign title>",
35
- }),
36
- stats: Flags.boolean({
37
- description: "display the stats",
38
- default: true,
39
- allowNo: true,
40
- }),
41
- };
42
-
43
- OrgSearch = async (name) => {
44
- const SearchCampaignsDocument = gql`
17
+ actionTypes = new Set();
18
+
19
+ static args = {
20
+ title: Args.string({ description: "name of the campaign, % for wildchar" }),
21
+ };
22
+
23
+ static description = "list all the campaigns";
24
+
25
+ static examples = ["<%= config.bin %> <%= command.id %> %pizza%"];
26
+
27
+ static flags = {
28
+ // flag with no value (-f, --force)
29
+ ...super.globalFlags,
30
+ org: Flags.string({
31
+ char: "o",
32
+ description: "campaigns of the organisation (coordinator or partner)",
33
+ exactlyOne: ["org", "title"],
34
+ helpValue: "<organisation name>",
35
+ }),
36
+ title: Flags.string({
37
+ char: "t",
38
+ description: "name of the campaign, % for wildchar",
39
+ helpValue: "<campaign title>",
40
+ }),
41
+ stats: Flags.boolean({
42
+ description: "display the stats",
43
+ default: true,
44
+ allowNo: true,
45
+ }),
46
+ };
47
+
48
+ OrgSearch = async (name) => {
49
+ const SearchCampaignsDocument = gql`
45
50
  query SearchCampaigns($org: String!, $withStats: Boolean = false) {
46
51
  org (name:$org) {
47
52
  campaigns {
@@ -55,16 +60,16 @@ export default class CampaignList extends Command {
55
60
  ${FragmentOrg}
56
61
  ${FragmentSummary}
57
62
  `;
58
- const result = await query(SearchCampaignsDocument, {
59
- org: name,
60
- withStats: this.flags.stats,
61
- });
62
- return result.org.campaigns;
63
- //return result.campaigns.map (d => {d.config = JSON.parse(d.config); return d});
64
- };
65
-
66
- Search = async (title) => {
67
- const SearchCampaignsDocument = gql`
63
+ const result = await query(SearchCampaignsDocument, {
64
+ org: name,
65
+ withStats: this.flags.stats,
66
+ });
67
+ return result.org.campaigns;
68
+ //return result.campaigns.map (d => {d.config = JSON.parse(d.config); return d});
69
+ };
70
+
71
+ Search = async (title) => {
72
+ const SearchCampaignsDocument = gql`
68
73
  query SearchCampaigns($title: String!, $withStats: Boolean = false) {
69
74
  campaigns(title: $title) {
70
75
  ...Summary
@@ -76,81 +81,81 @@ export default class CampaignList extends Command {
76
81
  ${FragmentOrg}
77
82
  ${FragmentSummary}
78
83
  `;
79
- const result = await query(SearchCampaignsDocument, {
80
- title: title,
81
- withStats: this.flags.stats,
82
- });
83
- return result.campaigns;
84
- //return result.campaigns.map (d => {d.config = JSON.parse(d.config); return d});
85
- };
86
-
87
- simplify = (d) => {
88
- const result = {
89
- id: d.id,
90
- Name: d.name,
91
- Title: d.title,
92
- Org: d.org.name,
93
- Status: d.status,
94
- };
95
- if (this.flags.stats) {
96
- result["#Supporters"] = d.stats.supporterCount;
97
-
98
- this.actionTypes.forEach((type) => {
99
- const action = d.stats.actionCount.find(
100
- (action) => action.actionType === type,
101
- );
102
- if (action) result[`#${type}`] = action.count;
103
- });
104
- }
105
- return result;
106
- };
107
-
108
- table = (r) => {
109
- super.table(r, null, (table) => table.sort(["id|des"]).toString());
110
- };
111
-
112
- async run() {
113
- const { args, flags } = await this.parse(CampaignList);
114
- let data = [];
115
-
116
- if (args.title && flags.title) {
117
- throw new Error(
118
- `${this.id} EITHER [title of the campaign] OR --title [title of the campaign]`,
119
- );
120
- }
121
- if (args.title) {
122
- flags.title = args.title;
123
- }
124
-
125
- if (!flags.title && !flags.org) {
126
- throw new Error(
127
- `${this.id} -t [title of the campaign] or -o [organisation]`,
128
- );
129
- }
130
-
131
- if (flags.title) {
132
- data = await this.Search(flags.title);
133
- if (this.flags.stats) {
134
- data.forEach((d) => {
135
- d.stats.actionCount.forEach((d) => {
136
- //skip share_confirmed?
137
- this.actionTypes.add(d.actionType);
138
- });
139
- });
140
- }
141
- }
142
-
143
- if (flags.org) {
144
- data = await this.OrgSearch(flags.org);
145
- if (this.flags.stats) {
146
- data.forEach((d) => {
147
- d.stats.actionCount.forEach((d) => {
148
- //skip share_confirmed?
149
- this.actionTypes.add(d.actionType);
150
- });
151
- });
152
- }
153
- }
154
- return this.output(data);
155
- }
84
+ const result = await query(SearchCampaignsDocument, {
85
+ title: title,
86
+ withStats: this.flags.stats,
87
+ });
88
+ return result.campaigns;
89
+ //return result.campaigns.map (d => {d.config = JSON.parse(d.config); return d});
90
+ };
91
+
92
+ simplify = (d) => {
93
+ const result = {
94
+ id: d.id,
95
+ Name: d.name,
96
+ Title: d.title,
97
+ Org: d.org.name,
98
+ Status: d.status,
99
+ };
100
+ if (this.flags.stats) {
101
+ result["#Supporters"] = d.stats.supporterCount;
102
+
103
+ this.actionTypes.forEach((type) => {
104
+ const action = d.stats.actionCount.find(
105
+ (action) => action.actionType === type,
106
+ );
107
+ if (action) result[`#${type}`] = action.count;
108
+ });
109
+ }
110
+ return result;
111
+ };
112
+
113
+ table = (r) => {
114
+ super.table(r, null, (table) => table.sort(["id|des"]).toString());
115
+ };
116
+
117
+ async run() {
118
+ const { args, flags } = await this.parse(CampaignList);
119
+ let data = [];
120
+
121
+ if (args.title && flags.title) {
122
+ throw new Error(
123
+ `${this.id} EITHER [title of the campaign] OR --title [title of the campaign]`,
124
+ );
125
+ }
126
+ if (args.title) {
127
+ flags.title = args.title;
128
+ }
129
+
130
+ if (!flags.title && !flags.org) {
131
+ throw new Error(
132
+ `${this.id} -t [title of the campaign] or -o [organisation]`,
133
+ );
134
+ }
135
+
136
+ if (flags.title) {
137
+ data = await this.Search(flags.title);
138
+ if (this.flags.stats) {
139
+ data.forEach((d) => {
140
+ d.stats.actionCount.forEach((d) => {
141
+ //skip share_confirmed?
142
+ this.actionTypes.add(d.actionType);
143
+ });
144
+ });
145
+ }
146
+ }
147
+
148
+ if (flags.org) {
149
+ data = await this.OrgSearch(flags.org);
150
+ if (this.flags.stats) {
151
+ data.forEach((d) => {
152
+ d.stats.actionCount.forEach((d) => {
153
+ //skip share_confirmed?
154
+ this.actionTypes.add(d.actionType);
155
+ });
156
+ });
157
+ }
158
+ }
159
+ return this.output(data);
160
+ }
156
161
  }
@@ -1,19 +1,19 @@
1
1
  query SearchCampaigns($name: String!) {
2
- campaigns(name: $name) {
3
- id
4
- name
5
- title
6
- config
7
- }
2
+ campaigns(name: $name) {
3
+ id
4
+ name
5
+ title
6
+ config
7
+ }
8
8
  }
9
9
 
10
10
  query GetOrgCampaigns($org: String!) {
11
- org(name: $org) {
12
- campaigns {
13
- id
14
- name
15
- title
16
- config
17
- }
18
- }
11
+ org(name: $org) {
12
+ campaigns {
13
+ id
14
+ name
15
+ title
16
+ config
17
+ }
18
+ }
19
19
  }
@@ -4,31 +4,31 @@ import Command from "#src/procaCommand.mjs";
4
4
  import { gql, mutation } from "#src/urql.mjs";
5
5
 
6
6
  export default class CampaignStatus extends Command {
7
- static args = this.multiid();
8
- static aliases = ["campaign:close"];
9
-
10
- static examples = [
11
- "<%= config.bin %> <%= command.id %> -name <campaign>",
12
- "<%= config.bin %> <%= command.id %> -i <campaign_id>",
13
- ];
14
-
15
- static isCloseCommand =
16
- process.argv.includes("close") ||
17
- this.commandPath?.includes("close") ||
18
- this.id?.includes("close");
19
-
20
- static flags = {
21
- status: Flags.string({
22
- ...this.flagify({ multiid: true }),
23
- description: "Status to set",
24
- required: true,
25
- default: this.isCloseCommand ? "close" : undefined,
26
- options: ["draft", "live", "closed", "ignored"],
27
- }),
28
- };
29
-
30
- updateStatus = async (props) => {
31
- const Query = gql`
7
+ static args = this.multiid();
8
+ static aliases = ["campaign:close"];
9
+
10
+ static examples = [
11
+ "<%= config.bin %> <%= command.id %> -name <campaign>",
12
+ "<%= config.bin %> <%= command.id %> -i <campaign_id>",
13
+ ];
14
+
15
+ static isCloseCommand =
16
+ process.argv.includes("close") ||
17
+ this.commandPath?.includes("close") ||
18
+ this.id?.includes("close");
19
+
20
+ static flags = {
21
+ status: Flags.string({
22
+ ...this.flagify({ multiid: true }),
23
+ description: "Status to set",
24
+ required: true,
25
+ default: this.isCloseCommand ? "close" : undefined,
26
+ options: ["draft", "live", "closed", "ignored"],
27
+ }),
28
+ };
29
+
30
+ updateStatus = async (props) => {
31
+ const Query = gql`
32
32
  mutation (
33
33
  $id: Int,
34
34
  $name: String
@@ -43,21 +43,21 @@ $status: String!
43
43
  }
44
44
  `;
45
45
 
46
- const result = await mutation(Query, {
47
- // org: props.org,
48
- id: props.id,
49
- name: props.name,
50
- status: props.status.toUpperCase(),
51
- });
46
+ const result = await mutation(Query, {
47
+ // org: props.org,
48
+ id: props.id,
49
+ name: props.name,
50
+ status: props.status.toUpperCase(),
51
+ });
52
52
 
53
- console.log("result", result);
54
- return result.updateCampaign;
55
- };
53
+ console.log("result", result);
54
+ return result.updateCampaign;
55
+ };
56
56
 
57
- async run() {
58
- const { args, flags } = await this.parse();
57
+ async run() {
58
+ const { args, flags } = await this.parse();
59
59
 
60
- const data = await this.updateStatus(flags);
61
- return this.output(data);
62
- }
60
+ const data = await this.updateStatus(flags);
61
+ return this.output(data);
62
+ }
63
63
  }
@@ -0,0 +1,124 @@
1
+ import { Flags } from "@oclif/core";
2
+ import prompts from "prompts";
3
+ import CampaignGet from "#src/commands/campaign/get.mjs";
4
+ import WidgetList from "#src/commands/widget/list.mjs";
5
+ import WidgetUpdate from "#src/commands/widget/update.mjs";
6
+ import Command from "#src/procaCommand.mjs";
7
+
8
+ export default class CampaignWidgetArchive extends Command {
9
+ static args = this.multiid(); // Add this!
10
+
11
+ static description = "Archive all widgets in the campaign by adding suffix";
12
+
13
+ static examples = [
14
+ "<%= config.bin %> <%= command.id %> old_campaign",
15
+ "<%= config.bin %> <%= command.id %> -n old_campaign --suffix _backup",
16
+ "<%= config.bin %> <%= command.id %> old_campaign --dry-run",
17
+ ];
18
+
19
+ static flags = {
20
+ ...this.flagify({ multiid: true }),
21
+ suffix: Flags.string({
22
+ char: "s",
23
+ description: "custom suffix to append (default: _archive)",
24
+ helpValue: "<suffix>",
25
+ default: "_archive",
26
+ }),
27
+ "dry-run": Flags.boolean({
28
+ description: "preview changes without executing",
29
+ default: false,
30
+ }),
31
+ };
32
+
33
+ fetchCampaign = async ({ id, name }) => {
34
+ const campaignGet = new CampaignGet([], this.config);
35
+ return await campaignGet.fetch({ id, name });
36
+ };
37
+
38
+ fetchWidgets = async (campaignName) => {
39
+ const widgetList = new WidgetList([], this.config);
40
+ widgetList.flags = { campaign: campaignName, config: true };
41
+ return await widgetList.fetchCampaign(campaignName);
42
+ };
43
+
44
+ async run() {
45
+ const { flags } = await this.parse();
46
+ const { id, name, suffix, "dry-run": dryRun } = flags;
47
+
48
+ this.log(`Fetching source campaign: ${name || id}`);
49
+ const campaign = await this.fetchCampaign({ id, name });
50
+
51
+ if (!campaign) {
52
+ this.error("Campaign not found");
53
+ return;
54
+ }
55
+
56
+ this.log(`Fetching widgets for campaign: ${campaign.name}`);
57
+ const widgets = await this.fetchWidgets(campaign.name);
58
+
59
+ if (!widgets || widgets.length === 0) {
60
+ this.warn("No widgets found for this campaign");
61
+ return;
62
+ }
63
+
64
+ this.log(`Found ${widgets.length} widgets`);
65
+
66
+ const renameList = widgets.map((widget) => ({
67
+ id: widget.id,
68
+ oldName: widget.name,
69
+ newName: `${widget.name}${suffix}`,
70
+ locale: widget.locale,
71
+ }));
72
+
73
+ this.log("\nArchive plan:");
74
+ this.table(renameList);
75
+
76
+ if (dryRun) {
77
+ this.log("\n[DRY RUN] No changes made");
78
+ return renameList;
79
+ }
80
+
81
+ // Confirm before proceeding
82
+ const response = await prompts({
83
+ type: "confirm",
84
+ name: "proceed",
85
+ message: `Archive ${renameList.length} widgets by adding suffix "${suffix}"?`,
86
+ initial: false,
87
+ });
88
+
89
+ if (!response.proceed) {
90
+ this.log("Cancelled");
91
+ return;
92
+ }
93
+
94
+ const widgetUpdate = new WidgetUpdate([], this.config);
95
+ const results = [];
96
+
97
+ for (const item of renameList) {
98
+ try {
99
+ this.log(`Archiving: ${item.oldName} → ${item.newName}`);
100
+ const input = {
101
+ name: item.newName,
102
+ locale: item.locale,
103
+ };
104
+ const result = await widgetUpdate.update(item.id, input);
105
+ results.push({
106
+ id: result.id,
107
+ name: result.name,
108
+ status: "success",
109
+ });
110
+ } catch (error) {
111
+ this.error(`Failed to archive ${item.oldName}: ${error.message}`);
112
+ results.push({
113
+ id: item.id,
114
+ name: item.oldName,
115
+ status: "failed",
116
+ error: error.message,
117
+ });
118
+ }
119
+ }
120
+
121
+ this.log("\nArchive complete!");
122
+ return this.output(results);
123
+ }
124
+ }