environments.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. import isEqual from "lodash/isEqual"
  2. import { combineLatest } from "rxjs"
  3. import { distinctUntilChanged, map, pluck } from "rxjs/operators"
  4. import DispatchingStore, {
  5. defineDispatchers,
  6. } from "~/newstore/DispatchingStore"
  7. export type Environment = {
  8. name: string
  9. variables: {
  10. key: string
  11. value: string
  12. }[]
  13. }
  14. const defaultEnvironmentsState = {
  15. environments: [
  16. {
  17. name: "My Environment Variables",
  18. variables: [],
  19. },
  20. ] as Environment[],
  21. globals: [] as Environment["variables"],
  22. // Current environment index specifies the index
  23. // -1 means no environments are selected
  24. currentEnvironmentIndex: -1,
  25. }
  26. type EnvironmentStore = typeof defaultEnvironmentsState
  27. const dispatchers = defineDispatchers({
  28. setCurrentEnviromentIndex(
  29. { environments }: EnvironmentStore,
  30. { newIndex }: { newIndex: number }
  31. ) {
  32. if (newIndex >= environments.length || newIndex <= -2) {
  33. console.log(
  34. `Ignoring possibly invalid current environment index assignment (value: ${newIndex})`
  35. )
  36. return {}
  37. }
  38. return {
  39. currentEnvironmentIndex: newIndex,
  40. }
  41. },
  42. appendEnvironments(
  43. { environments }: EnvironmentStore,
  44. { envs }: { envs: Environment[] }
  45. ) {
  46. return {
  47. environments: [...environments, ...envs],
  48. }
  49. },
  50. replaceEnvironments(
  51. _: EnvironmentStore,
  52. { environments }: { environments: Environment[] }
  53. ) {
  54. return {
  55. environments,
  56. }
  57. },
  58. createEnvironment(
  59. { environments }: EnvironmentStore,
  60. { name }: { name: string }
  61. ) {
  62. return {
  63. environments: [
  64. ...environments,
  65. {
  66. name,
  67. variables: [],
  68. },
  69. ],
  70. }
  71. },
  72. deleteEnvironment(
  73. { environments, currentEnvironmentIndex }: EnvironmentStore,
  74. { envIndex }: { envIndex: number }
  75. ) {
  76. return {
  77. environments: environments.filter((_, index) => index !== envIndex),
  78. currentEnvironmentIndex:
  79. envIndex === currentEnvironmentIndex ? -1 : currentEnvironmentIndex,
  80. }
  81. },
  82. renameEnvironment(
  83. { environments }: EnvironmentStore,
  84. { envIndex, newName }: { envIndex: number; newName: string }
  85. ) {
  86. return {
  87. environments: environments.map((env, index) =>
  88. index === envIndex
  89. ? {
  90. ...env,
  91. name: newName,
  92. }
  93. : env
  94. ),
  95. }
  96. },
  97. updateEnvironment(
  98. { environments }: EnvironmentStore,
  99. { envIndex, updatedEnv }: { envIndex: number; updatedEnv: Environment }
  100. ) {
  101. return {
  102. environments: environments.map((env, index) =>
  103. index === envIndex ? updatedEnv : env
  104. ),
  105. }
  106. },
  107. addEnvironmentVariable(
  108. { environments }: EnvironmentStore,
  109. { envIndex, key, value }: { envIndex: number; key: string; value: string }
  110. ) {
  111. return {
  112. environments: environments.map((env, index) =>
  113. index === envIndex
  114. ? {
  115. ...env,
  116. variables: [...env.variables, { key, value }],
  117. }
  118. : env
  119. ),
  120. }
  121. },
  122. removeEnvironmentVariable(
  123. { environments }: EnvironmentStore,
  124. { envIndex, variableIndex }: { envIndex: number; variableIndex: number }
  125. ) {
  126. return {
  127. environments: environments.map((env, index) =>
  128. index === envIndex
  129. ? {
  130. ...env,
  131. variables: env.variables.filter(
  132. (_, vIndex) => vIndex !== variableIndex
  133. ),
  134. }
  135. : env
  136. ),
  137. }
  138. },
  139. setEnvironmentVariables(
  140. { environments }: EnvironmentStore,
  141. {
  142. envIndex,
  143. vars,
  144. }: { envIndex: number; vars: { key: string; value: string }[] }
  145. ) {
  146. return {
  147. environments: environments.map((env, index) =>
  148. index === envIndex
  149. ? {
  150. ...env,
  151. variables: vars,
  152. }
  153. : env
  154. ),
  155. }
  156. },
  157. updateEnvironmentVariable(
  158. { environments }: EnvironmentStore,
  159. {
  160. envIndex,
  161. variableIndex,
  162. updatedKey,
  163. updatedValue,
  164. }: {
  165. envIndex: number
  166. variableIndex: number
  167. updatedKey: string
  168. updatedValue: string
  169. }
  170. ) {
  171. return {
  172. environments: environments.map((env, index) =>
  173. index === envIndex
  174. ? {
  175. ...env,
  176. variables: env.variables.map((v, vIndex) =>
  177. vIndex === variableIndex
  178. ? { key: updatedKey, value: updatedValue }
  179. : v
  180. ),
  181. }
  182. : env
  183. ),
  184. }
  185. },
  186. setGlobalVariables(_, { entries }: { entries: Environment["variables"] }) {
  187. return {
  188. globals: entries,
  189. }
  190. },
  191. clearGlobalVariables() {
  192. return {
  193. globals: [],
  194. }
  195. },
  196. addGlobalVariable(
  197. { globals },
  198. { entry }: { entry: Environment["variables"][number] }
  199. ) {
  200. return {
  201. globals: [...globals, entry],
  202. }
  203. },
  204. removeGlobalVariable({ globals }, { envIndex }: { envIndex: number }) {
  205. return {
  206. globals: globals.filter((_, i) => i !== envIndex),
  207. }
  208. },
  209. updateGlobalVariable(
  210. { globals },
  211. {
  212. envIndex,
  213. updatedEntry,
  214. }: { envIndex: number; updatedEntry: Environment["variables"][number] }
  215. ) {
  216. return {
  217. globals: globals.map((x, i) => (i !== envIndex ? x : updatedEntry)),
  218. }
  219. },
  220. })
  221. export const environmentsStore = new DispatchingStore(
  222. defaultEnvironmentsState,
  223. dispatchers
  224. )
  225. export const environments$ = environmentsStore.subject$.pipe(
  226. pluck("environments"),
  227. distinctUntilChanged()
  228. )
  229. export const globalEnv$ = environmentsStore.subject$.pipe(
  230. pluck("globals"),
  231. distinctUntilChanged()
  232. )
  233. export const selectedEnvIndex$ = environmentsStore.subject$.pipe(
  234. pluck("currentEnvironmentIndex"),
  235. distinctUntilChanged()
  236. )
  237. export const currentEnvironment$ = combineLatest([
  238. environments$,
  239. selectedEnvIndex$,
  240. ]).pipe(
  241. map(([envs, selectedIndex]) => {
  242. if (selectedIndex === -1) {
  243. const env: Environment = {
  244. name: "No environment",
  245. variables: [],
  246. }
  247. return env
  248. } else {
  249. return envs[selectedIndex]
  250. }
  251. })
  252. )
  253. /**
  254. * Stream returning all the environment variables accessible in
  255. * the current state (Global + The Selected Environment).
  256. * NOTE: The source environment attribute will be "Global" for Global Env as source.
  257. */
  258. export const aggregateEnvs$ = combineLatest([
  259. currentEnvironment$,
  260. globalEnv$,
  261. ]).pipe(
  262. map(([selectedEnv, globalVars]) => {
  263. const results: { key: string; value: string; sourceEnv: string }[] = []
  264. selectedEnv.variables.forEach(({ key, value }) =>
  265. results.push({ key, value, sourceEnv: selectedEnv.name })
  266. )
  267. globalVars.forEach(({ key, value }) =>
  268. results.push({ key, value, sourceEnv: "Global" })
  269. )
  270. return results
  271. }),
  272. distinctUntilChanged(isEqual)
  273. )
  274. export function getCurrentEnvironment(): Environment {
  275. if (environmentsStore.value.currentEnvironmentIndex === -1) {
  276. return {
  277. name: "No environment",
  278. variables: [],
  279. }
  280. }
  281. return environmentsStore.value.environments[
  282. environmentsStore.value.currentEnvironmentIndex
  283. ]
  284. }
  285. export function setCurrentEnvironment(newEnvIndex: number) {
  286. environmentsStore.dispatch({
  287. dispatcher: "setCurrentEnviromentIndex",
  288. payload: {
  289. newIndex: newEnvIndex,
  290. },
  291. })
  292. }
  293. export function getLegacyGlobalEnvironment(): Environment | null {
  294. const envs = environmentsStore.value.environments
  295. const el = envs.find(
  296. (env) => env.name === "globals" || env.name === "Globals"
  297. )
  298. return el ?? null
  299. }
  300. export function getGlobalVariables(): Environment["variables"] {
  301. return environmentsStore.value.globals
  302. }
  303. export function addGlobalEnvVariable(entry: Environment["variables"][number]) {
  304. environmentsStore.dispatch({
  305. dispatcher: "addGlobalVariable",
  306. payload: {
  307. entry,
  308. },
  309. })
  310. }
  311. export function setGlobalEnvVariables(entries: Environment["variables"]) {
  312. environmentsStore.dispatch({
  313. dispatcher: "setGlobalVariables",
  314. payload: {
  315. entries,
  316. },
  317. })
  318. }
  319. export function clearGlobalEnvVariables() {
  320. environmentsStore.dispatch({
  321. dispatcher: "clearGlobalVariables",
  322. payload: {},
  323. })
  324. }
  325. export function removeGlobalEnvVariable(envIndex: number) {
  326. environmentsStore.dispatch({
  327. dispatcher: "removeGlobalVariable",
  328. payload: {
  329. envIndex,
  330. },
  331. })
  332. }
  333. export function updateGlobalEnvVariable(
  334. envIndex: number,
  335. updatedEntry: Environment["variables"][number]
  336. ) {
  337. environmentsStore.dispatch({
  338. dispatcher: "updateGlobalVariable",
  339. payload: {
  340. envIndex,
  341. updatedEntry,
  342. },
  343. })
  344. }
  345. export function replaceEnvironments(newEnvironments: any[]) {
  346. environmentsStore.dispatch({
  347. dispatcher: "replaceEnvironments",
  348. payload: {
  349. environments: newEnvironments,
  350. },
  351. })
  352. }
  353. export function appendEnvironments(envs: Environment[]) {
  354. environmentsStore.dispatch({
  355. dispatcher: "appendEnvironments",
  356. payload: {
  357. envs,
  358. },
  359. })
  360. }
  361. export function createEnvironment(envName: string) {
  362. environmentsStore.dispatch({
  363. dispatcher: "createEnvironment",
  364. payload: {
  365. name: envName,
  366. },
  367. })
  368. }
  369. export function deleteEnvironment(envIndex: number) {
  370. environmentsStore.dispatch({
  371. dispatcher: "deleteEnvironment",
  372. payload: {
  373. envIndex,
  374. },
  375. })
  376. }
  377. export function renameEnvironment(envIndex: number, newName: string) {
  378. environmentsStore.dispatch({
  379. dispatcher: "renameEnvironment",
  380. payload: {
  381. envIndex,
  382. newName,
  383. },
  384. })
  385. }
  386. export function updateEnvironment(envIndex: number, updatedEnv: Environment) {
  387. environmentsStore.dispatch({
  388. dispatcher: "updateEnvironment",
  389. payload: {
  390. envIndex,
  391. updatedEnv,
  392. },
  393. })
  394. }
  395. export function setEnvironmentVariables(
  396. envIndex: number,
  397. vars: { key: string; value: string }[]
  398. ) {
  399. environmentsStore.dispatch({
  400. dispatcher: "setEnvironmentVariables",
  401. payload: {
  402. envIndex,
  403. vars,
  404. },
  405. })
  406. }
  407. export function addEnvironmentVariable(
  408. envIndex: number,
  409. { key, value }: { key: string; value: string }
  410. ) {
  411. environmentsStore.dispatch({
  412. dispatcher: "addEnvironmentVariable",
  413. payload: {
  414. envIndex,
  415. key,
  416. value,
  417. },
  418. })
  419. }
  420. export function removeEnvironmentVariable(
  421. envIndex: number,
  422. variableIndex: number
  423. ) {
  424. environmentsStore.dispatch({
  425. dispatcher: "removeEnvironmentVariable",
  426. payload: {
  427. envIndex,
  428. variableIndex,
  429. },
  430. })
  431. }
  432. export function updateEnvironmentVariable(
  433. envIndex: number,
  434. variableIndex: number,
  435. { key, value }: { key: string; value: string }
  436. ) {
  437. environmentsStore.dispatch({
  438. dispatcher: "updateEnvironmentVariable",
  439. payload: {
  440. envIndex,
  441. variableIndex,
  442. updatedKey: key,
  443. updatedValue: value,
  444. },
  445. })
  446. }
  447. export function getEnviroment(index: number) {
  448. return environmentsStore.value.environments[index]
  449. }