openc3 7.4.0 → 7.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d94ef0547084256ba519d150e9e7637fe2623ad68703fb56ff43579ceb1119b
4
- data.tar.gz: bb907222d40154d622e73fb8732ff2715186183f5ce097f58832839ea3621fb3
3
+ metadata.gz: 38237f07ec722ff8f92d12fd8b1219f0f90fe58c7e37e30e8d50fd9107cc373e
4
+ data.tar.gz: 5b2d61f7c5cfc095fc554099d4b4854d147b7c9335dc413a024afc14d09b6713
5
5
  SHA512:
6
- metadata.gz: d59f2a554a6fd751533736e12088e85958e9fe8569ccc2ffde017e68c00626b39ddd7f08334e9e9f83fa47a599b8c0a803c0da248b945a7dff3f8e41a41085cc
7
- data.tar.gz: 54c6fc8f881f6ccfef18dd8e37ebbe99b078e199f95738b9f6da5d24183d279252a9ee563c2be338d4f4e2cf32bb0299b4761727b40ffb5f771e354ba3877538
6
+ metadata.gz: 5cf34d15ab53eee6dde3268c9735c51ebe8ed39ee910a34388549bde4e6c5abb9e60afd88a0698937e2c5f5ff16b106dd0633c268f62fdbf79be0f6b02e1fc22
7
+ data.tar.gz: b9e56c46a90420c6a8c20e5dbcae3b49d30686c4453d640e5bfbca90d5391949eb3054a8d11380ef1735f1b05f830973b1dd79a70b3ce7b7178b17b0f892c673
data/bin/openc3cli CHANGED
@@ -1541,7 +1541,7 @@ if not ARGV[0].nil? # argument(s) given
1541
1541
  puts " OPENC3_SETTING_<NAME> One variable per setting, e.g."
1542
1542
  puts " OPENC3_SETTING_TIME_ZONE=UTC sets 'time_zone'"
1543
1543
  puts " OPENC3_SETTINGS_OVERWRITE true to overwrite existing settings on every"
1544
- puts " run. false/unset leaves them alone"
1544
+ puts " run. false/unset keeps Admin Console edits"
1545
1545
  puts " OPENC3_SETTINGS_ALLOW_UNKNOWN true to allow setting names COSMOS doesn't"
1546
1546
  puts " recognize. Without it an unknown name is"
1547
1547
  puts " reported and skipped, so a typo can't"
@@ -1551,8 +1551,9 @@ if not ARGV[0].nil? # argument(s) given
1551
1551
  puts ""
1552
1552
  puts "These three accept true/false (1/0 also work)."
1553
1553
  puts ""
1554
- puts "A setting that already exists is left alone because an operator may have"
1555
- puts "edited it in the Admin Console. Settings written by a release before this"
1554
+ puts "A new setting is written. A setting still holding the value last seeded is"
1555
+ puts "updated, so changing a variable and restarting works. A setting changed in"
1556
+ puts "the Admin Console is left alone. Settings written by a release before this"
1556
1557
  puts "command existed carry no record of having been seeded, so they all count as"
1557
1558
  puts "edited: on such an upgrade run one init with OPENC3_SETTINGS_OVERWRITE=true"
1558
1559
  puts "to adopt the environment values, then turn it back off."
@@ -329,19 +329,23 @@ module OpenC3
329
329
  end
330
330
  packets = []
331
331
  cvt_items = []
332
- items.each_with_index do |item, index|
332
+ items.each do |item|
333
+ # get_tlm_available returns nil for items which don't exist and its result is
334
+ # passed directly here, so nil is a placeholder which returns a nil value
333
335
  if item.nil?
