File size: 4,184 Bytes
b39afbe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/**
 * Copyright (c) 2023 MERCENARIES.AI PTE. LTD.
 * All rights reserved.
 */

import axios from 'axios';
import { BaseWorkflow, omnilog, type IWorkflowMeta } from 'omni-shared';

class ClientWorkflow extends BaseWorkflow {
  _errors: any[] = [];
  _dirty: number = 0; // 0 = no local changes, 1 = unsaved, any other value is a dirtyCookie, i.e. save-in-progress.
  _flags: string[] = [];

  get displayName(): string {
    let result = this.meta.name || this.id;
    if (this.isDirty) result += '*';
    if (this.readOnly) result += ' (read-only)';
    if (this.copyOnWrite) result += ' (copy-on-write)';
    return result;
  }

  hasFlag(flag: string): boolean {
    if (flag !== flag.toLowerCase()) {
      throw new Error(`ClientWorkflow Flag "${flag}" must be lower-case`);
    }
    return this._flags.includes(flag);
  }

  setFlag(flag: string, value: boolean = true) {
    if (flag !== flag.toLowerCase()) {
      throw new Error(`ClientWorkflow Flag "${flag}" must be lower-case`);
    }
    if (value) {
      // Set true
      if (!this._flags.includes(flag)) {
        this._flags.push(flag);
      }
      return;
    }
    // Set false, i.e. clear
    this._flags = this._flags.filter((f) => f !== flag);
  }

  clearFlag(flag: string) {
    this.setFlag(flag, false);
  }

  get isDirty(): boolean {
    return this._dirty !== 0;
  }

  setDirty() {
    this._dirty = 1; // i.e. unsaved.
  }

  get copyOnWrite(): boolean {
    return this.hasFlag('copyonwrite');
  }

  set copyOnWrite(value: boolean) {
    this.setFlag('copyonwrite', value);
  }

  get readOnly(): boolean {
    return this.hasFlag('readonly');
  }

  set readOnly(value: boolean) {
    this.setFlag('readonly', value);
  }

  // Clone the recipe on the server
  static async clone(data: { id: string; meta?: Partial<IWorkflowMeta> }): Promise<ClientWorkflow> {
    const result = await axios.post('/api/v1/workflow/clone', { ...data }, { withCredentials: true });

    const json = result.data.workflow;
    return ClientWorkflow.fromJSON(json);
  }

  // Returns 'true' if/when server version matches local version
  async syncToServer(): Promise<boolean> {
    if (this.readOnly) {
      /* TODO: Ensure overwriting a read-only workflow will fail on the server. */
      return false;
    }

    if (this.copyOnWrite) {
      this.copyOnWrite = false;
      this.id = '';
    }

    const dirtyCookie = new Date().getTime();
    this._dirty = dirtyCookie; // i.e. save in progress.
    this.meta.updated = Date.now();
    //@ts-ignore
    const payload = window.Alpine.raw(this.toJSON());

    try {
      const result = await axios({
        method: this.id ? 'put' : 'post',
        url: '/api/v1/workflow',
        data: payload,
        withCredentials: true
      });

      if (result.status !== 200) {
        return false; /* Unable to write to server. */
      }
      if (!result.data.workflow) {
        return false; /* Unable to write to server. */
      }
      const serverId = result.data.workflow.id;
      if (!serverId) {
        throw new Error('Server did not return a valid recipe Id');
      }
      if (this.id && this.id !== serverId) {
        omnilog.log('server updated our id unexpectedly', this.id, serverId);
      }
      this.id = serverId;
    } catch (e) {
      omnilog.log('error writing to server', e);
      return false; /* Unable to write to server. */
    }

    if (this._dirty === dirtyCookie) {
      this._dirty = 0; // Only set back to 0 if it wasn't changed while we were saving.
    }

    return true;
  }

  static fromJSON(json: any, flags: string[] | undefined = undefined): ClientWorkflow {
    const result = new ClientWorkflow(json.id);
    result.id = json.id;
    if (!result.id && json._id) {
      result.id = json._id.replace('wf:', '');
    }

    result.setMeta(json.meta);
    result.setRete(json.rete);
    result.setAPI(json.api);

    if (flags && flags.length > 0) {
      result._flags = flags;
    } else if (json._flags) {
      result._flags = json._flags;
    }

    return result;
  }

  toJSON() {
    const ret: any = super.toJSON();
    ret._flags = this._flags;
    return ret;
  }
}

export default ClientWorkflow;