permission.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. package main
  2. import (
  3. "fmt"
  4. "strconv"
  5. "strings"
  6. ti "github.com/charmbracelet/bubbles/textinput"
  7. tea "github.com/charmbracelet/bubbletea"
  8. "github.com/langgenius/dify-plugin-daemon/internal/types/entities/plugin_entities"
  9. )
  10. var permissionKeySeq = []string{
  11. "tool.enabled",
  12. "model.enabled",
  13. "model.llm",
  14. "model.text_embedding",
  15. "model.rerank",
  16. "model.tts",
  17. "model.speech2text",
  18. "model.moderation",
  19. "app.enabled",
  20. "storage.enabled",
  21. "storage.size",
  22. "endpoint.enabled",
  23. }
  24. type permission struct {
  25. cursor string
  26. permission plugin_entities.PluginPermissionRequirement
  27. storageSizeEditor ti.Model
  28. }
  29. func newPermission() permission {
  30. return permission{
  31. cursor: permissionKeySeq[0],
  32. storageSizeEditor: ti.New(),
  33. }
  34. }
  35. func (p permission) View() string {
  36. cursor := func(key string) string {
  37. if p.cursor == key {
  38. return "→ "
  39. }
  40. return " "
  41. }
  42. checked := func(enabled bool) string {
  43. if enabled {
  44. return fmt.Sprintf("\033[32m%s\033[0m", "[✔]")
  45. }
  46. return fmt.Sprintf("\033[31m%s\033[0m", "[✘]")
  47. }
  48. s := "Configure the permissions of the plugin, use up and down to navigate, enter to select, after selection, press right to move to the next menu\n"
  49. s += "Backwards Invocation:\n"
  50. s += "Tools:\n"
  51. s += fmt.Sprintf(" %sEnabled: %v\n", cursor("tool.enabled"), checked(p.permission.AllowInvokeTool()))
  52. s += "Models:\n"
  53. s += fmt.Sprintf(" %sEnabled: %v\n", cursor("model.enabled"), checked(p.permission.AllowInvokeModel()))
  54. s += fmt.Sprintf(" %sLLM: %v\n", cursor("model.llm"), checked(p.permission.AllowInvokeLLM()))
  55. s += fmt.Sprintf(" %sText Embedding: %v\n", cursor("model.text_embedding"), checked(p.permission.AllowInvokeTextEmbedding()))
  56. s += fmt.Sprintf(" %sRerank: %v\n", cursor("model.rerank"), checked(p.permission.AllowInvokeRerank()))
  57. s += fmt.Sprintf(" %sTTS: %v\n", cursor("model.tts"), checked(p.permission.AllowInvokeTTS()))
  58. s += fmt.Sprintf(" %sSpeech2Text: %v\n", cursor("model.speech2text"), checked(p.permission.AllowInvokeSpeech2Text()))
  59. s += fmt.Sprintf(" %sModeration: %v\n", cursor("model.moderation"), checked(p.permission.AllowInvokeModeration()))
  60. s += "Apps:\n"
  61. s += fmt.Sprintf(" %sEnabled: %v\n", cursor("app.enabled"), checked(p.permission.AllowInvokeApp()))
  62. s += "Resources:\n"
  63. s += "Storage:\n"
  64. s += fmt.Sprintf(" %sEnabled: %v\n", cursor("storage.enabled"), checked(p.permission.AllowInvokeStorage()))
  65. if p.permission.AllowInvokeStorage() {
  66. s += fmt.Sprintf(" %sSize: %v\n", cursor("storage.size"), p.storageSizeEditor.View())
  67. } else {
  68. s += fmt.Sprintf(" %sSize: %v\n", cursor("storage.size"), "N/A")
  69. }
  70. s += "Endpoints:\n"
  71. s += fmt.Sprintf(" %sEnabled: %v\n", cursor("endpoint.enabled"), checked(p.permission.AllowRegistryEndpoint()))
  72. return s
  73. }
  74. func (p *permission) edit() {
  75. if p.cursor == "tool.enabled" {
  76. if p.permission.AllowInvokeTool() {
  77. p.permission.Tool = nil
  78. } else {
  79. p.permission.Tool = &plugin_entities.PluginPermissionToolRequirement{
  80. Enabled: true,
  81. }
  82. }
  83. }
  84. if strings.HasPrefix(p.cursor, "model.") {
  85. if p.permission.AllowInvokeModel() {
  86. if p.cursor == "model.enabled" {
  87. p.permission.Model = nil
  88. return
  89. }
  90. } else {
  91. p.permission.Model = &plugin_entities.PluginPermissionModelRequirement{
  92. Enabled: true,
  93. }
  94. }
  95. }
  96. if p.cursor == "model.llm" {
  97. if p.permission.AllowInvokeLLM() {
  98. p.permission.Model.LLM = false
  99. } else {
  100. p.permission.Model.LLM = true
  101. }
  102. }
  103. if p.cursor == "model.text_embedding" {
  104. if p.permission.AllowInvokeTextEmbedding() {
  105. p.permission.Model.TextEmbedding = false
  106. } else {
  107. p.permission.Model.TextEmbedding = true
  108. }
  109. }
  110. if p.cursor == "model.rerank" {
  111. if p.permission.AllowInvokeRerank() {
  112. p.permission.Model.Rerank = false
  113. } else {
  114. p.permission.Model.Rerank = true
  115. }
  116. }
  117. if p.cursor == "model.tts" {
  118. if p.permission.AllowInvokeTTS() {
  119. p.permission.Model.TTS = false
  120. } else {
  121. p.permission.Model.TTS = true
  122. }
  123. }
  124. if p.cursor == "model.speech2text" {
  125. if p.permission.AllowInvokeSpeech2Text() {
  126. p.permission.Model.Speech2text = false
  127. } else {
  128. p.permission.Model.Speech2text = true
  129. }
  130. }
  131. if p.cursor == "model.moderation" {
  132. if p.permission.AllowInvokeModeration() {
  133. p.permission.Model.Moderation = false
  134. } else {
  135. p.permission.Model.Moderation = true
  136. }
  137. }
  138. if p.cursor == "app.enabled" {
  139. if p.permission.AllowInvokeApp() {
  140. p.permission.App = nil
  141. } else {
  142. p.permission.App = &plugin_entities.PluginPermissionAppRequirement{
  143. Enabled: true,
  144. }
  145. }
  146. }
  147. if p.cursor == "storage.enabled" {
  148. if p.permission.AllowInvokeStorage() {
  149. p.permission.Storage = nil
  150. } else {
  151. p.permission.Storage = &plugin_entities.PluginPermissionStorageRequirement{
  152. Enabled: true,
  153. Size: 1048576,
  154. }
  155. }
  156. }
  157. if p.cursor == "endpoint.enabled" {
  158. if p.permission.AllowRegistryEndpoint() {
  159. p.permission.Endpoint = nil
  160. } else {
  161. p.permission.Endpoint = &plugin_entities.PluginPermissionEndpointRequirement{
  162. Enabled: true,
  163. }
  164. }
  165. }
  166. }
  167. func (p *permission) updateStorageSize() {
  168. if p.cursor == "storage.size" {
  169. // set the storage size editor to the current storage size
  170. if p.permission.AllowInvokeStorage() {
  171. p.storageSizeEditor.SetValue(fmt.Sprintf("%d", p.permission.Storage.Size))
  172. p.storageSizeEditor.Focus()
  173. }
  174. } else {
  175. p.storageSizeEditor.Blur()
  176. // get the storage size from the editor
  177. if p.permission.AllowInvokeStorage() {
  178. p.permission.Storage.Size, _ = strconv.ParseUint(p.storageSizeEditor.Value(), 10, 64)
  179. }
  180. }
  181. }
  182. func (p permission) Update(msg tea.Msg) (subMenu, subMenuEvent, tea.Cmd) {
  183. switch msg := msg.(type) {
  184. case tea.KeyMsg:
  185. switch msg.String() {
  186. case "ctrl+c":
  187. return p, SUB_MENU_EVENT_NONE, tea.Quit
  188. case "down":
  189. // find the next key in the permissionKeySeq
  190. for i, key := range permissionKeySeq {
  191. if key == p.cursor {
  192. if i == len(permissionKeySeq)-1 {
  193. p.cursor = permissionKeySeq[0]
  194. } else {
  195. p.cursor = permissionKeySeq[i+1]
  196. }
  197. p.updateStorageSize()
  198. break
  199. }
  200. }
  201. case "up":
  202. // find the previous key in the permissionKeySeq
  203. for i, key := range permissionKeySeq {
  204. if key == p.cursor {
  205. if i == 0 {
  206. p.cursor = permissionKeySeq[len(permissionKeySeq)-1]
  207. } else {
  208. p.cursor = permissionKeySeq[i-1]
  209. }
  210. p.updateStorageSize()
  211. break
  212. }
  213. }
  214. case "enter":
  215. p.edit()
  216. case "right":
  217. if p.cursor == "storage.size" {
  218. break
  219. }
  220. p.cursor = permissionKeySeq[0]
  221. p.updateStorageSize()
  222. return p, SUB_MENU_EVENT_NEXT, nil
  223. }
  224. }
  225. // update storage size editor
  226. if p.cursor == "storage.size" {
  227. if p.storageSizeEditor.Focused() {
  228. // check if msg is a number
  229. model, cmd := p.storageSizeEditor.Update(msg)
  230. p.storageSizeEditor = model
  231. return p, SUB_MENU_EVENT_NONE, cmd
  232. }
  233. }
  234. return p, SUB_MENU_EVENT_NONE, nil
  235. }
  236. func (p permission) Init() tea.Cmd {
  237. return nil
  238. }