334
- # null items mean that it doesn't exist
335
- cvt_items[index] = nil
336
- else
337
- item_upcase = item.to_s.upcase
338
- target_name, packet_name, item_name, value_type, limits = item_upcase.split('__')
339
- raise ArgumentError, "items must be formatted as TGT__PKT__ITEM__TYPE" if target_name.nil? || packet_name.nil? || item_name.nil? || value_type.nil?
340
- if packet_name == 'LATEST' # Lookup packet_name in case of LATEST
341
- packet_name = CvtModel.determine_latest_packet_for_item(target_name, item_name, cache_timeout: cache_timeout, scope: scope)
342
- end
336
+ cvt_items << [nil, nil, nil, nil, nil]
337
+ next
338
+ end
339
+ # get_tlm_available tacks on __LIMITS to indicate a limits value is available
340
+ # so accept both TGT__PKT__ITEM__TYPE and TGT__PKT__ITEM__TYPE__LIMITS
341
+ parts = item.to_s.upcase.split('__')
342
+ raise ArgumentError, "items must be formatted as TGT__PKT__ITEM__TYPE" if parts.length < 4 || parts.length > 5
343
+ target_name, packet_name, item_name, value_type, limits = parts
344
+ if packet_name == 'LATEST' # Lookup packet_name in case of LATEST
345
+ packet_name = CvtModel.determine_latest_packet_for_item(target_name, item_name, cache_timeout: cache_timeout, scope: scope)
343
346
  end
344
- cvt_items[index] = [target_name, packet_name, item_name, value_type, limits]
347
+ # NOTE: limits is required by the historical (start_time) QuestDB lookup
348
+ cvt_items << [target_name, packet_name, item_name, value_type, limits]
345
349
  packets << [target_name, packet_name]
346
350
  end
347
351
  packets.uniq!
@@ -36,6 +36,14 @@ module OpenC3
36
36
  end
37
37
 
38
38
  def reset
39
+ @read_data_input_time = nil
40
+ @read_data_input = ''
41
+ @read_data_output_time = nil
42
+ @read_data_output = ''
43
+ @write_data_input_time = nil
44
+ @write_data_input = ''
45
+ @write_data_output_time = nil
46
+ @write_data_output = ''
39
47
  @extra = nil
40
48
  end
41
49
 
@@ -53,10 +53,19 @@ module OpenC3
53
53
 
54
54
  USER_AGENT = 'OpenC3 / v7 (ruby/openc3/lib/io/json_api_object)'.freeze
55
55
 
56
+ # Time limit for the first response byte from the server. This must be an
57
+ # explicit number rather than nil, see connect() for why. Requests can
58
+ # legitimately block for a long time, e.g. cmd() with a large timeout waiting
59
+ # on an interface ack, so this is effectively "wait forever" while still
60
+ # bounded so a wedged connection eventually releases the thread.
61
+ DEFAULT_READ_TIMEOUT_S = 86400
62
+
56
63
  # @param url [String] The url of openc3-cosmos-cmd-tlm-api http://openc3-cosmos-cmd-tlm-api:2901
57
64
  # @param timeout [Float] The time to wait before disconnecting 1.0
58
65
  # @param authentication [OpenC3Authentication] The authentication object if nill initialize will generate
59
- def initialize(url:, timeout: 1.0, authentication: nil)
66
+ # @param read_timeout [Float] The time to wait for the first response byte from the server.
67
+ # Defaults to the OPENC3_API_READ_TIMEOUT environment variable or DEFAULT_READ_TIMEOUT_S.
68
+ def initialize(url:, timeout: 1.0, authentication: nil, read_timeout: nil)
60
69
  @http = nil
61
70
  @mutex = Mutex.new
62
71
  @request_data = ""
@@ -65,6 +74,7 @@ module OpenC3
65
74
  @log = [nil, nil, nil]
66
75
  @authentication = authentication.nil? ? generate_auth() : authentication
67
76
  @timeout = timeout
77
+ @read_timeout = (read_timeout || ENV.fetch('OPENC3_API_READ_TIMEOUT', DEFAULT_READ_TIMEOUT_S)).to_f
68
78
  @shutdown = false
69
79
  # JsonDRb.debug = true # Enable for debugging
70
80
  end
@@ -120,7 +130,11 @@ module OpenC3
120
130
  # :open_timeout - time limit for just the connection phase (e.g. handshake) (Integer in seconds)
121
131
  # :read_timeout - time limit for the first response byte received from the server (Integer in seconds)
122
132
  # :write_timeout - time limit for the client to send the request to the server (Integer in seconds)
