mage-ai 0.8.10__py3-none-any.whl → 0.8.12__py3-none-any.whl

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.

Potentially problematic release.


This version of mage-ai might be problematic. Click here for more details.

Files changed (76) hide show
  1. mage_ai/api/policies/BlockPolicy.py +13 -0
  2. mage_ai/api/policies/SyncPolicy.py +30 -0
  3. mage_ai/api/presenters/BlockPresenter.py +12 -1
  4. mage_ai/api/presenters/SyncPresenter.py +11 -0
  5. mage_ai/api/resources/BlockResource.py +10 -3
  6. mage_ai/api/resources/SyncResource.py +43 -0
  7. mage_ai/data_preparation/executors/pipeline_executor.py +9 -0
  8. mage_ai/data_preparation/executors/streaming_pipeline_executor.py +3 -1
  9. mage_ai/data_preparation/models/block/__init__.py +5 -3
  10. mage_ai/data_preparation/models/block/integration/__init__.py +59 -0
  11. mage_ai/data_preparation/models/constants.py +1 -0
  12. mage_ai/data_preparation/preferences.py +43 -0
  13. mage_ai/data_preparation/sync/__init__.py +17 -0
  14. mage_ai/data_preparation/sync/base_sync.py +7 -0
  15. mage_ai/data_preparation/sync/git_sync.py +26 -0
  16. mage_ai/data_preparation/templates/data_loaders/streaming/kafka.yaml +5 -0
  17. mage_ai/orchestration/db/models.py +14 -0
  18. mage_ai/orchestration/pipeline_scheduler.py +12 -4
  19. mage_ai/server/constants.py +1 -1
  20. mage_ai/server/frontend_dist/404.html +2 -2
  21. mage_ai/server/frontend_dist/404.html.html +2 -2
  22. mage_ai/server/frontend_dist/_next/static/BJSgpMeWTfdkZw_YRDpOz/_buildManifest.js +1 -0
  23. mage_ai/server/frontend_dist/_next/static/chunks/5477-d76f7f4b9d329116.js +1 -0
  24. mage_ai/server/frontend_dist/_next/static/chunks/9767-e89f3e19764e4f24.js +1 -0
  25. mage_ai/server/frontend_dist/_next/static/chunks/pages/{_app-44766f29c8c5b4ce.js → _app-77b4b367fdb247d6.js} +1 -1
  26. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-51fe31916670195c.js +1 -0
  27. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/account/{profile-acd7ee47219fee3d.js → profile-88bc8c5e21f7e493.js} +1 -1
  28. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-4c05a269e02f2208.js +1 -0
  29. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync_data-f1f47e503c490758.js +1 -0
  30. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{users-c128672e053a4c30.js → users-439adeb06fca8436.js} +1 -1
  31. mage_ai/server/frontend_dist/_next/static/chunks/pages/terminal-6feb9848233a6c6e.js +1 -0
  32. mage_ai/server/frontend_dist/index.html +2 -2
  33. mage_ai/server/frontend_dist/manage.html +2 -2
  34. mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
  35. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  36. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
  37. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
  38. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
  39. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  40. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  41. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
  42. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
  43. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
  44. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
  45. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  46. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
  47. mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
  48. mage_ai/server/frontend_dist/pipelines.html +2 -2
  49. mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
  50. mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
  51. mage_ai/server/frontend_dist/settings/workspace/sync_data.html +20 -0
  52. mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
  53. mage_ai/server/frontend_dist/settings.html +2 -2
  54. mage_ai/server/frontend_dist/sign-in.html +2 -2
  55. mage_ai/server/frontend_dist/terminal.html +2 -2
  56. mage_ai/server/frontend_dist/test.html +3 -3
  57. mage_ai/server/frontend_dist/triggers.html +2 -2
  58. mage_ai/server/server.py +1 -0
  59. mage_ai/shared/config.py +4 -1
  60. mage_ai/streaming/sources/kafka.py +49 -3
  61. mage_ai/tests/data_preparation/test_templates.py +5 -0
  62. mage_ai/tests/streaming/sources/test_kafka.py +17 -0
  63. {mage_ai-0.8.10.dist-info → mage_ai-0.8.12.dist-info}/METADATA +3 -1
  64. {mage_ai-0.8.10.dist-info → mage_ai-0.8.12.dist-info}/RECORD +70 -61
  65. mage_ai/server/frontend_dist/_next/static/avIy1qfPFOamteWu3WLo7/_buildManifest.js +0 -1
  66. mage_ai/server/frontend_dist/_next/static/chunks/9140-6f67e0879394373d.js +0 -1
  67. mage_ai/server/frontend_dist/_next/static/chunks/9767-3f852fd90cf7857f.js +0 -1
  68. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-03812efcc2f955c1.js +0 -1
  69. mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-07bda506f68974fb.js +0 -1
  70. mage_ai/server/frontend_dist/_next/static/chunks/pages/terminal-5d7c45bb058a3f20.js +0 -1
  71. /mage_ai/server/frontend_dist/_next/static/{avIy1qfPFOamteWu3WLo7 → BJSgpMeWTfdkZw_YRDpOz}/_middlewareManifest.js +0 -0
  72. /mage_ai/server/frontend_dist/_next/static/{avIy1qfPFOamteWu3WLo7 → BJSgpMeWTfdkZw_YRDpOz}/_ssgManifest.js +0 -0
  73. {mage_ai-0.8.10.dist-info → mage_ai-0.8.12.dist-info}/LICENSE +0 -0
  74. {mage_ai-0.8.10.dist-info → mage_ai-0.8.12.dist-info}/WHEEL +0 -0
  75. {mage_ai-0.8.10.dist-info → mage_ai-0.8.12.dist-info}/entry_points.txt +0 -0
  76. {mage_ai-0.8.10.dist-info → mage_ai-0.8.12.dist-info}/top_level.txt +0 -0
@@ -38,6 +38,7 @@ BlockPolicy.allow_read(BlockPresenter.default_attributes + [], scopes=[
38
38
  ], condition=lambda policy: policy.has_at_least_editor_role())
39
39
 
