environments.ts 11 KB

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