123
- @http = Faraday.new(request: { open_timeout: @timeout.to_i, read_timeout: nil }) do |f|
133
+ # NOTE: read_timeout must be an explicit number. Faraday only assigns it to Net::HTTP
134
+ # when the value is truthy (see Faraday::Adapter::NetHttp#configure_request), so passing
135
+ # nil does NOT mean "wait forever", it silently leaves Net::HTTP's 60s default in place.
136
+ # That 60s then caps every request regardless of any longer application level timeout.
137
+ @http = Faraday.new(request: { open_timeout: @timeout.to_i, read_timeout: @read_timeout }) do |f|
124
138
  f.adapter :net_http # adds the adapter to the connection, defaults to `Faraday.default_adapter`
125
139
  end
126
140
  rescue => e
@@ -212,7 +226,9 @@ module OpenC3
212
226
  @response_data = resp.body
213
227
  return resp
214
228
  rescue Faraday::ConnectionFailed, Errno::ECONNRESET, Errno::EPIPE, IOError => e
215
- # Connection errors are retryable - reconnect and try again
229
+ # Retryable. Nothing was successfully sent, so replaying is safe. This includes
230
+ # Net::OpenTimeout, which Faraday maps to ConnectionFailed and which covers a
231
+ # service that is still starting up.
216
232
  retry_count += 1
217
233
  @log[2] = "#{method} Exception: #{e.class}, #{e.message}, #{e.backtrace}"
218
234
  if retry_count <= RETRY_COUNT
@@ -225,6 +241,11 @@ module OpenC3
225
241
  raise error
226
242
  end
227
243
  rescue StandardError => e
244
+ # Everything else, including Faraday::TimeoutError from a read timeout, is NOT
245
+ # retryable. A read timeout means the request was fully sent and the server may
246
+ # have already acted on it. Many endpoints are not idempotent (create_activity,
247
+ # script_run, cmd), so a retry risks duplicating the operation. It would also blow
248
+ # past the caller's deadline by RETRY_COUNT times.
228
249
  @log[2] = "#{method} Exception: #{e.class}, #{e.message}, #{e.backtrace}"
229
250
  disconnect()
230
251
  error = "Api Exception: #{@log[0]} ::: #{@log[1]} ::: #{@log[2]}"
@@ -38,8 +38,9 @@ module OpenC3
38
38
  # @param url [String] The url of openc3-cosmos-cmd-tlm-api http://openc3-cosmos-cmd-tlm-api:2901
39
39
  # @param timeout [Float] The time to wait before disconnecting 1.0
40
40
  # @param authentication [OpenC3Authentication] The authentication object if nill initialize will generate
41
- def initialize(url:, timeout: 1.0, authentication: nil)
42
- super(url: url, timeout: timeout, authentication: authentication)
41
+ # @param read_timeout [Float] The time to wait for the first response byte from the server
42
+ def initialize(url:, timeout: 1.0, authentication: nil, read_timeout: nil)
43
+ super(url: url, timeout: timeout, authentication: authentication, read_timeout: read_timeout)
43
44
  @uri = URI("#{url}/openc3-api/api")
44
45
  end
45
46
 
@@ -150,11 +150,14 @@ module OpenC3
150
150
  if trigger['name'].nil? || trigger['group'].nil?
151
151
  raise ReactionInputError.new "invalid trigger, must contain 'name' and 'group' keys: #{trigger}"
152
152
  end
153
- trigger_name = trigger['name']
154
- unless trigger_hash[trigger_name].nil?
153
+ # Trigger names are only unique within a group so both parts identify
154
+ # the trigger. Keying on name alone rejects a reaction which references
155
+ # the same trigger name in two different groups.
156
+ trigger_key = "#{trigger['group']}__#{trigger['name']}"
157
+ unless trigger_hash[trigger_key].nil?
155
158
  raise ReactionInputError.new "no duplicate triggers allowed: #{triggers}"
156
159
  else
157
- trigger_hash[trigger_name] = 1
160
+ trigger_hash[trigger_key] = 1
158
161
  end
159
162
  end
160
163
  return triggers
@@ -182,9 +182,11 @@ module OpenC3
182
182
  # Seed settings from OPENC3_SETTING_<NAME> environment variables. Called by