40
40
  BlockPolicy.allow_read([
41
+ 'bookmarks',
41
42
  'content',
42
43
  'outputs',
43
44
  ] + BlockPresenter.default_attributes, scopes=[
@@ -68,9 +69,11 @@ BlockPolicy.allow_write([
68
69
 
69
70
  BlockPolicy.allow_write([
70
71
  'all_upstream_blocks_executed',
72
+ 'bookmark_values',
71
73
  'color',
72
74
  'configuration',
73
75
  'content',
76
+ 'destination_table',
74
77
  'downstream_blocks',
75
78
  'executor_config',
76
79
  'executor_type',
@@ -80,6 +83,7 @@ BlockPolicy.allow_write([
80
83
  'name',
81
84
  'outputs',
82
85
  'status',
86
+ 'tap_stream_id',
83
87
  'type',
84
88
  'upstream_blocks',
85
89
  'uuid',
@@ -88,3 +92,12 @@ BlockPolicy.allow_write([
88
92
  ], on_action=[
89
93
  constants.UPDATE,
90
94
  ], condition=lambda policy: policy.has_at_least_editor_role())
95
+
96
+ BlockPolicy.allow_query([
97
+ 'destination_table',
98
+ 'state_stream',
99
+ ], scopes=[
100
+ OauthScope.CLIENT_PRIVATE,
101
+ ], on_action=[
102
+ constants.DETAIL,
103
+ ], condition=lambda policy: policy.has_at_least_viewer_role())
@@ -0,0 +1,30 @@
1
+ from mage_ai.api.oauth_scope import OauthScope
2
+ from mage_ai.api.operations import constants
3
+ from mage_ai.api.policies.BasePolicy import BasePolicy
4
+ from mage_ai.api.presenters.SyncPresenter import SyncPresenter
5
+
6
+
7
+ class SyncPolicy(BasePolicy):
8
+ pass
9
+
10
+
11
+ SyncPolicy.allow_read(SyncPresenter.default_attributes, scopes=[
12
+ OauthScope.CLIENT_PRIVATE,
13
+ ], on_action=[
14
+ constants.CREATE,
15
+ constants.UPDATE,
16
+ ], condition=lambda policy: policy.has_at_least_viewer_role())
17
+
18
+ SyncPolicy.allow_write(SyncPresenter.default_attributes, scopes=[
19
+ OauthScope.CLIENT_PRIVATE,
20
+ ], on_action=[
21
+ constants.CREATE,
22
+ ], condition=lambda policy: policy.has_at_least_editor_role())
23
+
24
+ SyncPolicy.allow_write([
25
+ 'action_type',
26
+ ], scopes=[
27
+ OauthScope.CLIENT_PRIVATE,
28
+ ], on_action=[
29
+ constants.UPDATE,
30
+ ], condition=lambda policy: policy.has_at_least_editor_role())
@@ -30,13 +30,24 @@ class BlockPresenter(BasePresenter):
30
30
  if display_format in [constants.CREATE, constants.UPDATE]:
31
31
  return self.model.to_dict(include_content=True)
32
32
  elif display_format in [constants.DETAIL, 'dbt']:
33
- include_outputs = kwargs.get('query', {}).get('include_outputs', [True])
33
+ query = kwargs.get('query', {})
34
+
35
+ include_outputs = query.get('include_outputs', [True])
34
36
  if include_outputs:
35
37
  include_outputs = include_outputs[0]
36
38
 
39
+ state_stream = query.get('state_stream', [None])
40
+ if state_stream:
41
+ state_stream = state_stream[0]
42
+ destination_table = query.get('destination_table', [None])
43
+ if destination_table:
44
+ destination_table = destination_table[0]
45
+
37
46
  data = self.model.to_dict(
47
+ destination_table=destination_table,
38
48
  include_content=True,
39
49
  include_outputs=include_outputs,
50
+ state_stream=state_stream,
40
51
  )
41
52
 
42
53
  if 'dbt' == display_format:
@@ -0,0 +1,11 @@
1
+ from mage_ai.api.presenters.BasePresenter import BasePresenter
2
+
3
+
4
+ class SyncPresenter(BasePresenter):
5
+ default_attributes = [
6
+ 'branch',
7
+ 'remote_repo_link',
8
+ 'repo_path',
9
+ 'sync_on_pipeline_run',
10
+ 'type',
11
+ ]
@@ -53,12 +53,12 @@ class BlockResource(GenericResource):
53
53
  block_type_and_uuid = urllib.parse.unquote(pk)
54
54
  parts = block_type_and_uuid.split('/')
55
55
 
56
- if len(parts) != 2:
56
+ if len(parts) < 2:
57
57
  error.update(message='The url path should be in block_type/block_uuid format.')
58
58
  raise ApiError(error)
59
59
 
60
60
  block_type = parts[0]
61
- block_uuid = parts[1]
61
+ block_uuid = '/'.join(parts[1:])
62
62
  parts2 = block_uuid.split('.')
63
63
  language = None
64
64
  if len(parts2) >= 2:
@@ -78,4 +78,11 @@ class BlockResource(GenericResource):
78
78
 
79
79
  @safe_db_query
80
80
  def update(self, payload, **kwargs):
81
- self.model.update(payload)
81
+ query = kwargs.get('query', {})
82
+ update_state = query.get('update_state', [False])
83
+ if update_state:
84
+ update_state = update_state[0]
85
+ self.model.update(
86
+ payload,
87
+ update_state=update_state,
88
+ )
@@ -0,0 +1,43 @@
1
+ from mage_ai.api.resources.GenericResource import GenericResource
2
+ from mage_ai.data_preparation.preferences import get_preferences
3
+ from mage_ai.data_preparation.sync import SyncType, SyncConfig
4
+ from mage_ai.data_preparation.sync.git_sync import GitSync
5
+
6
+
7
+ class SyncResource(GenericResource):
8
+ @classmethod
9
+ def collection(self, query, meta, user, **kwargs):
10
+ preferences = get_preferences()
11
+ sync_config = preferences.sync_config
12
+ return self.build_result_set(
13
+ [sync_config],
14
+ user,
15
+ **kwargs,
16
+ )
17
+
18
+ @classmethod
19
+ def create(self, payload, user, **kwargs):
20
+ sync_config = SyncConfig.load(config=payload)
21
+ get_preferences().update_preferences(
22
+ dict(sync_config=sync_config.to_dict())
23
+ )
24
+
25
+ if sync_config.type == SyncType.GIT:
26
+ # set up Git repo
27
+ GitSync(sync_config)
28
+
29
+ return self(get_preferences().sync_config, user, **kwargs)
30
+
31
+ @classmethod
32
+ def member(self, pk, user, **kwargs):
33
+ return self(get_preferences().sync_config, user, **kwargs)
34
+
35
+ def update(self, payload, **kwargs):
36
+ sync_config = SyncConfig.load(config=self.model)
37
+ action_type = payload.get('action_type')
38
+ if action_type == 'sync_data':
39
+ if sync_config.type == SyncType.GIT:
40
+ sync = GitSync(sync_config)
41
+ sync.sync_data()
42
+
43
+ return self
@@ -1,6 +1,7 @@
1
1
  from mage_ai.data_preparation.logging.logger import DictLogger
2
2
  from mage_ai.data_preparation.logging.logger_manager_factory import LoggerManagerFactory
3
3
  from mage_ai.data_preparation.models.pipeline import Pipeline
4
+ from mage_ai.shared.hash import merge_dict
4
5
  from typing import Dict
5
6
  import asyncio
6
7
 
@@ -33,3 +34,11 @@ class PipelineExecutor:
33
34
  update_status=update_status,
34
35
  ))
35
36
  self.logger_manager.output_logs_to_destination()
37
+
38
+ def _build_tags(self, **kwargs):
39
+ default_tags = dict(
40
+ pipeline_uuid=self.pipeline.uuid,
41
+ )
42
+ if kwargs.get('pipeline_run_id'):
43
+ default_tags['pipeline_run_id'] = kwargs.get('pipeline_run_id')
44
+ return merge_dict(kwargs.get('tags', {}), default_tags)
@@ -69,10 +69,12 @@ class StreamingPipelineExecutor(PipelineExecutor):
69
69
  # TODOs:
70
70
  # 1. Support multiple sources and sinks
71
71
  # 2. Support flink pipeline
72
+
73
+ tags = self._build_tags(**kwargs)
72
74
  if build_block_output_stdout:
73
75
  stdout = build_block_output_stdout(self.pipeline.uuid)
74
76
  else:
75
- stdout = StreamToLogger(self.logger)
77
+ stdout = StreamToLogger(self.logger, logging_tags=tags)
76
78
  try:
77
79
  with redirect_stdout(stdout):
78
80
  with redirect_stderr(stdout):
@@ -1263,6 +1263,7 @@ df = get_variable('{self.pipeline.uuid}', '{block_uuid}', 'df')
1263
1263
  include_outputs=False,
1264
1264
  sample_count=None,
1265
1265
  check_if_file_exists: bool = False,
1266
+ **kwargs,
1266
1267
  ):
1267
1268
  data = self.to_dict_base()
1268
1269
  if include_content:
@@ -1280,6 +1281,7 @@ df = get_variable('{self.pipeline.uuid}', '{block_uuid}', 'df')
1280
1281
  'Delete the current block to remove it from the pipeline or write code ' +
1281
1282
  f'and save the pipeline to create a new file at {file_path}.',
1282
1283
  )
1284
+
1283
1285
  return data
1284
1286
 
1285
1287
  async def to_dict_async(
@@ -1314,7 +1316,7 @@ df = get_variable('{self.pipeline.uuid}', '{block_uuid}', 'df')
1314
1316
 
1315
1317
  return data
1316
1318
 
1317
- def update(self, data):
1319
+ def update(self, data, **kwargs):
1318
1320
  if 'name' in data and data['name'] != self.name:
1319
1321
  self.__update_name(data['name'])
1320
1322
  if (
@@ -1338,6 +1340,7 @@ df = get_variable('{self.pipeline.uuid}', '{block_uuid}', 'df')
1338
1340
  if self.has_callback:
1339
1341
  CallbackBlock.create(self.uuid)
1340
1342
  self.__update_pipeline_block()
1343
+
1341
1344
  return self
1342
1345
 
1343
1346
  def update_upstream_blocks(self, upstream_blocks: List[Any]) -> None:
@@ -1505,8 +1508,6 @@ df = get_variable('{self.pipeline.uuid}', '{block_uuid}', 'df')
1505
1508
  raise Exception(f'Failed to pass tests for block {self.uuid}')
1506
1509
 
1507
1510
  def analyze_outputs(self, variable_mapping, shape_only: bool = False):
1508
- from mage_ai.data_cleaner.data_cleaner import clean as clean_data
1509
-
1510
1511
  if self.pipeline is None:
1511
1512
  return
1512
1513
  for uuid, data in variable_mapping.items():
@@ -1532,6 +1533,7 @@ df = get_variable('{self.pipeline.uuid}', '{block_uuid}', 'df')
1532
1533
  else:
1533
1534
  data_for_analysis = data.reset_index(drop=True)
1534
1535
  try:
1536
+ from mage_ai.data_cleaner.data_cleaner import clean as clean_data
1535
1537
  analysis = clean_data(
1536
1538
  data_for_analysis,
1537
1539
  df_original=data,
@@ -314,6 +314,65 @@ class SourceBlock(IntegrationBlock):
314
314
 
315
315
 
316
316
  class DestinationBlock(IntegrationBlock):
317
+ def to_dict(
318
+ self,
319
+ include_content=False,
320
+ include_outputs=False,
321
+ sample_count=None,
322
+ check_if_file_exists: bool = False,
323
+ destination_table: str = None,
324
+ state_stream: str = None,
325
+ ):
326
+ data = {}
327
+ if state_stream and destination_table:
328
+ from mage_ai.data_preparation.models.pipelines.integration_pipeline \
329
+ import IntegrationPipeline
330
+ integration_pipeline = IntegrationPipeline(self.pipeline.uuid)
331
+ destination_state_file_path = integration_pipeline.destination_state_file_path(
332
+ destination_table=destination_table,
333
+ stream=state_stream,
334
+ )
335
+ if os.path.isfile(destination_state_file_path):
336
+ with open(destination_state_file_path, 'r') as f:
337
+ text = f.read()
338
+ d = json.loads(text) if text else {}
339
+ bookmark_values = d.get('bookmarks', {}).get(state_stream)
340
+ data['bookmarks'] = bookmark_values
341
+
342
+ return merge_dict(
343
+ super().to_dict(
344
+ include_content,
345
+ include_outputs,
346
+ sample_count,
347
+ check_if_file_exists,
348
+ ),
349
+ data,
350
+ )
351
+
352
+ def update(self, data, update_state=False):
353
+ if update_state:
354
+ from mage_ai.data_preparation.models.pipelines.integration_pipeline \
355
+ import IntegrationPipeline
356
+ from mage_integrations.destinations.utils \
357
+ import update_destination_state_bookmarks
358
+
359
+ integration_pipeline = IntegrationPipeline(self.pipeline.uuid)
360
+ tap_stream_id = data.get('tap_stream_id')
361
+ destination_table = data.get('destination_table')
362
+ bookmark_values = data.get('bookmark_values', {})
363
+ if tap_stream_id and destination_table:
364
+ destination_state_file_path = integration_pipeline.destination_state_file_path(
365
+ destination_table=destination_table,
366
+ stream=tap_stream_id,
367
+ )
368
+ update_destination_state_bookmarks(
369
+ destination_state_file_path,
370
+ tap_stream_id,
371
+ bookmark_values=bookmark_values
372
+ )
373
+
374
+ return super().update(data)
375
+
317
376
  def output_variables(self, execution_partition: str = None) -> List[str]:
318
377
  return []
319
378
 
@@ -2,6 +2,7 @@ from enum import Enum
2
2
 
3
3
  PIPELINES_FOLDER = 'pipelines'
4
4
  PIPELINE_CONFIG_FILE = 'metadata.yaml'
5
+ PREFERENCES_FILE = '.preferences.yaml'
5
6
  DATA_INTEGRATION_CATALOG_FILE = 'data_integration_catalog.json'
6
7
 
7
8
 
@@ -0,0 +1,43 @@
1
+ from typing import Dict
2
+ from mage_ai.data_preparation.models.constants import PREFERENCES_FILE
3
+ from mage_ai.data_preparation.repo_manager import get_repo_path
4
+ import os
5
+ import traceback
6
+ import yaml
7
+
8
+
9
+ class Preferences:
10
+ def __init__(self, repo_path: str = None, config_dict: Dict = None):
11
+ self.repo_path = repo_path or get_repo_path()
12
+ self.preferences_file_path = \
13
+ os.path.join(self.repo_path, PREFERENCES_FILE)
14
+
15
+ try:
16
+ if not config_dict:
17
+ if os.path.exists(self.preferences_file_path):
18
+ with open(self.preferences_file_path) as f:
19
+ preferences = yaml.full_load(f.read()) or {}
20
+ else:
21
+ preferences = dict()
22
+ else:
23
+ preferences = config_dict
24
+
25
+ self.sync_config = preferences.get('sync_config', dict())
26
+ except Exception:
27
+ traceback.print_exc()
28
+ pass
29
+
30
+ def update_preferences(self, updates: Dict):
31
+ preferences = self.to_dict()
32
+ preferences.update(updates)
33
+ with open(self.preferences_file_path, 'w') as f:
34
+ yaml.dump(preferences, f)
35
+
36
+ def to_dict(self) -> Dict:
37
+ return dict(
38
+ sync_config=self.sync_config
39
+ )
40
+
41
+
42
+ def get_preferences(repo_path=None) -> Preferences:
43
+ return Preferences(repo_path=repo_path)
@@ -0,0 +1,17 @@
1
+ from dataclasses import dataclass
2
+ from enum import Enum
3
+ from mage_ai.shared.config import BaseConfig
4
+ import os
5
+
6
+
7
+ class SyncType(str, Enum):
8
+ GIT = 'git'
9
+
10
+
11
+ @dataclass
12
+ class SyncConfig(BaseConfig):
13
+ type: SyncType
14
+ remote_repo_link: str
15
+ repo_path: str = os.getcwd()
16
+ branch: str = 'main'
17
+ sync_on_pipeline_run: bool = False
@@ -0,0 +1,7 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class BaseSync(ABC):
5
+ @abstractmethod
6
+ def sync_data(self) -> None:
7
+ pass
@@ -0,0 +1,26 @@
1
+ from mage_ai.data_preparation.sync import SyncConfig
2
+ from mage_ai.data_preparation.sync.base_sync import BaseSync
3
+ from mage_ai.shared.logger import VerboseFunctionExec
4
+ import git
5
+
6
+
7
+ class GitSync(BaseSync):
8
+ def __init__(self, sync_config: SyncConfig):
9
+ self.remote_repo_link = sync_config.remote_repo_link
10
+ self.repo_path = sync_config.repo_path
11
+ self.branch = sync_config.branch
12
+ try:
13
+ self.repo = git.Repo(self.repo_path)
14
+ except git.exc.InvalidGitRepositoryError:
15
+ self.repo = git.Repo.init(self.repo_path)
16
+ self.repo.create_remote('origin', self.remote_repo_link)
17
+
18
+ self.origin = self.repo.remotes.origin
19
+
20
+ def sync_data(self):
21
+ with VerboseFunctionExec(
22
+ f'Syncing data with remote repo {self.remote_repo_link}',
23
+ verbose=True,
24
+ ):
25
+ self.origin.fetch(kill_after_timeout=60)
26
+ self.repo.git.reset('--hard', f'origin/{self.branch}')
@@ -18,3 +18,8 @@ consumer_group: unique_consumer_group
18
18
  # mechanism: "PLAIN"
19
19
  # username: username
20
20
  # password: password
21
+
22
+ # Uncomment the config below to use protobuf schema to deserialize message
23
+ # serde_config:
24
+ # serialization_method: PROTOBUF
25
+ # schema_classpath: "path.to.schema.SchemaClass"
@@ -76,6 +76,11 @@ class BaseModel(Base):
76
76
  def full_clean(self, **kwargs) -> None:
77
77
  pass
78
78
 
79
+ @classmethod
80
+ @safe_db_query
81
+ def get(self, uuid):
82
+ return self.query.get(uuid)
83
+
79
84
  def save(self, commit=True) -> None:
80
85
  self.session.add(self)
81
86
  if commit:
@@ -667,6 +672,15 @@ class Backfill(BaseModel):
667
672
 
668
673
  pipeline_runs = relationship('PipelineRun', back_populates='backfill')
669
674
 
675
+ @classmethod
676
+ @safe_db_query
677
+ def filter(self, pipeline_schedule_ids: List = None):
678
+ if pipeline_schedule_ids is not None:
679
+ return Backfill.query.filter(
680
+ Backfill.pipeline_schedule_id.in_(pipeline_schedule_ids),
681
+ )
682
+ return []
683
+
670
684
 
671
685
  class Secret(BaseModel):
672
686
  name = Column(String(255), unique=True)
@@ -14,7 +14,10 @@ from mage_ai.data_preparation.models.block.utils import (
14
14
  from mage_ai.data_preparation.models.constants import PipelineType
15
15
  from mage_ai.data_preparation.models.pipeline import Pipeline
16
16
  from mage_ai.data_preparation.models.pipelines.integration_pipeline import IntegrationPipeline
17
+ from mage_ai.data_preparation.preferences import get_preferences
17
18
  from mage_ai.data_preparation.repo_manager import get_repo_config, get_repo_path
19
+ from mage_ai.data_preparation.sync import SyncConfig
20
+ from mage_ai.data_preparation.sync.git_sync import GitSync
18
21
  from mage_ai.data_preparation.variable_manager import get_global_variables
19
22
  from mage_ai.orchestration.db.models import (
20
23
  Backfill,
@@ -58,6 +61,12 @@ class PipelineScheduler:
58
61
  )
59
62
 
60
63
  def start(self, should_schedule: bool = True) -> None:
64
+ if get_preferences().sync_config:
65
+ sync_config = SyncConfig.load(config=get_preferences().sync_config)
66
+ if sync_config.sync_on_pipeline_run:
67
+ sync = GitSync(sync_config)
68
+ sync.sync_data()
69
+
61
70
  if self.pipeline_run.status == PipelineRun.PipelineRunStatus.RUNNING:
62
71
  return
63
72
  self.pipeline_run.update(status=PipelineRun.PipelineRunStatus.RUNNING)
@@ -126,7 +135,7 @@ class PipelineScheduler:
126
135
  )
127
136
  self.logger_manager.output_logs_to_destination()
128
137
 
129
- schedule = PipelineSchedule.query.get(
138
+ schedule = PipelineSchedule.get(
130
139
  self.pipeline_run.pipeline_schedule_id,
131
140
  )
132
141
 
@@ -735,9 +744,8 @@ def schedule_all():
735
744
  active_pipeline_schedules = \
736
745
  list(PipelineSchedule.active_schedules(pipeline_uuids=repo_pipelines))
737
746
 
738
- backfills = Backfill.query.filter(
739
- Backfill.pipeline_schedule_id.in_([ps.id for ps in active_pipeline_schedules]),
740
- )
747
+ backfills = Backfill.filter(pipeline_schedule_ids=[ps.id for ps in active_pipeline_schedules])
748
+
741
749
  backfills_by_pipeline_schedule_id = index_by(
742
750
  lambda backfill: backfill.pipeline_schedule_id,
743
751
  backfills,
@@ -12,4 +12,4 @@ DATAFRAME_OUTPUT_SAMPLE_COUNT = 10
12
12
  # Dockerfile depends on it because it runs ./scripts/install_mage.sh and uses
13
13
  # the last line to determine the version to install.
14
14
  VERSION = \
15
- '0.8.10'
15
+ '0.8.12'
@@ -1,4 +1,4 @@
1
- <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=0" name="viewport"/><title>404: This page could not be found</title><meta name="next-head-count" content="3"/><link href="/favicon.ico" rel="icon"/><link rel="preload" href="/_next/static/css/d1e8e64d0b07af2f.css" as="style"/><link rel="stylesheet" href="/_next/static/css/d1e8e64d0b07af2f.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-5cd94c89d3acac5f.js"></script><script src="/_next/static/chunks/webpack-bc5e4eb2c1ff587c.js" defer=""></script><script src="/_next/static/chunks/framework-7c365855dab1bf41.js" defer=""></script><script src="/_next/static/chunks/main-bb0dd5375146d7fd.js" defer=""></script><script src="/_next/static/chunks/pages/_app-44766f29c8c5b4ce.js" defer=""></script><script src="/_next/static/chunks/pages/_error-235304e5badb19eb.js" defer=""></script><script src="/_next/static/avIy1qfPFOamteWu3WLo7/_buildManifest.js" defer=""></script><script src="/_next/static/avIy1qfPFOamteWu3WLo7/_ssgManifest.js" defer=""></script><script src="/_next/static/avIy1qfPFOamteWu3WLo7/_middlewareManifest.js" defer=""></script><style data-styled="" data-styled-version="5.3.6">html{-webkit-box-sizing:border-box;box-sizing:border-box;-ms-overflow-style:scrollbar;}/*!sc*/
1
+ <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=0" name="viewport"/><title>404: This page could not be found</title><meta name="next-head-count" content="3"/><link href="/favicon.ico" rel="icon"/><link rel="preload" href="/_next/static/css/d1e8e64d0b07af2f.css" as="style"/><link rel="stylesheet" href="/_next/static/css/d1e8e64d0b07af2f.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-5cd94c89d3acac5f.js"></script><script src="/_next/static/chunks/webpack-bc5e4eb2c1ff587c.js" defer=""></script><script src="/_next/static/chunks/framework-7c365855dab1bf41.js" defer=""></script><script src="/_next/static/chunks/main-bb0dd5375146d7fd.js" defer=""></script><script src="/_next/static/chunks/pages/_app-77b4b367fdb247d6.js" defer=""></script><script src="/_next/static/chunks/pages/_error-235304e5badb19eb.js" defer=""></script><script src="/_next/static/BJSgpMeWTfdkZw_YRDpOz/_buildManifest.js" defer=""></script><script src="/_next/static/BJSgpMeWTfdkZw_YRDpOz/_ssgManifest.js" defer=""></script><script src="/_next/static/BJSgpMeWTfdkZw_YRDpOz/_middlewareManifest.js" defer=""></script><style data-styled="" data-styled-version="5.3.6">html{-webkit-box-sizing:border-box;box-sizing:border-box;-ms-overflow-style:scrollbar;}/*!sc*/
2
2
  *,*::before,*::after{-webkit-box-sizing:inherit;box-sizing:inherit;}/*!sc*/
3
3
  data-styled.g4[id="sc-global-czSCUT1"]{content:"sc-global-czSCUT1,"}/*!sc*/
4
4
  .kOVcuR .Toastify__toast-container{margin-top:24px;padding:0 !important;width:500px !important;}/*!sc*/
@@ -19,4 +19,4 @@ data-styled.g5[id="ToastWrapper-sc-1a33ph1-0"]{content:"kOVcuR,"}/*!sc*/
19
19
  .next-error-h1 {
20
20
  border-right: 1px solid rgba(255, 255, 255, .3);
21
21
  }
22
- }</style><h1 class="next-error-h1" style="display:inline-block;margin:0;margin-right:20px;padding:10px 23px 10px 0;font-size:24px;font-weight:500;vertical-align:top">404<!-- --></h1><div style="display:inline-block;text-align:left;line-height:49px;height:49px;vertical-align:middle"><h2 style="font-size:14px;font-weight:normal;line-height:inherit;margin:0;padding:0">This page could not be found<!-- -->.<!-- --></h2></div></div></div><div></div><div></div><div class="ToastWrapper-sc-1a33ph1-0 kOVcuR"><div class="Toastify"></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404},"currentTheme":{"accent":{"alert":"#F6540B","blue":"#4877FF","blueLight":"rgba(72, 119, 255, 0.5)","contentDefaultTransparent":"rgba(174, 174, 174, 0.5)","cyan":"#65E3FF","cyanTransparent":"rgba(101, 227, 255, 0.12)","dbt":"#fc6949","dbtLight":"rgba(252, 105, 73, 0.5)","info":"#00ABFF","infoTransparent":"rgba(0, 171, 255, 0.5)","negative":"#FF1E59","negativeTransparent":"rgba(255, 30, 89, 0.3)","pink":"#FF4FF8","pinkLight":"#FFB9FC","positive":"#00A81A","primaryTransparent":"rgba(155, 108, 167, 0.5)","purple":"#7D55EC","purpleLight":"rgba(125, 85, 236, 0.5)","teal":"#00B4CC","tealLight":"rgba(0, 180, 204, 0.5)","warning":"#DD9900","warningTransparent":"rgba(221, 153, 0, 0.5)","yellow":"#FFCC19","yellowLight":"rgba(255, 204, 25, 0.5)"},"background":{"chartBlock":"#2E3036","codeArea":"#1E1F24","codeTextarea":"#000000","content":"#1B1C20","danger":"#FFD0DB","dark":"#B1B8C3","header":"#1B1B1B","menu":"#0F4CFF","muted":"#F9FAFC","navigation":"#EDEDED","output":"#2E3036","page":"#1E1F24","panel":"#232429","popup":"#27292E","row":"#2C2C2C","row2":"#51535C","scrollbarThumb":"rgba(100, 100, 100, 0.5)","scrollbarThumbHover":"rgba(255, 255, 255, 0.3)","scrollbarTrack":"#2E3036","success":"#8ADE00","table":"#292A2F"},"borders":{"contrast":"#FFFFFF","danger":"#FF144D","dark":"#000000","info":"#FFCC19","light":"#2F3034","medium":"#1C1C1C","success":"#2FCB52"},"brand":{"earth100":"#C6EEDB","earth200":"#9DDFBF","earth300":"#6BBF96","earth400":"#37A46F","earth400Transparent":"rgba(55, 164, 111, 0.4)","earth500":"#00954C","energy100":"#FFF4BA","energy200":"#FFED92","energy300":"#FFE662","energy400":"#FFDA19","energy400Transparent":"rgba(255, 218, 25, 0.04)","energy500":"#F6C000","fire100":"#FFD7E0","fire200":"#FFA3B9","fire300":"#FF547D","fire400":"#FF144D","fire400Transparent":"rgba(255, 20, 77, 0.4)","fire500":"#EB0032","stone100":"#F3E6D7","stone200":"#E3D4C2","stone400":"#BFA78B","stone500":"#AF8859","water100":"#BDCEFF","water200":"#81A1FF","water300":"#517DFF","water400":"#2A60FE","water400Transparent":"rgba(42, 96, 254, 0.4)","water500":"#0F4CFF","wind100":"#EEEAFF","wind200":"#CCC1F4","wind300":"#A698DD","wind400":"#6B50D7","wind400SuperTransparent":"rgba(107, 80, 215, 0.12)","wind400Transparent":"rgba(107, 80, 215, 0.4)","wind500":"#4E32BC"},"chart":{"backgroundPrimary":"#7D55EC","backgroundSecondary":"#FF144D","backgroundTertiary":"#86E2FF","button1":"#4877FF","button2":"#FFCC19","button3":"#8ADE00","button4":"#FF4FF8","button5":"#B98D95","lines":"#9B6CA7","primary":"#6B50D7","secondary":"#FF144D","tertiary":"#2A60FE"},"content":{"active":"#FFFFFF","default":"#AEAEAE","disabled":"rgba(255, 255, 255, 0.3)","inverted":"#2C2C2C","muted":"#787A85"},"elevation":{"visualizationAccent":"#996CFF","visualizationAccentAlt":"#C1ACF7"},"feature":{"active":"rgba(250, 248, 254, 0.14)","disabled":"rgba(201, 206, 218, 0.12)"},"icons":{"neutral":"#787878"},"interactive":{"activeBorder":"#060606","checked":"#060606","dangerBorder":"#FF144D","defaultBackground":"#36383F","defaultBorder":"#1C1C1C","disabledBorder":"#B1B8C3","focusBackground":"#B1B8C3","focusBorder":"#86E2FF","hoverBackground":"#4E4E4E","hoverBorder":"#B9BFCA","hoverOverlay":"rgba(255, 255, 255, 0.1)","linkPrimary":"#1752FF","linkPrimaryHover":"#4877FF","linkSecondary":"#6B50D7","linkSecondaryDisabled":"#C4B9EF","rowHoverBackground":"rgba(0, 0, 0, 0.1)"},"loader":{"color":"#EB0032","colorInverted":"#8ADE00"},"logo":{"color":"#FFFFFF"},"monotone":{"black":"#060606","blackTransparent":"rgba(0, 0, 0, 0.6)","gray":"#B1B8C3","grey100":"#F2F2F2","grey200":"#D5D7DC","grey300":"#B4B8C0","grey400":"#70747C","grey500":"#51535C","purple":"#6B50D7","white":"#FFFFFF"},"neutral":{"n100":"#E7E8EA","n200":"#D8DADE","n300":"#CBCCD0","n400":"#BCBEC4","n500":"#AEB0B6"},"progress":{"negative":"#FF144D","positive":"#6B50D7"},"shadow":{"base":"12px 40px 120px rgba(106, 117, 139, 0.4)","menu":"4px 10px 20px rgba(6, 6, 6, 0.12)","popup":"10px 20px 40px rgba(0, 0, 0, 0.2)","small":"0px, 4px, rgba(0, 0, 0, 0.25)","window":"0px 10px 60px rgba(0, 0, 0, 0.7)"},"status":{"negative":"#FF144D","positive":"#24B400"},"text":{"fileBrowser":"#787A85"}}},"page":"/_error","query":{},"buildId":"avIy1qfPFOamteWu3WLo7","nextExport":true,"isFallback":false,"gip":true,"appGip":true,"scriptLoader":[]}</script></body></html>
22
+ }</style><h1 class="next-error-h1" style="display:inline-block;margin:0;margin-right:20px;padding:10px 23px 10px 0;font-size:24px;font-weight:500;vertical-align:top">404<!-- --></h1><div style="display:inline-block;text-align:left;line-height:49px;height:49px;vertical-align:middle"><h2 style="font-size:14px;font-weight:normal;line-height:inherit;margin:0;padding:0">This page could not be found<!-- -->.<!-- --></h2></div></div></div><div></div><div></div><div class="ToastWrapper-sc-1a33ph1-0 kOVcuR"><div class="Toastify"></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404},"currentTheme":{"accent":{"alert":"#F6540B","blue":"#4877FF","blueLight":"rgba(72, 119, 255, 0.5)","contentDefaultTransparent":"rgba(174, 174, 174, 0.5)","cyan":"#65E3FF","cyanTransparent":"rgba(101, 227, 255, 0.12)","dbt":"#fc6949","dbtLight":"rgba(252, 105, 73, 0.5)","info":"#00ABFF","infoTransparent":"rgba(0, 171, 255, 0.5)","negative":"#FF1E59","negativeTransparent":"rgba(255, 30, 89, 0.3)","pink":"#FF4FF8","pinkLight":"#FFB9FC","positive":"#00A81A","primaryTransparent":"rgba(155, 108, 167, 0.5)","purple":"#7D55EC","purpleLight":"rgba(125, 85, 236, 0.5)","teal":"#00B4CC","tealLight":"rgba(0, 180, 204, 0.5)","warning":"#DD9900","warningTransparent":"rgba(221, 153, 0, 0.5)","yellow":"#FFCC19","yellowLight":"rgba(255, 204, 25, 0.5)"},"background":{"chartBlock":"#2E3036","codeArea":"#1E1F24","codeTextarea":"#000000","content":"#1B1C20","danger":"#FFD0DB","dark":"#B1B8C3","header":"#1B1B1B","menu":"#0F4CFF","muted":"#F9FAFC","navigation":"#EDEDED","output":"#2E3036","page":"#1E1F24","panel":"#232429","popup":"#27292E","row":"#2C2C2C","row2":"#51535C","scrollbarThumb":"rgba(100, 100, 100, 0.5)","scrollbarThumbHover":"rgba(255, 255, 255, 0.3)","scrollbarTrack":"#2E3036","success":"#8ADE00","table":"#292A2F"},"borders":{"contrast":"#FFFFFF","danger":"#FF144D","dark":"#000000","info":"#FFCC19","light":"#2F3034","medium":"#1C1C1C","success":"#2FCB52"},"brand":{"earth100":"#C6EEDB","earth200":"#9DDFBF","earth300":"#6BBF96","earth400":"#37A46F","earth400Transparent":"rgba(55, 164, 111, 0.4)","earth500":"#00954C","energy100":"#FFF4BA","energy200":"#FFED92","energy300":"#FFE662","energy400":"#FFDA19","energy400Transparent":"rgba(255, 218, 25, 0.04)","energy500":"#F6C000","fire100":"#FFD7E0","fire200":"#FFA3B9","fire300":"#FF547D","fire400":"#FF144D","fire400Transparent":"rgba(255, 20, 77, 0.4)","fire500":"#EB0032","stone100":"#F3E6D7","stone200":"#E3D4C2","stone400":"#BFA78B","stone500":"#AF8859","water100":"#BDCEFF","water200":"#81A1FF","water300":"#517DFF","water400":"#2A60FE","water400Transparent":"rgba(42, 96, 254, 0.4)","water500":"#0F4CFF","wind100":"#EEEAFF","wind200":"#CCC1F4","wind300":"#A698DD","wind400":"#6B50D7","wind400SuperTransparent":"rgba(107, 80, 215, 0.12)","wind400Transparent":"rgba(107, 80, 215, 0.4)","wind500":"#4E32BC"},"chart":{"backgroundPrimary":"#7D55EC","backgroundSecondary":"#FF144D","backgroundTertiary":"#86E2FF","button1":"#4877FF","button2":"#FFCC19","button3":"#8ADE00","button4":"#FF4FF8","button5":"#B98D95","lines":"#9B6CA7","primary":"#6B50D7","secondary":"#FF144D","tertiary":"#2A60FE"},"content":{"active":"#FFFFFF","default":"#AEAEAE","disabled":"rgba(255, 255, 255, 0.3)","inverted":"#2C2C2C","muted":"#787A85"},"elevation":{"visualizationAccent":"#996CFF","visualizationAccentAlt":"#C1ACF7"},"feature":{"active":"rgba(250, 248, 254, 0.14)","disabled":"rgba(201, 206, 218, 0.12)"},"icons":{"neutral":"#787878"},"interactive":{"activeBorder":"#060606","checked":"#060606","dangerBorder":"#FF144D","defaultBackground":"#36383F","defaultBorder":"#1C1C1C","disabledBorder":"#B1B8C3","focusBackground":"#B1B8C3","focusBorder":"#86E2FF","hoverBackground":"#4E4E4E","hoverBorder":"#B9BFCA","hoverOverlay":"rgba(255, 255, 255, 0.1)","linkPrimary":"#1752FF","linkPrimaryHover":"#4877FF","linkSecondary":"#6B50D7","linkSecondaryDisabled":"#C4B9EF","rowHoverBackground":"rgba(0, 0, 0, 0.1)"},"loader":{"color":"#EB0032","colorInverted":"#8ADE00"},"logo":{"color":"#FFFFFF"},"monotone":{"black":"#060606","blackTransparent":"rgba(0, 0, 0, 0.6)","gray":"#B1B8C3","grey100":"#F2F2F2","grey200":"#D5D7DC","grey300":"#B4B8C0","grey400":"#70747C","grey500":"#51535C","purple":"#6B50D7","white":"#FFFFFF"},"neutral":{"n100":"#E7E8EA","n200":"#D8DADE","n300":"#CBCCD0","n400":"#BCBEC4","n500":"#AEB0B6"},"progress":{"negative":"#FF144D","positive":"#6B50D7"},"shadow":{"base":"12px 40px 120px rgba(106, 117, 139, 0.4)","menu":"4px 10px 20px rgba(6, 6, 6, 0.12)","popup":"10px 20px 40px rgba(0, 0, 0, 0.2)","small":"0px, 4px, rgba(0, 0, 0, 0.25)","window":"0px 10px 60px rgba(0, 0, 0, 0.7)"},"status":{"negative":"#FF144D","positive":"#24B400"},"text":{"fileBrowser":"#787A85"}}},"page":"/_error","query":{},"buildId":"BJSgpMeWTfdkZw_YRDpOz","nextExport":true,"isFallback":false,"gip":true,"appGip":true,"scriptLoader":[]}</script></body></html>
@@ -1,4 +1,4 @@
1
- <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=0" name="viewport"/><title>404: This page could not be found</title><meta name="next-head-count" content="3"/><link href="/favicon.ico" rel="icon"/><link rel="preload" href="/_next/static/css/d1e8e64d0b07af2f.css" as="style"/><link rel="stylesheet" href="/_next/static/css/d1e8e64d0b07af2f.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-5cd94c89d3acac5f.js"></script><script src="/_next/static/chunks/webpack-bc5e4eb2c1ff587c.js" defer=""></script><script src="/_next/static/chunks/framework-7c365855dab1bf41.js" defer=""></script><script src="/_next/static/chunks/main-bb0dd5375146d7fd.js" defer=""></script><script src="/_next/static/chunks/pages/_app-44766f29c8c5b4ce.js" defer=""></script><script src="/_next/static/chunks/pages/_error-235304e5badb19eb.js" defer=""></script><script src="/_next/static/avIy1qfPFOamteWu3WLo7/_buildManifest.js" defer=""></script><script src="/_next/static/avIy1qfPFOamteWu3WLo7/_ssgManifest.js" defer=""></script><script src="/_next/static/avIy1qfPFOamteWu3WLo7/_middlewareManifest.js" defer=""></script><style data-styled="" data-styled-version="5.3.6">html{-webkit-box-sizing:border-box;box-sizing:border-box;-ms-overflow-style:scrollbar;}/*!sc*/
1
+ <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=0" name="viewport"/><title>404: This page could not be found</title><meta name="next-head-count" content="3"/><link href="/favicon.ico" rel="icon"/><link rel="preload" href="/_next/static/css/d1e8e64d0b07af2f.css" as="style"/><link rel="stylesheet" href="/_next/static/css/d1e8e64d0b07af2f.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-5cd94c89d3acac5f.js"></script><script src="/_next/static/chunks/webpack-bc5e4eb2c1ff587c.js" defer=""></script><script src="/_next/static/chunks/framework-7c365855dab1bf41.js" defer=""></script><script src="/_next/static/chunks/main-bb0dd5375146d7fd.js" defer=""></script><script src="/_next/static/chunks/pages/_app-77b4b367fdb247d6.js" defer=""></script><script src="/_next/static/chunks/pages/_error-235304e5badb19eb.js" defer=""></script><script src="/_next/static/BJSgpMeWTfdkZw_YRDpOz/_buildManifest.js" defer=""></script><script src="/_next/static/BJSgpMeWTfdkZw_YRDpOz/_ssgManifest.js" defer=""></script><script src="/_next/static/BJSgpMeWTfdkZw_YRDpOz/_middlewareManifest.js" defer=""></script><style data-styled="" data-styled-version="5.3.6">html{-webkit-box-sizing:border-box;box-sizing:border-box;-ms-overflow-style:scrollbar;}/*!sc*/
2
2
  *,*::before,*::after{-webkit-box-sizing:inherit;box-sizing:inherit;}/*!sc*/
3
3
  data-styled.g4[id="sc-global-czSCUT1"]{content:"sc-global-czSCUT1,"}/*!sc*/
4
4
  .kOVcuR .Toastify__toast-container{margin-top:24px;padding:0 !important;width:500px !important;}/*!sc*/
@@ -19,4 +19,4 @@ data-styled.g5[id="ToastWrapper-sc-1a33ph1-0"]{content:"kOVcuR,"}/*!sc*/
19
19
  .next-error-h1 {
20
20
  border-right: 1px solid rgba(255, 255, 255, .3);
21
21
  }
22
- }</style><h1 class="next-error-h1" style="display:inline-block;margin:0;margin-right:20px;padding:10px 23px 10px 0;font-size:24px;font-weight:500;vertical-align:top">404<!-- --></h1><div style="display:inline-block;text-align:left;line-height:49px;height:49px;vertical-align:middle"><h2 style="font-size:14px;font-weight:normal;line-height:inherit;margin:0;padding:0">This page could not be found<!-- -->.<!-- --></h2></div></div></div><div></div><div></div><div class="ToastWrapper-sc-1a33ph1-0 kOVcuR"><div class="Toastify"></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404},"currentTheme":{"accent":{"alert":"#F6540B","blue":"#4877FF","blueLight":"rgba(72, 119, 255, 0.5)","contentDefaultTransparent":"rgba(174, 174, 174, 0.5)","cyan":"#65E3FF","cyanTransparent":"rgba(101, 227, 255, 0.12)","dbt":"#fc6949","dbtLight":"rgba(252, 105, 73, 0.5)","info":"#00ABFF","infoTransparent":"rgba(0, 171, 255, 0.5)","negative":"#FF1E59","negativeTransparent":"rgba(255, 30, 89, 0.3)","pink":"#FF4FF8","pinkLight":"#FFB9FC","positive":"#00A81A","primaryTransparent":"rgba(155, 108, 167, 0.5)","purple":"#7D55EC","purpleLight":"rgba(125, 85, 236, 0.5)","teal":"#00B4CC","tealLight":"rgba(0, 180, 204, 0.5)","warning":"#DD9900","warningTransparent":"rgba(221, 153, 0, 0.5)","yellow":"#FFCC19","yellowLight":"rgba(255, 204, 25, 0.5)"},"background":{"chartBlock":"#2E3036","codeArea":"#1E1F24","codeTextarea":"#000000","content":"#1B1C20","danger":"#FFD0DB","dark":"#B1B8C3","header":"#1B1B1B","menu":"#0F4CFF","muted":"#F9FAFC","navigation":"#EDEDED","output":"#2E3036","page":"#1E1F24","panel":"#232429","popup":"#27292E","row":"#2C2C2C","row2":"#51535C","scrollbarThumb":"rgba(100, 100, 100, 0.5)","scrollbarThumbHover":"rgba(255, 255, 255, 0.3)","scrollbarTrack":"#2E3036","success":"#8ADE00","table":"#292A2F"},"borders":{"contrast":"#FFFFFF","danger":"#FF144D","dark":"#000000","info":"#FFCC19","light":"#2F3034","medium":"#1C1C1C","success":"#2FCB52"},"brand":{"earth100":"#C6EEDB","earth200":"#9DDFBF","earth300":"#6BBF96","earth400":"#37A46F","earth400Transparent":"rgba(55, 164, 111, 0.4)","earth500":"#00954C","energy100":"#FFF4BA","energy200":"#FFED92","energy300":"#FFE662","energy400":"#FFDA19","energy400Transparent":"rgba(255, 218, 25, 0.04)","energy500":"#F6C000","fire100":"#FFD7E0","fire200":"#FFA3B9","fire300":"#FF547D","fire400":"#FF144D","fire400Transparent":"rgba(255, 20, 77, 0.4)","fire500":"#EB0032","stone100":"#F3E6D7","stone200":"#E3D4C2","stone400":"#BFA78B","stone500":"#AF8859","water100":"#BDCEFF","water200":"#81A1FF","water300":"#517DFF","water400":"#2A60FE","water400Transparent":"rgba(42, 96, 254, 0.4)","water500":"#0F4CFF","wind100":"#EEEAFF","wind200":"#CCC1F4","wind300":"#A698DD","wind400":"#6B50D7","wind400SuperTransparent":"rgba(107, 80, 215, 0.12)","wind400Transparent":"rgba(107, 80, 215, 0.4)","wind500":"#4E32BC"},"chart":{"backgroundPrimary":"#7D55EC","backgroundSecondary":"#FF144D","backgroundTertiary":"#86E2FF","button1":"#4877FF","button2":"#FFCC19","button3":"#8ADE00","button4":"#FF4FF8","button5":"#B98D95","lines":"#9B6CA7","primary":"#6B50D7","secondary":"#FF144D","tertiary":"#2A60FE"},"content":{"active":"#FFFFFF","default":"#AEAEAE","disabled":"rgba(255, 255, 255, 0.3)","inverted":"#2C2C2C","muted":"#787A85"},"elevation":{"visualizationAccent":"#996CFF","visualizationAccentAlt":"#C1ACF7"},"feature":{"active":"rgba(250, 248, 254, 0.14)","disabled":"rgba(201, 206, 218, 0.12)"},"icons":{"neutral":"#787878"},"interactive":{"activeBorder":"#060606","checked":"#060606","dangerBorder":"#FF144D","defaultBackground":"#36383F","defaultBorder":"#1C1C1C","disabledBorder":"#B1B8C3","focusBackground":"#B1B8C3","focusBorder":"#86E2FF","hoverBackground":"#4E4E4E","hoverBorder":"#B9BFCA","hoverOverlay":"rgba(255, 255, 255, 0.1)","linkPrimary":"#1752FF","linkPrimaryHover":"#4877FF","linkSecondary":"#6B50D7","linkSecondaryDisabled":"#C4B9EF","rowHoverBackground":"rgba(0, 0, 0, 0.1)"},"loader":{"color":"#EB0032","colorInverted":"#8ADE00"},"logo":{"color":"#FFFFFF"},"monotone":{"black":"#060606","blackTransparent":"rgba(0, 0, 0, 0.6)","gray":"#B1B8C3","grey100":"#F2F2F2","grey200":"#D5D7DC","grey300":"#B4B8C0","grey400":"#70747C","grey500":"#51535C","purple":"#6B50D7","white":"#FFFFFF"},"neutral":{"n100":"#E7E8EA","n200":"#D8DADE","n300":"#CBCCD0","n400":"#BCBEC4","n500":"#AEB0B6"},"progress":{"negative":"#FF144D","positive":"#6B50D7"},"shadow":{"base":"12px 40px 120px rgba(106, 117, 139, 0.4)","menu":"4px 10px 20px rgba(6, 6, 6, 0.12)","popup":"10px 20px 40px rgba(0, 0, 0, 0.2)","small":"0px, 4px, rgba(0, 0, 0, 0.25)","window":"0px 10px 60px rgba(0, 0, 0, 0.7)"},"status":{"negative":"#FF144D","positive":"#24B400"},"text":{"fileBrowser":"#787A85"}}},"page":"/_error","query":{},"buildId":"avIy1qfPFOamteWu3WLo7","nextExport":true,"isFallback":false,"gip":true,"appGip":true,"scriptLoader":[]}</script></body></html>
22
+ }</style><h1 class="next-error-h1" style="display:inline-block;margin:0;margin-right:20px;padding:10px 23px 10px 0;font-size:24px;font-weight:500;vertical-align:top">404<!-- --></h1><div style="display:inline-block;text-align:left;line-height:49px;height:49px;vertical-align:middle"><h2 style="font-size:14px;font-weight:normal;line-height:inherit;margin:0;padding:0">This page could not be found<!-- -->.<!-- --></h2></div></div></div><div></div><div></div><div class="ToastWrapper-sc-1a33ph1-0 kOVcuR"><div class="Toastify"></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404},"currentTheme":{"accent":{"alert":"#F6540B","blue":"#4877FF","blueLight":"rgba(72, 119, 255, 0.5)","contentDefaultTransparent":"rgba(174, 174, 174, 0.5)","cyan":"#65E3FF","cyanTransparent":"rgba(101, 227, 255, 0.12)","dbt":"#fc6949","dbtLight":"rgba(252, 105, 73, 0.5)","info":"#00ABFF","infoTransparent":"rgba(0, 171, 255, 0.5)","negative":"#FF1E59","negativeTransparent":"rgba(255, 30, 89, 0.3)","pink":"#FF4FF8","pinkLight":"#FFB9FC","positive":"#00A81A","primaryTransparent":"rgba(155, 108, 167, 0.5)","purple":"#7D55EC","purpleLight":"rgba(125, 85, 236, 0.5)","teal":"#00B4CC","tealLight":"rgba(0, 180, 204, 0.5)","warning":"#DD9900","warningTransparent":"rgba(221, 153, 0, 0.5)","yellow":"#FFCC19","yellowLight":"rgba(255, 204, 25, 0.5)"},"background":{"chartBlock":"#2E3036","codeArea":"#1E1F24","codeTextarea":"#000000","content":"#1B1C20","danger":"#FFD0DB","dark":"#B1B8C3","header":"#1B1B1B","menu":"#0F4CFF","muted":"#F9FAFC","navigation":"#EDEDED","output":"#2E3036","page":"#1E1F24","panel":"#232429","popup":"#27292E","row":"#2C2C2C","row2":"#51535C","scrollbarThumb":"rgba(100, 100, 100, 0.5)","scrollbarThumbHover":"rgba(255, 255, 255, 0.3)","scrollbarTrack":"#2E3036","success":"#8ADE00","table":"#292A2F"},"borders":{"contrast":"#FFFFFF","danger":"#FF144D","dark":"#000000","info":"#FFCC19","light":"#2F3034","medium":"#1C1C1C","success":"#2FCB52"},"brand":{"earth100":"#C6EEDB","earth200":"#9DDFBF","earth300":"#6BBF96","earth400":"#37A46F","earth400Transparent":"rgba(55, 164, 111, 0.4)","earth500":"#00954C","energy100":"#FFF4BA","energy200":"#FFED92","energy300":"#FFE662","energy400":"#FFDA19","energy400Transparent":"rgba(255, 218, 25, 0.04)","energy500":"#F6C000","fire100":"#FFD7E0","fire200":"#FFA3B9","fire300":"#FF547D","fire400":"#FF144D","fire400Transparent":"rgba(255, 20, 77, 0.4)","fire500":"#EB0032","stone100":"#F3E6D7","stone200":"#E3D4C2","stone400":"#BFA78B","stone500":"#AF8859","water100":"#BDCEFF","water200":"#81A1FF","water300":"#517DFF","water400":"#2A60FE","water400Transparent":"rgba(42, 96, 254, 0.4)","water500":"#0F4CFF","wind100":"#EEEAFF","wind200":"#CCC1F4","wind300":"#A698DD","wind400":"#6B50D7","wind400SuperTransparent":"rgba(107, 80, 215, 0.12)","wind400Transparent":"rgba(107, 80, 215, 0.4)","wind500":"#4E32BC"},"chart":{"backgroundPrimary":"#7D55EC","backgroundSecondary":"#FF144D","backgroundTertiary":"#86E2FF","button1":"#4877FF","button2":"#FFCC19","button3":"#8ADE00","button4":"#FF4FF8","button5":"#B98D95","lines":"#9B6CA7","primary":"#6B50D7","secondary":"#FF144D","tertiary":"#2A60FE"},"content":{"active":"#FFFFFF","default":"#AEAEAE","disabled":"rgba(255, 255, 255, 0.3)","inverted":"#2C2C2C","muted":"#787A85"},"elevation":{"visualizationAccent":"#996CFF","visualizationAccentAlt":"#C1ACF7"},"feature":{"active":"rgba(250, 248, 254, 0.14)","disabled":"rgba(201, 206, 218, 0.12)"},"icons":{"neutral":"#787878"},"interactive":{"activeBorder":"#060606","checked":"#060606","dangerBorder":"#FF144D","defaultBackground":"#36383F","defaultBorder":"#1C1C1C","disabledBorder":"#B1B8C3","focusBackground":"#B1B8C3","focusBorder":"#86E2FF","hoverBackground":"#4E4E4E","hoverBorder":"#B9BFCA","hoverOverlay":"rgba(255, 255, 255, 0.1)","linkPrimary":"#1752FF","linkPrimaryHover":"#4877FF","linkSecondary":"#6B50D7","linkSecondaryDisabled":"#C4B9EF","rowHoverBackground":"rgba(0, 0, 0, 0.1)"},"loader":{"color":"#EB0032","colorInverted":"#8ADE00"},"logo":{"color":"#FFFFFF"},"monotone":{"black":"#060606","blackTransparent":"rgba(0, 0, 0, 0.6)","gray":"#B1B8C3","grey100":"#F2F2F2","grey200":"#D5D7DC","grey300":"#B4B8C0","grey400":"#70747C","grey500":"#51535C","purple":"#6B50D7","white":"#FFFFFF"},"neutral":{"n100":"#E7E8EA","n200":"#D8DADE","n300":"#CBCCD0","n400":"#BCBEC4","n500":"#AEB0B6"},"progress":{"negative":"#FF144D","positive":"#6B50D7"},"shadow":{"base":"12px 40px 120px rgba(106, 117, 139, 0.4)","menu":"4px 10px 20px rgba(6, 6, 6, 0.12)","popup":"10px 20px 40px rgba(0, 0, 0, 0.2)","small":"0px, 4px, rgba(0, 0, 0, 0.25)","window":"0px 10px 60px rgba(0, 0, 0, 0.7)"},"status":{"negative":"#FF144D","positive":"#24B400"},"text":{"fileBrowser":"#787A85"}}},"page":"/_error","query":{},"buildId":"BJSgpMeWTfdkZw_YRDpOz","nextExport":true,"isFallback":false,"gip":true,"appGip":true,"scriptLoader":[]}</script></body></html>