diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json
index 6445e0ff6d..89832a2d3f 100644
--- a/webapp/i18n/en.json
+++ b/webapp/i18n/en.json
@@ -143,13 +143,16 @@
"DUU48k": "There is no task explicitly assigned to you. You can expand your search using the filters.",
"DXACD6": "Publish retrospective report and access the timeline",
"DaHpK1": "Search for a channel",
+ "Dm4qf7": "What would you like AI to do next?",
"DnBhRg": "Add People",
"DqTQOp": "Once",
"DtCplA": "{numParticipants, plural, =1 {# participant} other {# participants}}",
+ "EI6ktT": "Generate update with AI",
"EQpfkS": "Finished",
"EVSn9A": "Start a run",
"EWz2w5": "Run Playbook",
"Edy3wX": "Checklist moved to {channel}",
+ "EeeJRA": "Accept and insert generated content",
"Ek1Fx2": "When a message with these keywords is posted",
"EvBQLq": "Make Playbook Admin",
"F4pfM/": "Please enter a number, or leave the target blank.",
@@ -162,6 +165,7 @@
"G/yZLu": "Remove",
"GDCpPr": "Recent status update",
"GG1yhI": "There are templates for a range of use cases and events. You can use a playbook as-is or customize it—then share it with your team.",
+ "GV5peK": "Stop generating",
"GVpA4Q": "Create New Playbook",
"GXjP8g": "All the runs that you can access will show here",
"GZoWl1": "Automate activities for this task",
@@ -203,6 +207,7 @@
"LDYFkN": "Duration (in dd:hh:mm)",
"LI7YlB": "Add details on what this metric is about and how it should be filled in. This description will be available on the retrospective page for each run where values for these metrics will be input.",
"LKu0ex": "Are you sure you want to finish the run {runName} for all participants?",
+ "La5DKn": "Go to previous version",
"LaseGE": "You do not have permission to edit this checklist",
"LfhTNW": "Browse or create Playbooks and Runs",
"LmhSmU": "Confirm Entry Delete",
@@ -222,6 +227,7 @@
"MtrTNy": "Tomorrow",
"MvEydR": "{name} posted a status update",
"MyIJbr": "Contents",
+ "N+Ntft": "version {number} of {total}",
"N1U/QR": "Task state changes",
"N2IrpM": "Confirm",
"N7Ln74": "Rerun",
@@ -360,6 +366,7 @@
"a0hBZ0": "Delete metric",
"a2r7Vb": "Private channel",
"aACJNp": "Run started by {name}",
+ "aCdAsI": "Copy to clipboard",
"aEhjYg": "Outline",
"aWpBzj": "Show more",
"aYIUar": "Thank you!",
@@ -418,6 +425,7 @@
"g0mp+I": "When you convert to a private playbook, membership and run history is preserved. This change is permanent and cannot be undone. Are you sure you want to convert {playbookTitle} to a private playbook?",
"g4IF1x": "There are no runs for this playbook.",
"g9pEhE": "Due",
+ "gDsMz6": "AI Status Update Generator",
"gGcNUr": "You do not have permissions",
"gGtlrk": "Your playbooks",
"gS1i4/": "Mark the task as done",
@@ -497,6 +505,7 @@
"nqVby7": "{numTasksChecked, number} of {numTasks, number} {numTasks, plural, =1 {task} other {tasks}} checked",
"nsd54s": "Confirm disable status updates",
"o+ZEL3": "Published {timestamp}",
+ "o/nFZb": "Regenerate content",
"o2eHmz": "Run finished by {name}",
"o6N9pU": "Run actions",
"oAJsne": "Public playbook",
@@ -536,6 +545,7 @@
"sVlNlY": "Every team's structure is different. You can manage which users in the team can create playbooks.",
"sX5Mn5": "Please enter one webhook per line",
"scYyVv": "Would you like to fill out the retrospective report?",
+ "sjzLbX": "Accept",
"soePYH": "{num_checklists, plural, =0 {no checklists} one {# checklist} other {# checklists}}",
"sqNmlF": "Skip retrospective",
"syEQFE": "Publish",
@@ -560,6 +570,7 @@
"v1SpKO": "Role changes",
"v5/Cox": "Duplicate checklist",
"vDvWJ6": "Try request update with a free trial",
+ "vFb69a": "Go to next version",
"vL4++D": "Track progress and ownership",
"vSMfYU": "Run info",
"viXE32": "Private",
diff --git a/webapp/package-lock.json b/webapp/package-lock.json
index 6f935f380e..ea792f2a00 100644
--- a/webapp/package-lock.json
+++ b/webapp/package-lock.json
@@ -7,7 +7,7 @@
"dependencies": {
"@apollo/client": "3.7.3",
"@floating-ui/react-dom-interactions": "0.6.3",
- "@mattermost/compass-icons": "0.1.32",
+ "@mattermost/compass-icons": "0.1.47",
"@mattermost/types": "7.1.0",
"@mdi/js": "^6.5.95",
"@mdi/react": "1.5.0",
@@ -424,7 +424,6 @@
"node_modules/@babel/compat-data": {
"version": "7.16.4",
"integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==",
- "dev": true,
"engines": {
"node": ">=6.9.0"
}
@@ -432,7 +431,6 @@
"node_modules/@babel/core": {
"version": "7.16.7",
"integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==",
- "dev": true,
"dependencies": {
"@babel/code-frame": "^7.16.7",
"@babel/generator": "^7.16.7",
@@ -496,7 +494,6 @@
"node_modules/@babel/helper-compilation-targets": {
"version": "7.16.7",
"integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==",
- "dev": true,
"dependencies": {
"@babel/compat-data": "^7.16.4",
"@babel/helper-validator-option": "^7.16.7",
@@ -640,7 +637,6 @@
"node_modules/@babel/helper-module-transforms": {
"version": "7.16.7",
"integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==",
- "dev": true,
"dependencies": {
"@babel/helper-environment-visitor": "^7.16.7",
"@babel/helper-module-imports": "^7.16.7",
@@ -705,7 +701,6 @@
"node_modules/@babel/helper-simple-access": {
"version": "7.16.7",
"integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==",
- "dev": true,
"dependencies": {
"@babel/types": "^7.16.7"
},
@@ -753,7 +748,6 @@
"node_modules/@babel/helper-validator-option": {
"version": "7.16.7",
"integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==",
- "dev": true,
"engines": {
"node": ">=6.9.0"
}
@@ -775,7 +769,6 @@
"node_modules/@babel/helpers": {
"version": "7.16.7",
"integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==",
- "dev": true,
"dependencies": {
"@babel/template": "^7.16.7",
"@babel/traverse": "^7.16.7",
@@ -5130,9 +5123,9 @@
}
},
"node_modules/@mattermost/compass-icons": {
- "version": "0.1.32",
- "resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.32.tgz",
- "integrity": "sha512-SruyY3dJUGoOCuc5M7KkpFZgotfmeV5Osi+nrMObRdTmaLfJ8h9Q6ZueLx4k4LkLt7hW0CAl33pWc6jO7p3egQ=="
+ "version": "0.1.47",
+ "resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.47.tgz",
+ "integrity": "sha512-vI4j1m/B9qQu51g5YnMQBft8gDh/ZWp3JHBgZXJwb522uY2o6WjwOpCbFwdJxWnD2uq/N2D9wDNmdutJNddf+w=="
},
"node_modules/@mattermost/types": {
"version": "7.1.0",
@@ -5692,8 +5685,7 @@
},
"node_modules/@types/node": {
"version": "14.18.5",
- "integrity": "sha512-LMy+vDDcQR48EZdEx5wRX1q/sEl6NdGuHXPnfeL8ixkwCOSZ2qnIyIZmcCbdX0MeRqHhAcHmX+haCbrS8Run+A==",
- "dev": true
+ "integrity": "sha512-LMy+vDDcQR48EZdEx5wRX1q/sEl6NdGuHXPnfeL8ixkwCOSZ2qnIyIZmcCbdX0MeRqHhAcHmX+haCbrS8Run+A=="
},
"node_modules/@types/parse-json": {
"version": "4.0.0",
@@ -7611,7 +7603,6 @@
"node_modules/browserslist": {
"version": "4.19.1",
"integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==",
- "dev": true,
"dependencies": {
"caniuse-lite": "^1.0.30001286",
"electron-to-chromium": "^1.4.17",
@@ -7744,7 +7735,6 @@
"node_modules/caniuse-lite": {
"version": "1.0.30001296",
"integrity": "sha512-WfrtPEoNSoeATDlf4y3QvkwiELl9GyPLISV5GejTbbQRtQx4LhsXmc9IQ6XCL2d7UxCyEzToEZNMeqR79OUw8Q==",
- "dev": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
@@ -8992,8 +8982,7 @@
},
"node_modules/electron-to-chromium": {
"version": "1.4.37",
- "integrity": "sha512-XIvFB1omSAxYgHYX48sC+HR8i/p7lx7R+0cX9faElg1g++h9IilCrJ12+bQuY+d96Wp7zkBiJwMOv+AhLtLrTg==",
- "dev": true
+ "integrity": "sha512-XIvFB1omSAxYgHYX48sC+HR8i/p7lx7R+0cX9faElg1g++h9IilCrJ12+bQuY+d96Wp7zkBiJwMOv+AhLtLrTg=="
},
"node_modules/elliptic": {
"version": "6.5.4",
@@ -9146,7 +9135,6 @@
"node_modules/escalade": {
"version": "3.1.1",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
- "dev": true,
"engines": {
"node": ">=6"
}
@@ -10541,7 +10529,6 @@
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
- "dev": true,
"engines": {
"node": ">=6.9.0"
}
@@ -10795,7 +10782,7 @@
"version": "5.11.2",
"resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.11.2.tgz",
"integrity": "sha512-4EiZ3/UXYcjm+xFGP544/yW1+DVI8ZpKASFbzrV5EDTFWJp0ZvLl4Dy2fSZAzz9imKp5pZMIcjB0x/H69Pv/6w==",
- "dev": true,
+ "devOptional": true,
"engines": {
"node": ">=10"
},
@@ -13855,7 +13842,6 @@
"node_modules/json5": {
"version": "2.2.0",
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
- "dev": true,
"dependencies": {
"minimist": "^1.2.5"
},
@@ -15434,8 +15420,7 @@
},
"node_modules/node-releases": {
"version": "2.0.1",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==",
- "dev": true
+ "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
},
"node_modules/normalize-path": {
"version": "3.0.0",
@@ -16017,8 +16002,7 @@
},
"node_modules/picocolors": {
"version": "1.0.0",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
- "dev": true
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"node_modules/picomatch": {
"version": "2.3.1",
@@ -17635,7 +17619,6 @@
"node_modules/semver": {
"version": "6.3.0",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true,
"bin": {
"semver": "bin/semver.js"
}
@@ -20255,13 +20238,11 @@
},
"@babel/compat-data": {
"version": "7.16.4",
- "integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==",
- "dev": true
+ "integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q=="
},
"@babel/core": {
"version": "7.16.7",
"integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==",
- "dev": true,
"requires": {
"@babel/code-frame": "^7.16.7",
"@babel/generator": "^7.16.7",
@@ -20309,7 +20290,6 @@
"@babel/helper-compilation-targets": {
"version": "7.16.7",
"integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==",
- "dev": true,
"requires": {
"@babel/compat-data": "^7.16.4",
"@babel/helper-validator-option": "^7.16.7",
@@ -20411,7 +20391,6 @@
"@babel/helper-module-transforms": {
"version": "7.16.7",
"integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==",
- "dev": true,
"requires": {
"@babel/helper-environment-visitor": "^7.16.7",
"@babel/helper-module-imports": "^7.16.7",
@@ -20461,7 +20440,6 @@
"@babel/helper-simple-access": {
"version": "7.16.7",
"integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==",
- "dev": true,
"requires": {
"@babel/types": "^7.16.7"
}
@@ -20493,8 +20471,7 @@
},
"@babel/helper-validator-option": {
"version": "7.16.7",
- "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==",
- "dev": true
+ "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ=="
},
"@babel/helper-wrap-function": {
"version": "7.16.7",
@@ -20510,7 +20487,6 @@
"@babel/helpers": {
"version": "7.16.7",
"integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==",
- "dev": true,
"requires": {
"@babel/template": "^7.16.7",
"@babel/traverse": "^7.16.7",
@@ -22515,7 +22491,8 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.3.0.tgz",
"integrity": "sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"has-flag": {
"version": "4.0.0",
@@ -22566,7 +22543,8 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"yargs": {
"version": "17.3.1",
@@ -22869,7 +22847,8 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
- "dev": true
+ "dev": true,
+ "requires": {}
}
}
},
@@ -22942,7 +22921,8 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
- "dev": true
+ "dev": true,
+ "requires": {}
}
}
},
@@ -23169,7 +23149,8 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
- "dev": true
+ "dev": true,
+ "requires": {}
}
}
},
@@ -23208,7 +23189,8 @@
},
"@graphql-typed-document-node/core": {
"version": "3.1.1",
- "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg=="
+ "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==",
+ "requires": {}
},
"@guyplusplus/turndown-plugin-gfm": {
"version": "1.0.7",
@@ -23249,7 +23231,8 @@
},
"@icons/material": {
"version": "0.2.4",
- "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw=="
+ "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==",
+ "requires": {}
},
"@istanbuljs/load-nyc-config": {
"version": "1.1.0",
@@ -23798,14 +23781,15 @@
}
},
"@mattermost/compass-icons": {
- "version": "0.1.32",
- "resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.32.tgz",
- "integrity": "sha512-SruyY3dJUGoOCuc5M7KkpFZgotfmeV5Osi+nrMObRdTmaLfJ8h9Q6ZueLx4k4LkLt7hW0CAl33pWc6jO7p3egQ=="
+ "version": "0.1.47",
+ "resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.47.tgz",
+ "integrity": "sha512-vI4j1m/B9qQu51g5YnMQBft8gDh/ZWp3JHBgZXJwb522uY2o6WjwOpCbFwdJxWnD2uq/N2D9wDNmdutJNddf+w=="
},
"@mattermost/types": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@mattermost/types/-/types-7.1.0.tgz",
- "integrity": "sha512-SVw5oDXwflNdXUWzl3QuTT5npEddglq6bB+kqdHjowPopOv1Fxi4zJh08/LvaRJYQENEk1QnEVIRTNhnoV0/tg=="
+ "integrity": "sha512-SVw5oDXwflNdXUWzl3QuTT5npEddglq6bB+kqdHjowPopOv1Fxi4zJh08/LvaRJYQENEk1QnEVIRTNhnoV0/tg==",
+ "requires": {}
},
"@mdi/js": {
"version": "6.5.95",
@@ -23907,7 +23891,8 @@
"@restart/context": {
"version": "2.1.4",
"integrity": "sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"@restart/hooks": {
"version": "0.3.27",
@@ -24261,8 +24246,7 @@
},
"@types/node": {
"version": "14.18.5",
- "integrity": "sha512-LMy+vDDcQR48EZdEx5wRX1q/sEl6NdGuHXPnfeL8ixkwCOSZ2qnIyIZmcCbdX0MeRqHhAcHmX+haCbrS8Run+A==",
- "dev": true
+ "integrity": "sha512-LMy+vDDcQR48EZdEx5wRX1q/sEl6NdGuHXPnfeL8ixkwCOSZ2qnIyIZmcCbdX0MeRqHhAcHmX+haCbrS8Run+A=="
},
"@types/parse-json": {
"version": "4.0.0",
@@ -24908,7 +24892,8 @@
"@webpack-cli/configtest": {
"version": "1.1.0",
"integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"@webpack-cli/info": {
"version": "1.4.0",
@@ -24921,7 +24906,8 @@
"@webpack-cli/serve": {
"version": "1.6.0",
"integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"@whatwg-node/fetch": {
"version": "0.5.4",
@@ -25022,13 +25008,15 @@
"acorn-import-assertions": {
"version": "1.8.0",
"integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"acorn-jsx": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"acorn-walk": {
"version": "7.2.0",
@@ -25103,7 +25091,8 @@
"ajv-keywords": {
"version": "3.5.2",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"ansi-escapes": {
"version": "4.3.2",
@@ -25816,7 +25805,6 @@
"browserslist": {
"version": "4.19.1",
"integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==",
- "dev": true,
"requires": {
"caniuse-lite": "^1.0.30001286",
"electron-to-chromium": "^1.4.17",
@@ -25909,8 +25897,7 @@
},
"caniuse-lite": {
"version": "1.0.30001296",
- "integrity": "sha512-WfrtPEoNSoeATDlf4y3QvkwiELl9GyPLISV5GejTbbQRtQx4LhsXmc9IQ6XCL2d7UxCyEzToEZNMeqR79OUw8Q==",
- "dev": true
+ "integrity": "sha512-WfrtPEoNSoeATDlf4y3QvkwiELl9GyPLISV5GejTbbQRtQx4LhsXmc9IQ6XCL2d7UxCyEzToEZNMeqR79OUw8Q=="
},
"capital-case": {
"version": "1.0.4",
@@ -25971,7 +25958,8 @@
"chartjs-plugin-annotation": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/chartjs-plugin-annotation/-/chartjs-plugin-annotation-2.1.2.tgz",
- "integrity": "sha512-kmEp2WtpogwnKKnDPO3iO3mVwvVGtmG5BkZVtAEZm5YzJ9CYxojjYEgk7OTrFbJ5vU098b84UeJRe8kRfNcq5g=="
+ "integrity": "sha512-kmEp2WtpogwnKKnDPO3iO3mVwvVGtmG5BkZVtAEZm5YzJ9CYxojjYEgk7OTrFbJ5vU098b84UeJRe8kRfNcq5g==",
+ "requires": {}
},
"chokidar": {
"version": "3.5.2",
@@ -26899,8 +26887,7 @@
},
"electron-to-chromium": {
"version": "1.4.37",
- "integrity": "sha512-XIvFB1omSAxYgHYX48sC+HR8i/p7lx7R+0cX9faElg1g++h9IilCrJ12+bQuY+d96Wp7zkBiJwMOv+AhLtLrTg==",
- "dev": true
+ "integrity": "sha512-XIvFB1omSAxYgHYX48sC+HR8i/p7lx7R+0cX9faElg1g++h9IilCrJ12+bQuY+d96Wp7zkBiJwMOv+AhLtLrTg=="
},
"elliptic": {
"version": "6.5.4",
@@ -27021,8 +27008,7 @@
},
"escalade": {
"version": "3.1.1",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
- "dev": true
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
},
"escape-html": {
"version": "1.0.3",
@@ -27514,7 +27500,8 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-import-newlines/-/eslint-plugin-import-newlines-1.3.0.tgz",
"integrity": "sha512-8rokf6NvxC10ugA1VNmzEIO75CzId7IDF3Ai2GNXl0Xr4VORpb8u+bxsjRuE+2BS8MfDbrK/MHUQZI2G9qQyyA==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"eslint-plugin-no-relative-import-paths": {
"version": "1.5.0",
@@ -27565,7 +27552,8 @@
"eslint-plugin-react-hooks": {
"version": "4.3.0",
"integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"eslint-plugin-unused-imports": {
"version": "2.0.0",
@@ -28069,8 +28057,7 @@
},
"gensync": {
"version": "1.0.0-beta.2",
- "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
- "dev": true
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="
},
"get-caller-file": {
"version": "2.0.5",
@@ -28217,7 +28204,8 @@
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.2.0.tgz",
"integrity": "sha512-NkANeMnaHrlaSSlpKGyvn2R4rqUDeE/9E5YHx+b4nwo0R8dZyAqcih8/gxpCZvqWP9Vf6xuLpMSzSgdVEIM78g==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"minimatch": {
"version": "4.2.1",
@@ -28253,7 +28241,8 @@
"version": "5.11.2",
"resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.11.2.tgz",
"integrity": "sha512-4EiZ3/UXYcjm+xFGP544/yW1+DVI8ZpKASFbzrV5EDTFWJp0ZvLl4Dy2fSZAzz9imKp5pZMIcjB0x/H69Pv/6w==",
- "dev": true
+ "devOptional": true,
+ "requires": {}
},
"handle-thing": {
"version": "2.0.1",
@@ -28574,7 +28563,8 @@
"icss-utils": {
"version": "5.1.0",
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"identity-obj-proxy": {
"version": "3.0.0",
@@ -29080,7 +29070,8 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz",
"integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"istanbul-lib-coverage": {
"version": "3.2.0",
@@ -29815,7 +29806,8 @@
"jest-pnp-resolver": {
"version": "1.2.2",
"integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"jest-regex-util": {
"version": "27.4.0",
@@ -30476,7 +30468,6 @@
"json5": {
"version": "2.2.0",
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
- "dev": true,
"requires": {
"minimist": "^1.2.5"
}
@@ -31377,7 +31368,8 @@
"redux-thunk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz",
- "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q=="
+ "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==",
+ "requires": {}
},
"sass": {
"version": "1.56.1",
@@ -31483,7 +31475,8 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/meros/-/meros-1.2.1.tgz",
"integrity": "sha512-R2f/jxYqCAGI19KhAvaxSOxALBMkaXWH2a7rOyqQw+ZmizX5bKkEYWLzdhC+U82ZVVPVp6MCXe3EkVligh+12g==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"methods": {
"version": "1.1.2",
@@ -31707,8 +31700,7 @@
},
"node-releases": {
"version": "2.0.1",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==",
- "dev": true
+ "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
},
"normalize-path": {
"version": "3.0.0",
@@ -32133,8 +32125,7 @@
},
"picocolors": {
"version": "1.0.0",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
- "dev": true
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"picomatch": {
"version": "2.3.1",
@@ -32234,7 +32225,8 @@
"postcss-modules-extract-imports": {
"version": "3.0.0",
"integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"postcss-modules-local-by-default": {
"version": "4.0.0",
@@ -32537,7 +32529,8 @@
"react-chartjs-2": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-4.3.1.tgz",
- "integrity": "sha512-5i3mjP6tU7QSn0jvb8I4hudTzHJqS8l00ORJnVwI2sYu0ihpj83Lv2YzfxunfxTZkscKvZu2F2w9LkwNBhj6xA=="
+ "integrity": "sha512-5i3mjP6tU7QSn0jvb8I4hudTzHJqS8l00ORJnVwI2sYu0ihpj83Lv2YzfxunfxTZkscKvZu2F2w9LkwNBhj6xA==",
+ "requires": {}
},
"react-color": {
"version": "2.19.3",
@@ -32896,7 +32889,8 @@
},
"react-universal-interface": {
"version": "0.6.2",
- "integrity": "sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw=="
+ "integrity": "sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==",
+ "requires": {}
},
"react-use": {
"version": "17.3.2",
@@ -32927,7 +32921,8 @@
"react-virtualized-auto-sizer": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.7.tgz",
- "integrity": "sha512-Mxi6lwOmjwIjC1X4gABXMJcKHsOo0xWl3E3ugOgufB8GJU+MqrtY35aBuvCYv/razQ1Vbp7h1gWJjGjoNN5pmA=="
+ "integrity": "sha512-Mxi6lwOmjwIjC1X4gABXMJcKHsOo0xWl3E3ugOgufB8GJU+MqrtY35aBuvCYv/razQ1Vbp7h1gWJjGjoNN5pmA==",
+ "requires": {}
},
"react-window": {
"version": "1.8.8",
@@ -32941,7 +32936,8 @@
"react-window-infinite-loader": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/react-window-infinite-loader/-/react-window-infinite-loader-1.0.8.tgz",
- "integrity": "sha512-907ZLAiZZfBHuZyiY0V7uiSL4P/rI6UQyCF9wES1cDWTeyNLgGLaxu+BZkcUW3R5tSCQcbCcWBl0jVIpYzrKGQ=="
+ "integrity": "sha512-907ZLAiZZfBHuZyiY0V7uiSL4P/rI6UQyCF9wES1cDWTeyNLgGLaxu+BZkcUW3R5tSCQcbCcWBl0jVIpYzrKGQ==",
+ "requires": {}
},
"reactcss": {
"version": "1.2.3",
@@ -32987,7 +32983,8 @@
},
"redux-batched-actions": {
"version": "0.5.0",
- "integrity": "sha512-6orZWyCnIQXMGY4DUGM0oj0L7oYnwTACsfsru/J7r94RM3P9eS7SORGpr3LCeRCMoIMQcpfKZ7X4NdyFHBS8Eg=="
+ "integrity": "sha512-6orZWyCnIQXMGY4DUGM0oj0L7oYnwTACsfsru/J7r94RM3P9eS7SORGpr3LCeRCMoIMQcpfKZ7X4NdyFHBS8Eg==",
+ "requires": {}
},
"redux-mock-store": {
"version": "1.5.4",
@@ -32999,12 +32996,14 @@
},
"redux-persist": {
"version": "6.0.0",
- "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ=="
+ "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==",
+ "requires": {}
},
"redux-thunk": {
"version": "2.4.1",
"integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"regenerate": {
"version": "1.4.2",
@@ -33326,8 +33325,7 @@
},
"semver": {
"version": "6.3.0",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
},
"send": {
"version": "0.17.2",
@@ -33866,7 +33864,8 @@
"style-loader": {
"version": "3.3.1",
"integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"styled-components": {
"version": "5.3.3",
@@ -34467,11 +34466,13 @@
"use-isomorphic-layout-effect": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
- "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA=="
+ "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==",
+ "requires": {}
},
"use-memo-one": {
"version": "1.1.2",
- "integrity": "sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ=="
+ "integrity": "sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ==",
+ "requires": {}
},
"util-deprecate": {
"version": "1.0.2",
@@ -34874,7 +34875,8 @@
"ws": {
"version": "8.4.0",
"integrity": "sha512-IHVsKe2pjajSUIl4KYMQOdlyliovpEPquKkqbwswulszzI7r0SfQrxnXdWAEqOlDCLrVSJzo+O1hAwdog2sKSQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
}
}
},
@@ -35024,7 +35026,8 @@
"ws": {
"version": "7.5.6",
"integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"xml": {
"version": "1.0.1",
diff --git a/webapp/package.json b/webapp/package.json
index cf0a2a63d6..191a2a0254 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -7,7 +7,7 @@
"dependencies": {
"@apollo/client": "3.7.3",
"@floating-ui/react-dom-interactions": "0.6.3",
- "@mattermost/compass-icons": "0.1.32",
+ "@mattermost/compass-icons": "0.1.47",
"@mattermost/types": "7.1.0",
"@mdi/js": "^6.5.95",
"@mdi/react": "1.5.0",
diff --git a/webapp/src/actions.ts b/webapp/src/actions.ts
index df0f4ef139..5687eacce7 100644
--- a/webapp/src/actions.ts
+++ b/webapp/src/actions.ts
@@ -151,7 +151,7 @@ export function openUpdateRunStatusModal(
hasPermission: boolean,
message?: string,
reminderInSeconds?: number,
- finishRunChecked?: boolean
+ finishRunChecked?: boolean,
) {
return modals.openModal(makeUpdateRunStatusModalDefinition({
playbookRunId,
diff --git a/webapp/src/ai_integration.ts b/webapp/src/ai_integration.ts
new file mode 100644
index 0000000000..cb0d6b2fdc
--- /dev/null
+++ b/webapp/src/ai_integration.ts
@@ -0,0 +1,36 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import {GlobalState} from 'mattermost-webapp/packages/types/src/store';
+import {useSelector} from 'react-redux';
+
+import {Bot, BotSelector, BotsLoaderHook} from './types/ai';
+
+export const aiPluginID = 'mattermost-ai';
+
+export const useAIAvailable = () => {
+ //@ts-ignore plugins state is a thing
+ return useSelector((state) => Boolean(state.plugins?.plugins?.[aiPluginID]));
+};
+
+export const useAIAvailableBots = () => {
+ return useSelector((state) => {
+ //@ts-ignore plugins state is a thing
+ return state['plugins-' + aiPluginID]?.bots || [];
+ });
+};
+
+export const useBotSelector = () => {
+ return useSelector((state) => {
+ //@ts-ignore plugins state is a thing
+ return state['plugins-' + aiPluginID]?.botSelector;
+ });
+};
+
+export const useBotsLoaderHook = () => {
+ return useSelector((state) => {
+ //@ts-ignore plugins state is a thing
+ return state['plugins-' + aiPluginID]?.botsLoaderHook || (() => null);
+ });
+};
+
diff --git a/webapp/src/client.ts b/webapp/src/client.ts
index a0b12fab05..9681dba77d 100644
--- a/webapp/src/client.ts
+++ b/webapp/src/client.ts
@@ -62,6 +62,10 @@ export const setSiteUrl = (url?: string): void => {
apiUrl = `${basePath}/plugins/${manifest.id}/api/v0`;
};
+function playbookRunRoute(playbookRunID: string): string {
+ return `${basePath}/plugins/mattermost-ai/playbook_run/${playbookRunID}`;
+}
+
export const getSiteUrl = (): string => {
return siteURL;
};
@@ -811,3 +815,25 @@ export async function getTeamTopPlaybooks(timeRange: string, page: number, perPa
}
return data as InsightsResponse;
}
+
+export async function generateStatusUpdate(playbookRunID: string, botId: string, instructions: string[], messages: string[]) {
+ const url = `${playbookRunRoute(playbookRunID)}/generate_status`;
+ const response = await fetch(url, Client4.getOptions({
+ method: 'POST',
+ body: JSON.stringify({
+ instructions,
+ messages,
+ bot: botId,
+ }),
+ }));
+
+ if (response.ok) {
+ return;
+ }
+
+ throw new ClientError(Client4.url, {
+ message: '',
+ status_code: response.status,
+ url,
+ });
+}
diff --git a/webapp/src/components/assets/buttons.tsx b/webapp/src/components/assets/buttons.tsx
index 05b62eade8..b8496023cb 100644
--- a/webapp/src/components/assets/buttons.tsx
+++ b/webapp/src/components/assets/buttons.tsx
@@ -154,6 +154,31 @@ export const InvertedTertiaryButton = styled(Button)`
}
`;
+export const QuaternaryButton = styled(Button)`
+ transition: all 0.15s ease-out;
+
+ && {
+ color: var(--center-channel-color-64);
+ background-color: rgba(var(--center-channel-color-rgb), 0.08);
+ }
+
+ &&:hover:not([disabled]) {
+ color: var(--center-channel-color-75);
+ background-color: rgba(var(--center-channel-color-rgb), 0.12);
+ }
+
+ &&:active:not([disabled]) {
+ color: var(--button-bg-rgb);
+ background: rgba(var(--button-bg-rgb), 0.16);
+ }
+
+ &&:focus:not([disabled]) {
+ color: var(--button-bg-rgb);
+ background-color: rgba(var(--button-color-rgb), 0.08);
+ box-shadow: inset 0px 0px 0px 2px var(--sidebar-text-active-border-rgb);
+ }
+`;
+
export const SecondaryButton = styled(TertiaryButton)`
background: var(--button-color-rgb);
border: 1px solid var(--button-bg);
diff --git a/webapp/src/components/assets/icons/ai.tsx b/webapp/src/components/assets/icons/ai.tsx
new file mode 100644
index 0000000000..57983df6a8
--- /dev/null
+++ b/webapp/src/components/assets/icons/ai.tsx
@@ -0,0 +1,34 @@
+import React from 'react';
+
+import Svg from 'src/components/assets/svg';
+
+interface Props {
+ size?: number;
+}
+
+const IconAI = ({size = 16}: Props) => (
+
+
+);
+
+export default IconAI;
diff --git a/webapp/src/components/markdown_textbox.tsx b/webapp/src/components/markdown_textbox.tsx
index 227ef27acd..926bc332c6 100644
--- a/webapp/src/components/markdown_textbox.tsx
+++ b/webapp/src/components/markdown_textbox.tsx
@@ -35,6 +35,7 @@ type Props = {
hideHelpBar?: boolean;
previewByDefault?: boolean;
autoFocus?: boolean;
+ minHeight?: string;
} & ComponentProps;
const MarkdownTextbox = ({
@@ -48,6 +49,7 @@ const MarkdownTextbox = ({
previewByDefault,
autoFocus,
hideHelpBar,
+ minHeight = '104px',
...textboxProps
}: Props) => {
const [showPreview, setShowPreview] = useState(previewByDefault);
@@ -63,7 +65,10 @@ const MarkdownTextbox = ({
});
return (
-
+
`
.textarea-wrapper {
margin-bottom: 6px;
}
@@ -121,7 +126,7 @@ const Wrapper = styled.div`
}
height: unset;
- min-height: 104px;
+ min-height: ${(props) => props.$minHeight || '104px'};
max-height: 324px;
overflow: auto;
padding: 12px 30px 12px 16px;
diff --git a/webapp/src/components/modals/ai_modal.tsx b/webapp/src/components/modals/ai_modal.tsx
new file mode 100644
index 0000000000..3049b4bf44
--- /dev/null
+++ b/webapp/src/components/modals/ai_modal.tsx
@@ -0,0 +1,427 @@
+import {WebSocketMessage} from '@mattermost/client';
+
+import React, {
+ useCallback,
+ useEffect,
+ useRef,
+ useState,
+} from 'react';
+import styled from 'styled-components';
+import {FormattedMessage, useIntl} from 'react-intl';
+
+import IconAI from 'src/components/assets/icons/ai';
+import GenericModal from 'src/components/widgets/generic_modal';
+import {Textbox} from 'src/webapp_globals';
+
+import {generateStatusUpdate} from 'src/client';
+import {useBotSelector, useBotsLoaderHook} from 'src/ai_integration';
+
+import {Bot} from 'src/types/ai';
+
+import postEventListener, {PostUpdateWebsocketMessage} from 'src/websocket';
+
+const COPY_FEEDBACK_TIMEOUT_MS = 1000;
+const SCROLL_TO_BOTTOM_TIMEOUT_MS = 0;
+
+type Version = {
+ instruction: string
+ prevValue: string
+ value: string
+}
+
+type Props = {
+ playbookRunId: string
+ onAccept: (text: string) => void
+ onClose: () => void
+ isOpen: boolean
+}
+
+const StyledAIModal = styled(GenericModal)`
+ &&& {
+
+ .modal-content {
+ width: 90%;
+ margin-left: 5%;
+ }
+
+ .modal-body {
+ padding: 0 24px;
+ }
+
+ .modal-header .close {
+ z-index: 5;
+ }
+ }
+`;
+
+const AIModal = ({playbookRunId, onAccept, onClose, isOpen}: Props) => {
+ const intl = useIntl();
+ const [copied, setCopied] = useState(false);
+ const [instruction, setInstruction] = useState('');
+ const suggestionBox = useRef(null);
+ const BotSelector = useBotSelector();
+ const useBotlist = useBotsLoaderHook();
+ const {bots, activeBot, setActiveBot} = useBotlist();
+ const [currentVersion, setCurrentVersion] = useState(0);
+ const [versions, setVersions] = useState([]);
+ const [generating, setGenerating] = useState(false);
+
+ useEffect(() => {
+ if (activeBot?.id && isOpen) {
+ setCurrentVersion(versions.length + 1);
+ setVersions([...versions, {instruction: '', value: '', prevValue: ''}]);
+ setGenerating(true);
+ generateStatusUpdate(playbookRunId, activeBot.id, [], []);
+ }
+ }, [isOpen]);
+
+ useEffect(() => {
+ if (generating) {
+ postEventListener.registerPostUpdateListener('playbooks_post_update', (msg: WebSocketMessage) => {
+ const data = msg.data;
+ if (!data.control) {
+ setGenerating(true);
+ const newVersions = [...versions];
+ newVersions[versions.length - 1] = {...newVersions[versions.length - 1], value: data.next};
+ setVersions(newVersions);
+ setTimeout(() => suggestionBox.current?.scrollTo(0, suggestionBox.current?.scrollHeight), SCROLL_TO_BOTTOM_TIMEOUT_MS);
+ } else if (data.control === 'end') {
+ setGenerating(false);
+ }
+ });
+ }
+ return () => {
+ postEventListener.unregisterPostUpdateListener('playbooks_post_update');
+ };
+ }, [generating]);
+
+ const onBotChange = useCallback((bot: Bot) => {
+ setActiveBot(bot);
+ setCurrentVersion(versions.length + 1);
+ setVersions([...versions, {instruction: '', value: '', prevValue: ''}]);
+ setGenerating(true);
+ generateStatusUpdate(playbookRunId, bot.id, [], []);
+ }, [versions, playbookRunId]);
+
+ const regenerate = useCallback(() => {
+ setGenerating(true);
+ generateStatusUpdate(playbookRunId, activeBot?.id, [versions[currentVersion - 1].instruction], [versions[currentVersion - 1].prevValue]);
+ setCurrentVersion(versions.length + 1);
+ setVersions([...versions, {...versions[currentVersion - 1], value: ''}]);
+ }, [versions, playbookRunId, instruction, versions, currentVersion, activeBot?.id]);
+
+ const copyText = useCallback(() => {
+ navigator.clipboard.writeText(versions[currentVersion - 1].value);
+ setCopied(true);
+ setTimeout(() => setCopied(false), COPY_FEEDBACK_TIMEOUT_MS);
+ }, [versions, currentVersion]);
+
+ const onInputEnter = useCallback((e: React.KeyboardEvent) => {
+ // Detect hitting enter and run the generateStatusUpdate
+ if (e.key === 'Enter') {
+ generateStatusUpdate(playbookRunId, activeBot?.id, [instruction], [versions[currentVersion - 1].value]);
+ setVersions([...versions, {instruction, prevValue: versions[currentVersion - 1].value, value: ''}]);
+ setCurrentVersion(versions.length + 1);
+ setInstruction('');
+ setGenerating(true);
+ setTimeout(() => suggestionBox.current?.scrollTo(0, suggestionBox.current?.scrollHeight), SCROLL_TO_BOTTOM_TIMEOUT_MS);
+ }
+ }, [versions, instruction, playbookRunId, versions, currentVersion, activeBot?.id]);
+
+ const stopGenerating = useCallback(() => {
+ setGenerating(false);
+ }, []);
+
+ if (!activeBot?.id) {
+ return null;
+ }
+
+ if (!isOpen) {
+ return null;
+ }
+
+ return (
+
+
+
+
+ setCurrentVersion(currentVersion - 1)}
+ className={currentVersion === 1 ? 'disabled' : ''}
+ aria-label={intl.formatMessage({defaultMessage: 'Go to previous version'})}
+ aria-disabled={currentVersion === 1}
+ >
+
+
+
+ setCurrentVersion(currentVersion + 1)}
+ className={currentVersion === versions.length ? 'disabled' : ''}
+ aria-label={intl.formatMessage({defaultMessage: 'Go to next version'})}
+ aria-disabled={currentVersion === versions.length}
+ >
+
+
+
+
+
+
+
+
+
+ {generating &&
+
+
+
+
+ }
+ {!generating &&
+
+
+
+
+
+
+
+ onAccept(versions[currentVersion - 1].value)}
+ aria-label={intl.formatMessage({defaultMessage: 'Accept and insert generated content'})}
+ >
+
+
+
+
+
+
+
+ }
+
+
+ setInstruction(e.target.value)}
+ value={instruction}
+ onKeyUp={onInputEnter}
+ />
+
+
+
+ );
+};
+
+const IconButton = styled.span`
+ display: inline-block;
+ height: 24px;
+ width: 24px;
+ border-radius: 4px;
+ background: transparent;
+ text-decoration: none;
+ color: var(--center-channel-color-64);
+ padding: 8px;
+ cursor: pointer;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+
+ .icon {
+ font-size: 14.4px;
+ }
+
+ &:hover {
+ background: var(--center-channel-color-08);
+ color: var(--center-channel-color-75);
+ }
+
+ &:active {
+ color: rgba(var(--button-bg-rgb));
+ background: rgba(var(--button-bg-rgb), 0.16);
+ }
+
+ &.disabled {
+ color: var(--center-channel-color-56);
+ pointer-events: none;
+ cursor: not-allowed;
+ }
+`;
+
+const StopGeneratingButton = styled.button`
+ display: inline-flex;
+ margin: 12px 0;
+ align-items: center;
+ gap: 4px;
+ border-radius: 4px;
+ background: rgba(var(--center-channel-color-rgb), 0.08);
+ padding: 0px 10px 0 6px;
+ height: 24px;
+ color: var(--center-channel-color-64);
+ cursor: pointer;
+ text-decoration: none;
+ font-weight: 600;
+ font-size: 11px;
+ text-align: center;
+ border: 0;
+
+ &:hover {
+ background: rgba(var(--center-channel-color-rgb), 0.12);
+ color: var(--center-channel-color-75);
+ }
+
+ &:active {
+ background: rgba(var(--center-channel-color-rgb), 0.16);
+ }
+
+ &:focus {
+ outline: none;
+ }
+`;
+
+const AIModalContainer = styled.div`
+ position: relative;
+ margin-top: -56px;
+ padding-bottom: 24px;
+
+ &&&& textarea {
+ min-height: 250px;
+ max-height: 250px;
+ border: 0;
+ outline: 0;
+ box-shadow: none;
+ &:focus, &:hover, &:active {
+ border: 0;
+ outline: 0;
+ }
+ }
+ .autosize_textarea_placeholder {
+ display: none;
+ }
+`;
+
+const AIModalFooter = styled.div`
+ margin: 12px 0;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ gap: 4px;
+`;
+
+const ExtraInstructionsInput = styled.div`
+ display: flex;
+ width: 100%;
+ padding: 6px 16px;
+ min-height: 40px;
+ border-radius: 4px;
+ border: 1px solid var(--center-channel-color-16);
+ align-items: center;
+ transition: border-color 0.15s ease;
+
+ &:focus-within {
+ border: 2px solid var(--button-bg);
+ padding: 5px 15px; /* Reduce padding by 1px to maintain same size with 2px border */
+ }
+
+ input {
+ font-size: 14px;
+ border: 0px;
+ width: 100%;
+ margin-left: 8px;
+
+ &:focus {
+ outline: none;
+ }
+ }
+
+ svg {
+ color: var(--center-channel-color-64);
+ }
+`;
+
+const InsertButton = styled.button`
+ display: inline-block;
+ border-radius: 4px;
+ background: var(--button-bg-08);
+ padding: 0px 10px 0 6px;
+ height: 24px;
+ color: var(--button-bg);
+ cursor: pointer;
+ text-decoration: none;
+ font-weight: 600;
+ font-size: 11px;
+ text-align: center;
+ border: 0;
+ &:hover {
+ background: var(--button-bg-16);
+ }
+ &:active {
+ background: var(--button-bg-24);
+ }
+ &:focus {
+ outline: none;
+ }
+`;
+
+const AssistantMessageBox = styled.div`
+ max-height: 200px;
+ height: 200px;
+ overflow-y: auto;
+ &&&& .custom-textarea {
+ border: none;
+ box-shadow: none;
+ height: 100%;
+ }
+`;
+
+const Copied = styled.span<{ copied: boolean }>`
+ color: var(--online-indicator);
+ font-weight: 600;
+ margin: 0 4px;
+ font-size: 11px;
+ transition: opacity 1s;
+ opacity: ${(props) => (props.copied ? 1 : 0)};
+`;
+
+const TopBar = styled.div`
+ display: flex;
+ justify-content: space-between;
+ padding-bottom: 12px;
+ margin-right: 24px;
+`;
+
+const Versions = styled.div`
+ display: flex;
+ align-items: center;
+ color: var(--center-channel-color-75);
+ font-size: 12px;
+ gap: 4px;
+ font-weight: 600;
+ flex-grow: 1;
+
+ &.disabled {
+ color: var(--center-channel-color-64);
+ pointer-events: none;
+ }
+`;
+
+export default AIModal;
diff --git a/webapp/src/components/modals/update_run_status_modal.tsx b/webapp/src/components/modals/update_run_status_modal.tsx
index 12c5d0e8ef..43432b46c6 100644
--- a/webapp/src/components/modals/update_run_status_modal.tsx
+++ b/webapp/src/components/modals/update_run_status_modal.tsx
@@ -10,7 +10,7 @@ import React, {
import {Link} from 'react-router-dom';
import {useDispatch, useSelector} from 'react-redux';
import styled from 'styled-components';
-import {useIntl} from 'react-intl';
+import {FormattedMessage, useIntl} from 'react-intl';
import {DateTime, Duration} from 'luxon';
import {GlobalState} from '@mattermost/types/store';
@@ -19,8 +19,13 @@ import {getChannel} from 'mattermost-redux/selectors/entities/channels';
import {ApolloProvider, useQuery} from '@apollo/client';
+import {QuaternaryButton, TertiaryButton} from 'src/components/assets/buttons';
+
import GenericModal, {Description, Label} from 'src/components/widgets/generic_modal';
import UnsavedChangesModal from 'src/components/widgets/unsaved_changes_modal';
+import IconAI from 'src/components/assets/icons/ai';
+import AIModal from 'src/components/modals/ai_modal';
+import {useAIAvailable, useAIAvailableBots} from 'src/ai_integration';
import {
Mode,
@@ -102,6 +107,9 @@ const UpdateRunStatusModal = ({
const dispatch = useDispatch();
const {formatMessage, formatList} = useIntl();
const currentUserId = useSelector(getCurrentUserId);
+ const [aiModalOpen, setAIModalOpen] = useState(false);
+ const aiAvailable = useAIAvailable();
+ const aiAvailableBots = useAIAvailableBots();
const {data} = useQuery(runStatusModalQueryDocument, {
variables: {
runID: playbookRunId,
@@ -258,11 +266,48 @@ const UpdateRunStatusModal = ({
const form = (
{description()}
-
+
+
+ { aiAvailable && aiAvailableBots.length > 0 &&
+ (aiModalOpen ? (
+ {
+ setAIModalOpen(true);
+ }}
+ >
+
+
+
+ ) : (
+ {
+ setAIModalOpen(true);
+ }}
+ >
+
+
+
+ ))
+ }
+
+ { aiAvailable &&
+
+ {
+ setMessage(text);
+ setAIModalOpen(false);
+ }}
+ onClose={() => setAIModalOpen(false)}
+ isOpen={aiModalOpen}
+ />
+
+ }
{hasPermission ? form : warning}
@@ -502,6 +548,7 @@ const FooterContainer = styled.div`
display: flex;
flex-direction: row-reverse;
align-items: center;
+ width: 100%;
`;
const StyledCheckboxInput = styled(CheckboxInput)`
@@ -514,6 +561,28 @@ const StyledCheckboxInput = styled(CheckboxInput)`
}
`;
+const AiModalContainer = styled.div`
+ position: relative;
+ box-shadow: var(--elevation-6);
+`;
+
+const LastChangeSince = styled.div<{disabled: boolean}>`
+ display: flex;
+ justify-content: space-between;
+ pointer-events: ${(props) => (props.disabled ? 'none' : 'auto')};
+
+ >div {
+ margin: 24px 0 8px 0;
+ }
+ >button {
+ margin-top: 20px;
+ height: 24px;
+ gap: 6px;
+ padding: 0 10px;
+ font-size: 12px;
+ }
+`;
+
const ApolloWrappedModal = (props: Props) => {
const client = getPlaybooksGraphQLClient();
return ;
diff --git a/webapp/src/components/widgets/generic_modal.tsx b/webapp/src/components/widgets/generic_modal.tsx
index 1b048d9a05..005b2d1ee9 100644
--- a/webapp/src/components/widgets/generic_modal.tsx
+++ b/webapp/src/components/widgets/generic_modal.tsx
@@ -13,6 +13,7 @@ type Props = {
className?: string;
onHide: () => void;
onExited?: () => void;
+ compassDesign?: boolean;
modalHeaderText?: React.ReactNode;
modalHeaderSideText?: React.ReactNode;
modalHeaderIcon?: React.ReactNode;
@@ -211,7 +212,7 @@ export const ModalHeading = styled.h1`
font-size: 22px;
line-height: 28px;
color: var(--center-channel-color);
- margin: 0;
+ margin: 8px 0 0;
`;
export const ModalSideheading = styled.h6`
diff --git a/webapp/src/index.tsx b/webapp/src/index.tsx
index 6f9c7e21ce..4b2732d8d0 100644
--- a/webapp/src/index.tsx
+++ b/webapp/src/index.tsx
@@ -49,6 +49,7 @@ import {
handleWebsocketUserRemoved,
} from 'src/websocket_events';
import {
+ WEBSOCKET_MATTERMOST_AI_POSTUPDATE,
WEBSOCKET_PLAYBOOK_ARCHIVED,
WEBSOCKET_PLAYBOOK_CREATED,
WEBSOCKET_PLAYBOOK_RESTORED,
@@ -73,6 +74,7 @@ import {setPlaybooksGraphQLClient} from './graphql_client';
import {RHSTitlePlaceholder} from './rhs_title_remote_render';
import {ApolloWrapper, makeGraphqlClient} from './graphql/apollo';
import PresetTemplates from './components/templates/template_data';
+import postEventListener from './websocket';
const GlobalHeaderCenter = () => {
return null;
@@ -239,6 +241,7 @@ export default class Plugin {
registry.registerWebSocketEventHandler(WebsocketEvents.POST_DELETED, handleWebsocketPostEditedOrDeleted(store.getState, store.dispatch));
registry.registerWebSocketEventHandler(WebsocketEvents.POST_EDITED, handleWebsocketPostEditedOrDeleted(store.getState, store.dispatch));
registry.registerWebSocketEventHandler(WebsocketEvents.CHANNEL_UPDATED, handleWebsocketChannelUpdated(store.getState, store.dispatch));
+ registry.registerWebSocketEventHandler(WEBSOCKET_MATTERMOST_AI_POSTUPDATE, postEventListener.handlePostUpdateWebsockets);
// Local slash commands
registry.registerSlashCommandWillBePostedHook(makeSlashCommandHook(store));
diff --git a/webapp/src/manifest.js b/webapp/src/manifest.js
new file mode 100644
index 0000000000..19ec8b232a
--- /dev/null
+++ b/webapp/src/manifest.js
@@ -0,0 +1,47 @@
+// This file is automatically generated. Do not modify it manually.
+
+const manifest = JSON.parse(`
+{
+ "id": "playbooks",
+ "name": "Playbooks",
+ "description": "Mattermost Playbooks enable reliable and repeatable processes for your teams using checklists, automation, and retrospectives.",
+ "homepage_url": "https://github.com/mattermost/mattermost-plugin-playbooks/",
+ "support_url": "https://github.com/mattermost/mattermost-plugin-playbooks/issues",
+ "release_notes_url": "https://github.com/mattermost/mattermost-plugin-playbooks/releases/tag/v1.33.0+alpha.4",
+ "icon_path": "assets/plugin_icon.svg",
+ "version": "1.33.0+alpha.4+29103d5b",
+ "min_server_version": "6.3.0",
+ "server": {
+ "executables": {
+ "darwin-amd64": "server/dist/plugin-darwin-amd64",
+ "darwin-arm64": "server/dist/plugin-darwin-arm64",
+ "linux-amd64": "server/dist/plugin-linux-amd64",
+ "linux-arm64": "server/dist/plugin-linux-arm64",
+ "windows-amd64": "server/dist/plugin-windows-amd64.exe"
+ },
+ "executable": ""
+ },
+ "webapp": {
+ "bundle_path": "webapp/dist/main.js"
+ },
+ "settings_schema": {
+ "header": "",
+ "footer": "",
+ "settings": [
+ {
+ "key": "EnableExperimentalFeatures",
+ "display_name": "Enable Experimental Features:",
+ "type": "bool",
+ "help_text": "Enable experimental features that come with in-progress UI, bugs, and cool stuff.",
+ "placeholder": "",
+ "default": null
+ }
+ ]
+ }
+}
+`);
+
+export default manifest;
+export const id = manifest.id;
+export const version = manifest.version;
+export const pluginId = manifest.id;
diff --git a/webapp/src/types/ai.tsx b/webapp/src/types/ai.tsx
new file mode 100644
index 0000000000..1e06d5d8cf
--- /dev/null
+++ b/webapp/src/types/ai.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+
+export type Bot = {
+ id: string
+}
+
+type BotSelectorProps = {
+ bots: Bot[]
+ activeBot: Bot
+ setActiveBot: (bot: Bot) => void
+}
+
+export type BotsLoaderHook = () => BotSelectorProps
+export type BotSelector = React.FunctionComponent
diff --git a/webapp/src/types/websocket_events.ts b/webapp/src/types/websocket_events.ts
index 9c51582ad8..7dd964923b 100644
--- a/webapp/src/types/websocket_events.ts
+++ b/webapp/src/types/websocket_events.ts
@@ -8,3 +8,4 @@ export const WEBSOCKET_PLAYBOOK_RUN_CREATED = `custom_${manifest.id}_playbook_ru
export const WEBSOCKET_PLAYBOOK_CREATED = `custom_${manifest.id}_playbook_created`;
export const WEBSOCKET_PLAYBOOK_ARCHIVED = `custom_${manifest.id}_playbook_archived`;
export const WEBSOCKET_PLAYBOOK_RESTORED = `custom_${manifest.id}_playbook_restored`;
+export const WEBSOCKET_MATTERMOST_AI_POSTUPDATE = 'custom_mattermost-ai_postupdate';
diff --git a/webapp/src/websocket.tsx b/webapp/src/websocket.tsx
new file mode 100644
index 0000000000..73e204712c
--- /dev/null
+++ b/webapp/src/websocket.tsx
@@ -0,0 +1,30 @@
+import {WebSocketMessage} from '@mattermost/client';
+
+export interface PostUpdateWebsocketMessage {
+ next: string
+ post_id: string
+ control?: string
+}
+
+type WebsocketListener = (msg: WebSocketMessage) => void
+type WebsocketListeners = Map
+
+class PostEventListener {
+ postUpdateWebsocketListeners: WebsocketListeners = new Map();
+
+ public registerPostUpdateListener = (postID: string, listener: WebsocketListener) => {
+ this.postUpdateWebsocketListeners.set(postID, listener);
+ };
+
+ public unregisterPostUpdateListener = (postID: string) => {
+ this.postUpdateWebsocketListeners.delete(postID);
+ };
+
+ public handlePostUpdateWebsockets = (msg: WebSocketMessage) => {
+ const postID = msg.data.post_id;
+ this.postUpdateWebsocketListeners.get(postID)?.(msg);
+ };
+}
+
+const postEventListener = new PostEventListener();
+export default postEventListener;