183
183
  # `openc3cli initsettings` during init container startup.
184
184
  #
185
- # By default a setting is only written when it does not already exist, so a
186
- # value changed in the Admin Console survives a container restart. Set
187
- # OPENC3_SETTINGS_OVERWRITE to write on every run instead.
185
+ # By default a setting is written when it does not exist yet, or when it
186
+ # still holds the value last seeded (see seeded_value?), so a changed env
187
+ # var takes effect but a value changed in the Admin Console survives a
188
+ # container restart. Set OPENC3_SETTINGS_OVERWRITE to write on every run
189
+ # instead.
188
190
  #
189
191
  # Nothing here aborts init by default. A bad setting name, a bad value, or a
190
192
  # malformed control variable is reported on stdout and that one setting is
@@ -145,7 +145,12 @@ module OpenC3
145
145
  # Handle .xtce files
146
146
  extension = File.extname(filename).to_s.downcase
147
147
  if extension == ".xtce" or extension == ".xml"
148
- XtceParser.process(@commands, @telemetry, @warnings, filename, process_target_name)
148
+ target_name = XtceParser.process(@commands, @telemetry, @warnings, filename, process_target_name)
149
+ # XtceParser adds packets straight into @commands / @telemetry without
150
+ # going through finish_packet, so the ID lookup metadata finish_packet
151
+ # builds has to be built here instead. Without it Telemetry#identify
152
+ # and Commands#identify find no hash for the target and raise on nil.
153
+ build_xtce_id_metadata(target_name)
149
154
  return
150
155
  end
151
156
 
@@ -430,6 +435,36 @@ module OpenC3
430
435
 
431
436
  protected
432
437
 
438
+ # Build the ID lookup metadata for every packet an XTCE file just added to
439
+ # the given target. Packets are walked in the order XtceParser left them in,
440
+ # which is the order the rest of COSMOS sees them, so duplicate ID values
441
+ # resolve the same way here as they do everywhere else.
442
+ #
443
+ # @param target_name [String] Target the XTCE file defined, or nil if the
444
+ # file defined no target
445
+ def build_xtce_id_metadata(target_name)
446
+ return unless target_name
447
+
448
+ @commands[target_name]&.each_value do |packet|
449
+ next if packet.virtual
450
+
451
+ if packet.subpacket
452
+ build_id_metadata(packet, @cmd_subpacket_id_value_hash, @cmd_subpacket_id_signature, @cmd_subpacket_unique_id_mode)
453
+ else
454
+ build_id_metadata(packet, @cmd_id_value_hash, @cmd_id_signature, @cmd_unique_id_mode)
455
+ end
456
+ end
457
+ @telemetry[target_name]&.each_value do |packet|
458
+ next if packet.virtual
459
+
460
+ if packet.subpacket
461
+ build_id_metadata(packet, @tlm_subpacket_id_value_hash, @tlm_subpacket_id_signature, @tlm_subpacket_unique_id_mode)
462
+ else
463
+ build_id_metadata(packet, @tlm_id_value_hash, @tlm_id_signature, @tlm_unique_id_mode)
464
+ end
465
+ end
466
+ end
467
+
433
468
  def build_id_metadata(packet, id_value_hash, id_signature_hash, unique_id_mode_hash)
434
469
  target_id_value_hash = id_value_hash[packet.target_name]
435
470
  target_id_value_hash = {} unless target_id_value_hash
@@ -22,6 +22,10 @@ module OpenC3
22
22
  class XtceParser
23
23
  attr_accessor :current_target_name
24
24
 
25
+ # The target the file defined, still readable after parsing finishes.
26
+ # current_target_name is cleared by reset_processing_variables.
27
+ attr_reader :parsed_target_name
28
+
25
29
  # Processes a XTCE formatted OpenC3 configuration file
26
30
  #
27
31
  # @param commands [Hash<String=>Packet>] Hash of all the command packets
@@ -32,8 +36,10 @@ module OpenC3
32
36
  # that were created while parsing the configuration
33
37
  # @param filename [String] The name of the configuration file
34
38
  # @param target_name [String] Override the target name found in the XTCE file
39
+ # @return [String] The target name the packets were added under. The caller
40
+ # needs this to build the ID lookup metadata for those packets.
35
41
  def self.process(commands, telemetry, warnings, filename, target_name = nil)
36
- XtceParser.new(commands, telemetry, warnings, filename, target_name)
42
+ XtceParser.new(commands, telemetry, warnings, filename, target_name).parsed_target_name
37
43
  end
38
44
 
39
45
  def self.reverse_packet_order(target_name, cmd_or_tlm_hash)
@@ -91,6 +97,7 @@ module OpenC3
91
97
  XtceParser.reverse_packet_order(@current_target_name, @commands)
92
98
  XtceParser.reverse_packet_order(@current_target_name, @telemetry)
93
99
 
100
+ @parsed_target_name = @current_target_name
94
101
  reset_processing_variables()
95
102
  end
96
103
 
@@ -22,11 +22,15 @@ module OpenC3
22
22
  return _tables_handle_response(response, 'Failed to create binary')
23
23
  end
24
24
 
25
- def table_create_report(filename, definition, table_name: nil, scope: $openc3_scope)
25
+ # save: true (the default) writes the report into the target's storage next to
26
+ # the binary so it can be read back with get_target_file(). Pass save: false to
27
+ # get the contents in the return value without creating a file.
28
+ def table_create_report(filename, definition, table_name: nil, save: true, scope: $openc3_scope)
26
29
  post_data = {}
27
30
  post_data['binary'] = filename
28
31
  post_data['definition'] = definition
29
32
  post_data['table_name'] = table_name if table_name
33
+ post_data['save'] = save
30
34
  response = $api_server.request('post', '/openc3-api/tables/report', json: true, data: post_data, scope: scope)
31
35
  return _tables_handle_response(response, 'Failed to create report')
32
36
  end
@@ -928,6 +928,10 @@ module OpenC3
928
928
  # @return [Array, Hash] Array of [value, limits_state] pairs per row, or {} if no results.
929
929
  # Single-row results return a flat array; multi-row results return array of arrays.
930
930
  def self.tsdb_lookup(items, start_time:, end_time: nil, scope: "DEFAULT")
931
+ # Every item is a placeholder for an item which doesn't exist, so there's
932
+ # nothing to query. Return a single row of nil values, one per item.
933
+ return Array.new(items.length) { [nil, nil] } if items.all? { |item| item[2].nil? }
934
+
931
935
  # Group items by db_shard number while preserving their original positions
932
936
  db_shard_groups = {} # db_shard => { positions: [], items: [] }
933
937
  items.each_with_index do |item, pos|
@@ -944,62 +948,36 @@ module OpenC3
944
948
  return tsdb_lookup_single_db_shard(group[:items], start_time: start_time, end_time: end_time, scope: scope, db_shard: db_shard)
945
949
  end
946
950
 
947
- # Cross-db_shard: execute per-db_shard queries and merge results
948
- db_shard_results = {} # db_shard => data
951
+ # Cross-db_shard: execute per-db_shard queries (as arrays of rows) and merge results
952
+ db_shard_rows = {} # db_shard => rows
949
953
  db_shard_groups.each do |db_shard, group|
950
- result = tsdb_lookup_single_db_shard(group[:items], start_time: start_time, end_time: end_time, scope: scope, db_shard: db_shard)
951
- db_shard_results[db_shard] = result
954
+ result = tsdb_lookup_single_db_shard(group[:items], start_time: start_time, end_time: end_time, scope: scope, db_shard: db_shard, flatten: false)
955
+ db_shard_rows[db_shard] = result.is_a?(Array) ? result : []
952
956
  end
953
957
 
954
- # If all db_shards returned empty, return empty
955
- return {} if db_shard_results.values.all? { |r| r == {} }
956
-
957
- # Merge results positionally back into the original item order.
958
- # For single-row results (no end_time), merge flat arrays.
959
- # For multi-row results, each db_shard may have different row counts;
960
- # use the maximum row count and fill missing positions with [nil, nil].
961
- if !end_time
962
- # Single-row mode: each db_shard returns a flat array of [value, limits] pairs.
963
- # Merge them into the original item order.
964
- merged = Array.new(items.length) { [nil, nil] }
965
- db_shard_groups.each do |db_shard, group|
966
- result = db_shard_results[db_shard]
967
- next if result == {} || !result.is_a?(Array)
958
+ # Merge results positionally back into the original item order. Each db_shard
959
+ # may have different row counts so use the maximum row count and fill missing
960
+ # positions with [nil, nil]. If all db_shards returned empty, return empty.
961
+ max_rows = db_shard_rows.values.map(&:length).max
962
+ return {} if max_rows == 0
963
+
964
+ merged = Array.new(max_rows) { Array.new(items.length) { [nil, nil] } }
965
+ db_shard_groups.each do |db_shard, group|
966
+ db_shard_rows[db_shard].each_with_index do |row, row_num|
968
967
  group[:positions].each_with_index do |orig_pos, db_shard_idx|
969
- merged[orig_pos] = result[db_shard_idx] if result[db_shard_idx]
968
+ merged[row_num][orig_pos] = row[db_shard_idx] if row[db_shard_idx]
970
969
  end
971
970
  end
972
- merged
973
- else
974
- # Multi-row mode: find max row count across db_shards
975
- max_rows = 0
976
- db_shard_groups.each do |db_shard, _group|
977
- result = db_shard_results[db_shard]
978
- next if result == {}
979
- count = result.is_a?(Array) ? result.length : 0
980
- max_rows = count if count > max_rows
981
- end
982
- return {} if max_rows == 0
983
-
984
- merged = Array.new(max_rows) { Array.new(items.length) { [nil, nil] } }
985
- db_shard_groups.each do |db_shard, group|
986
- result = db_shard_results[db_shard]
987
- next if result == {}
988
- rows = result.is_a?(Array) ? result : []
989
- rows.each_with_index do |row, row_num|
990
- next unless row.is_a?(Array)
991
- group[:positions].each_with_index do |orig_pos, db_shard_idx|
992
- merged[row_num][orig_pos] = row[db_shard_idx] if row[db_shard_idx]
993
- end
994
- end
995
- end
996
- merged
997
971
  end
972
+ # Match the single db_shard behavior of returning a flat array for a single row
973
+ return merged[0] if max_rows == 1
974
+ merged
998
975
  end
999
976
 
1000
977
  # Execute a tsdb_lookup query against a single db_shard.
1001
978
  # This contains the original ASOF JOIN logic for items all on the same QuestDB instance.
1002
- def self.tsdb_lookup_single_db_shard(items, start_time:, end_time: nil, scope: "DEFAULT", db_shard: 0)
979
+ # When flatten is true a single row result is returned as a flat array rather than an array of rows.
980
+ def self.tsdb_lookup_single_db_shard(items, start_time:, end_time: nil, scope: "DEFAULT", db_shard: 0, flatten: true)
1003
981
  tables = {}
1004
982
  names = []
1005
983
  nil_count = 0
@@ -1060,6 +1038,11 @@ module OpenC3
1060
1038
  end
1061
1039
  end
1062
1040
 
1041
+ # Every item in this db_shard is a placeholder so there's no table to query.
1042
+ # Return no results and let tsdb_lookup fill these positions with [nil, nil]
1043
+ # when it merges the db_shards (an all placeholder lookup returns before this)
1044
+ return {} if tables.empty?
1045
+
1063
1046
  # Add needed timestamp columns to the SELECT for calculated items
1064
1047
  needed_timestamps.each do |table_index, ts_columns|
1065
1048
  ts_columns.each do |ts_col|
@@ -1147,7 +1130,7 @@ module OpenC3
1147
1130
  data[row_num].insert(position, [calculated_value, nil])
1148
1131
  end
1149
1132
  end
1150
- if result.ntuples == 1
1133
+ if flatten and result.ntuples == 1
1151
1134
  data = data[0]
1152
1135
  end
1153
1136
  data
@@ -1,14 +1,14 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- OPENC3_VERSION = '7.4.0'
3
+ OPENC3_VERSION = '7.4.1'
4
4
  module OpenC3
5
5
  module Version
6
6
  MAJOR = '7'
7
7
  MINOR = '4'
8
- PATCH = '0'
8
+ PATCH = '1'
9
9
  OTHER = ''
10
- BUILD = 'ed0cb44ca3c661eaf2babb77664d0063c955c68c'
10
+ BUILD = '2d4089e0687654512c2eb84722a5a4fa699dd5c3'
11
11
  end
12
- VERSION = '7.4.0'
13
- GEM_VERSION = '7.4.0'
12
+ VERSION = '7.4.1'
13
+ GEM_VERSION = '7.4.1'
14
14
  end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "<%= tool_name %>",
3
- "version": "7.4.0",
3
+ "version": "7.4.1",
4
4
  "scripts": {
5
5
  "ng": "ng",
6
6
  "start": "ng serve",
@@ -23,7 +23,7 @@
23
23
  "@angular/platform-browser-dynamic": "^18.2.6",
24
24
  "@angular/router": "^18.2.6",
25
25
  "@astrouxds/astro-web-components": "^7.24.0",
26
- "@openc3/js-common": "7.4.0",
26
+ "@openc3/js-common": "7.4.1",
27
27
  "rxjs": "~7.8.0",
28
28
  "single-spa": "^5.9.5",
29
29
  "single-spa-angular": "^9.2.0",
@@ -16,7 +16,7 @@
16
16
  "@emotion/react": "^11.13.3",
17
17
  "@emotion/styled": "^11.11.0",
18
18
  "@mui/material": "^6.1.1",
19
- "@openc3/js-common": "7.4.0",
19
+ "@openc3/js-common": "7.4.1",
20
20
  "react": "^18.2.0",
21
21
  "react-dom": "^18.2.0",
22
22
  "single-spa-react": "^5.1.4"
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@astrouxds/astro-web-components": "^7.24.0",
15
- "@openc3/js-common": "7.4.0",
15
+ "@openc3/js-common": "7.4.1",
16
16
  "@smui/button": "^7.0.0",
17
17
  "@smui/common": "^7.0.0",
18
18
  "@smui/card": "^7.0.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "<%= tool_name %>",
3
- "version": "7.4.0",
3
+ "version": "7.4.1",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -11,8 +11,8 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "@astrouxds/astro-web-components": "^7.24.0",
14
- "@openc3/js-common": "7.4.0",
15
- "@openc3/vue-common": "7.4.0",
14
+ "@openc3/js-common": "7.4.1",
15
+ "@openc3/vue-common": "7.4.1",
16
16
  "axios": "^1.7.7",
17
17
  "date-fns": "^4.1.0",
18
18
  "lodash": "^4.17.21",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "<%= widget_name %>",
3
- "version": "7.4.0",
3
+ "version": "7.4.1",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "@astrouxds/astro-web-components": "^7.24.0",
11
- "@openc3/vue-common": "7.4.0",
11
+ "@openc3/vue-common": "7.4.1",
12
12
  "vuetify": "^3.7.1"
13
13
  },
14
14
  "devDependencies": {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openc3
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.4.0
4
+ version: 7.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Melton
@@ -562,6 +562,26 @@ dependencies:
562
562
  - - "~>"
563
563
  - !ruby/object:Gem::Version
564
564
  version: '1.2'
565
+ - !ruby/object:Gem::Dependency
566
+ name: resolv
567
+ requirement: !ruby/object:Gem::Requirement
568
+ requirements:
569
+ - - "~>"
570
+ - !ruby/object:Gem::Version
571
+ version: '0.7'
572
+ - - ">="
573
+ - !ruby/object:Gem::Version
574
+ version: 0.7.2
575
+ type: :runtime
576
+ prerelease: false
577
+ version_requirements: !ruby/object:Gem::Requirement
578
+ requirements:
579
+ - - "~>"
580
+ - !ruby/object:Gem::Version
581
+ version: '0.7'
582
+ - - ">="
583
+ - !ruby/object:Gem::Version
584
+ version: 0.7.2
565
585
  - !ruby/object:Gem::Dependency
566
586
  name: resolv-replace
567
587
  requirement: !ruby/object:Gem::Requirement