tasks ready
This commit is contained in:
@@ -22,6 +22,9 @@ Auto-generated from all feature plans. Last updated: 2025-12-19
|
||||
- SQLite (for job history/results, connection configs), Filesystem (for temporary file uploads) (010-refactor-cli-to-web)
|
||||
- Python 3.9+ + FastAPI, Pydantic, requests, pyyaml (migrated from superset_tool) (012-remove-superset-tool)
|
||||
- SQLite (tasks.db, migrations.db), Filesystem (012-remove-superset-tool)
|
||||
- Filesystem (local git repo), SQLite (for GitServerConfig, Environment) (011-git-integration-dashboard)
|
||||
- Python 3.9+ (Backend), Node.js 18+ (Frontend) + FastAPI, SvelteKit, GitPython (or CLI git), Pydantic, SQLAlchemy, Superset API (011-git-integration-dashboard)
|
||||
- SQLite (for config/history), Filesystem (local Git repositories) (011-git-integration-dashboard)
|
||||
|
||||
- Python 3.9+ (Backend), Node.js 18+ (Frontend Build) (001-plugin-arch-svelte-ui)
|
||||
|
||||
@@ -42,9 +45,9 @@ cd src; pytest; ruff check .
|
||||
Python 3.9+ (Backend), Node.js 18+ (Frontend Build): Follow standard conventions
|
||||
|
||||
## Recent Changes
|
||||
- 011-git-integration-dashboard: Added Python 3.9+ (Backend), Node.js 18+ (Frontend) + FastAPI, SvelteKit, GitPython (or CLI git), Pydantic, SQLAlchemy, Superset API
|
||||
- 011-git-integration-dashboard: Added Python 3.9+, Node.js 18+
|
||||
- 012-remove-superset-tool: Added Python 3.9+ + FastAPI, Pydantic, requests, pyyaml (migrated from superset_tool)
|
||||
- 010-refactor-cli-to-web: Added Python 3.9+ (Backend), Node.js 18+ (Frontend) + FastAPI, SvelteKit, Tailwind CSS, Pydantic, SQLAlchemy, `superset_tool` (internal lib)
|
||||
- 009-backup-scheduler: Added Python 3.9+, Node.js 18+ + FastAPI, APScheduler, SQLAlchemy, SvelteKit, Tailwind CSS
|
||||
|
||||
|
||||
<!-- MANUAL ADDITIONS START -->
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
slice_name: "FI-0083 \u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043A\u0430\
|
||||
\ \u043F\u043E \u0414\u0417/\u041F\u0414\u0417"
|
||||
description: null
|
||||
certified_by: null
|
||||
certification_details: null
|
||||
viz_type: pivot_table_v2
|
||||
params:
|
||||
datasource: 859__table
|
||||
viz_type: pivot_table_v2
|
||||
slice_id: 4019
|
||||
groupbyColumns:
|
||||
- dt
|
||||
groupbyRows:
|
||||
- counterparty_search_name
|
||||
- attribute
|
||||
time_grain_sqla: P1M
|
||||
temporal_columns_lookup:
|
||||
dt: true
|
||||
metrics:
|
||||
- m_debt_amount
|
||||
- m_overdue_amount
|
||||
metricsLayout: COLUMNS
|
||||
adhoc_filters:
|
||||
- clause: WHERE
|
||||
comparator: No filter
|
||||
expressionType: SIMPLE
|
||||
operator: TEMPORAL_RANGE
|
||||
subject: dt
|
||||
row_limit: '90000'
|
||||
order_desc: false
|
||||
aggregateFunction: Sum
|
||||
combineMetric: true
|
||||
valueFormat: SMART_NUMBER
|
||||
date_format: smart_date
|
||||
rowOrder: key_a_to_z
|
||||
colOrder: key_a_to_z
|
||||
value_font_size: 12
|
||||
header_font_size: 12
|
||||
label_align: left
|
||||
column_config:
|
||||
m_debt_amount:
|
||||
d3NumberFormat: ',d'
|
||||
m_overdue_amount:
|
||||
d3NumberFormat: ',d'
|
||||
conditional_formatting: []
|
||||
extra_form_data: {}
|
||||
dashboards:
|
||||
- 184
|
||||
query_context: '{"datasource":{"id":859,"type":"table"},"force":false,"queries":[{"filters":[{"col":"dt","op":"TEMPORAL_RANGE","val":"No
|
||||
filter"}],"extras":{"having":"","where":""},"applied_time_extras":{},"columns":[{"timeGrain":"P1M","columnType":"BASE_AXIS","sqlExpression":"dt","label":"dt","expressionType":"SQL"},"counterparty_search_name","attribute"],"metrics":["m_debt_amount","m_overdue_amount"],"orderby":[["m_debt_amount",true]],"annotation_layers":[],"row_limit":90000,"series_limit":0,"order_desc":false,"url_params":{},"custom_params":{},"custom_form_data":{}}],"form_data":{"datasource":"859__table","viz_type":"pivot_table_v2","slice_id":4019,"groupbyColumns":["dt"],"groupbyRows":["counterparty_search_name","attribute"],"time_grain_sqla":"P1M","temporal_columns_lookup":{"dt":true},"metrics":["m_debt_amount","m_overdue_amount"],"metricsLayout":"COLUMNS","adhoc_filters":[{"clause":"WHERE","comparator":"No
|
||||
filter","expressionType":"SIMPLE","operator":"TEMPORAL_RANGE","subject":"dt"}],"row_limit":"90000","order_desc":false,"aggregateFunction":"Sum","combineMetric":true,"valueFormat":"SMART_NUMBER","date_format":"smart_date","rowOrder":"key_a_to_z","colOrder":"key_a_to_z","value_font_size":12,"header_font_size":12,"label_align":"left","column_config":{"m_debt_amount":{"d3NumberFormat":",d"},"m_overdue_amount":{"d3NumberFormat":",d"}},"conditional_formatting":[],"extra_form_data":{},"dashboards":[184],"force":false,"result_format":"json","result_type":"full"},"result_format":"json","result_type":"full"}'
|
||||
cache_timeout: null
|
||||
uuid: 9c293065-73e2-4d9b-a175-d188ff8ef575
|
||||
version: 1.0.0
|
||||
dataset_uuid: 9e645dc0-da25-4f61-9465-6e649b0bc4b1
|
||||
@@ -0,0 +1,13 @@
|
||||
database_name: Prod Clickhouse
|
||||
sqlalchemy_uri: clickhousedb+connect://viz_superset_click_prod:XXXXXXXXXX@rgm-s-khclk.hq.root.ad:443/dm
|
||||
cache_timeout: null
|
||||
expose_in_sqllab: true
|
||||
allow_run_async: false
|
||||
allow_ctas: false
|
||||
allow_cvas: false
|
||||
allow_dml: true
|
||||
allow_file_upload: false
|
||||
extra:
|
||||
allows_virtual_table_explore: true
|
||||
uuid: 97aced68-326a-4094-b381-27980560efa9
|
||||
version: 1.0.0
|
||||
@@ -0,0 +1,119 @@
|
||||
table_name: "FI-0080-06 \u041A\u0430\u043B\u0435\u043D\u0434\u0430\u0440\u044C (\u041E\
|
||||
\u0431\u0449\u0438\u0439 \u0441\u043F\u0440\u0430\u0432\u043E\u0447\u043D\u0438\u043A\
|
||||
)"
|
||||
main_dttm_col: null
|
||||
description: null
|
||||
default_endpoint: null
|
||||
offset: 0
|
||||
cache_timeout: null
|
||||
schema: dm_view
|
||||
sql: "-- [HEADER]\r\n-- [\u041D\u0410\u0417\u041D\u0410\u0427\u0415\u041D\u0418\u0415\
|
||||
]: \u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u0434\u0438\u0430\u043F\
|
||||
\u0430\u0437\u043E\u043D\u0430 \u0434\u0430\u0442 \u0434\u043B\u044F \u043E\u0442\
|
||||
\u0447\u0435\u0442\u0430 \u043E \u0437\u0430\u0434\u043E\u043B\u0436\u0435\u043D\
|
||||
\u043D\u043E\u0441\u0442\u044F\u0445 \u043F\u043E \u043E\u0431\u043E\u0440\u043E\
|
||||
\u0442\u043D\u044B\u043C \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043C\r\
|
||||
\n-- [\u041A\u041B\u042E\u0427\u0415\u0412\u042B\u0415 \u041A\u041E\u041B\u041E\u041D\
|
||||
\u041A\u0418]:\r\n-- - from_dt_txt: \u041D\u0430\u0447\u0430\u043B\u044C\u043D\
|
||||
\u0430\u044F \u0434\u0430\u0442\u0430 \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\
|
||||
\u0435 DD.MM.YYYY\r\n-- - to_dt_txt: \u041A\u043E\u043D\u0435\u0447\u043D\u0430\
|
||||
\u044F \u0434\u0430\u0442\u0430 \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435\
|
||||
\ DD.MM.YYYY\r\n-- [JINJA \u041F\u0410\u0420\u0410\u041C\u0415\u0422\u0420\u042B\
|
||||
]:\r\n-- - {{ filter_values(\"yes_no_check\") }}: \u0424\u0438\u043B\u044C\u0442\
|
||||
\u0440 \"\u0414\u0430/\u041D\u0435\u0442\" \u0434\u043B\u044F \u043E\u0433\u0440\
|
||||
\u0430\u043D\u0438\u0447\u0435\u043D\u0438\u044F \u0432\u044B\u0431\u043E\u0440\u043A\
|
||||
\u0438 \u043F\u043E \u0434\u0430\u0442\u0435\r\n-- [\u041B\u041E\u0413\u0418\u041A\
|
||||
\u0410]: \u041E\u043F\u0440\u0435\u0434\u0435\u043B\u044F\u0435\u0442 \u043F\u043E\
|
||||
\u0440\u043E\u0433\u043E\u0432\u0443\u044E \u0434\u0430\u0442\u0443 \u0432 \u0437\
|
||||
\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0438 \u043E\u0442 \u0442\
|
||||
\u0435\u043A\u0443\u0449\u0435\u0433\u043E \u0434\u043D\u044F \u043C\u0435\u0441\
|
||||
\u044F\u0446\u0430 \u0438 \u0444\u0438\u043B\u044C\u0442\u0440\u0443\u0435\u0442\
|
||||
\ \u0434\u0430\u043D\u043D\u044B\u0435\r\n\r\nWITH date_threshold AS (\r\n SELECT\
|
||||
\ \r\n -- \u041E\u043F\u0440\u0435\u0434\u0435\u043B\u044F\u0435\u043C \u043F\
|
||||
\u043E\u0440\u043E\u0433\u043E\u0432\u0443\u044E \u0434\u0430\u0442\u0443 \u0432\
|
||||
\ \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0438 \u043E\u0442\
|
||||
\ \u0442\u0435\u043A\u0443\u0449\u0435\u0433\u043E \u0434\u043D\u044F \r\n \
|
||||
\ CASE \r\n WHEN toDayOfMonth(now()) <= 10 THEN \r\n \
|
||||
\ toStartOfMonth(dateSub(MONTH, 1, now())) \r\n ELSE \r\n \
|
||||
\ toStartOfMonth(now()) \r\n END AS cutoff_date \r\n),\r\nfiltered_dates\
|
||||
\ AS (\r\n SELECT \r\n dt,\r\n formatDateTime(dt, '%d.%m.%Y') AS\
|
||||
\ from_dt_txt,\r\n formatDateTime(dt, '%d.%m.%Y') AS to_dt_txt\r\n \
|
||||
\ --dt as from_dt_txt,\r\n -- dt as to_dt_txt\r\n FROM dm_view.account_debt_for_working_capital_final\r\
|
||||
\n WHERE 1=1\r\n -- \u0411\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u0430\
|
||||
\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u0444\u0438\u043B\u044C\
|
||||
\u0442\u0440\u0430\r\n {% if filter_values(\"yes_no_check\") | length !=\
|
||||
\ 0 %}\r\n {% if filter_values(\"yes_no_check\")[0] == \"\u0414\u0430\
|
||||
\" %}\r\n AND dt < (SELECT cutoff_date FROM date_threshold)\r\n \
|
||||
\ {% endif %}\r\n {% endif %}\r\n)\r\nSELECT \r\ndt,\r\n from_dt_txt,\r\
|
||||
\n to_dt_txt,\r\n formatDateTime(toLastDayOfMonth(dt), '%d.%m.%Y') as last_day_of_month_dt_txt\r\
|
||||
\nFROM \r\n filtered_dates\r\nGROUP BY \r\n dt, from_dt_txt, to_dt_txt\r\n\
|
||||
ORDER BY \r\n dt DESC"
|
||||
params: null
|
||||
template_params: null
|
||||
filter_select_enabled: true
|
||||
fetch_values_predicate: null
|
||||
extra: null
|
||||
normalize_columns: false
|
||||
uuid: fca62707-6947-4440-a16b-70cb6a5cea5b
|
||||
metrics:
|
||||
- metric_name: max_date
|
||||
verbose_name: max_date
|
||||
metric_type: count
|
||||
expression: max(dt)
|
||||
description: null
|
||||
d3format: null
|
||||
currency: null
|
||||
extra:
|
||||
warning_markdown: ''
|
||||
warning_text: null
|
||||
columns:
|
||||
- column_name: from_dt_txt
|
||||
verbose_name: null
|
||||
is_dttm: true
|
||||
is_active: true
|
||||
type: String
|
||||
advanced_data_type: null
|
||||
groupby: true
|
||||
filterable: true
|
||||
expression: null
|
||||
description: null
|
||||
python_date_format: '%Y'
|
||||
extra: {}
|
||||
- column_name: dt
|
||||
verbose_name: null
|
||||
is_dttm: true
|
||||
is_active: true
|
||||
type: Date
|
||||
advanced_data_type: null
|
||||
groupby: true
|
||||
filterable: true
|
||||
expression: null
|
||||
description: null
|
||||
python_date_format: null
|
||||
extra: {}
|
||||
- column_name: last_day_of_month_dt_txt
|
||||
verbose_name: null
|
||||
is_dttm: false
|
||||
is_active: true
|
||||
type: String
|
||||
advanced_data_type: null
|
||||
groupby: true
|
||||
filterable: true
|
||||
expression: null
|
||||
description: null
|
||||
python_date_format: null
|
||||
extra: {}
|
||||
- column_name: to_dt_txt
|
||||
verbose_name: null
|
||||
is_dttm: true
|
||||
is_active: true
|
||||
type: String
|
||||
advanced_data_type: null
|
||||
groupby: true
|
||||
filterable: true
|
||||
expression: null
|
||||
description: null
|
||||
python_date_format: null
|
||||
extra: {}
|
||||
version: 1.0.0
|
||||
database_uuid: 97aced68-326a-4094-b381-27980560efa9
|
||||
@@ -0,0 +1,190 @@
|
||||
table_name: "FI-0090 \u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043A\u0430\
|
||||
\ \u043F\u043E \u0414\u0417/\u041F\u0414\u0417"
|
||||
main_dttm_col: dt
|
||||
description: null
|
||||
default_endpoint: null
|
||||
offset: 0
|
||||
cache_timeout: null
|
||||
schema: dm_view
|
||||
sql: "-- [JINJA_BLOCK] \u0426\u0435\u043D\u0442\u0440\u0430\u043B\u0438\u0437\u043E\
|
||||
\u0432\u0430\u043D\u043D\u043E\u0435 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\
|
||||
\u043D\u0438\u0435 \u0432\u0441\u0435\u0445 Jinja \u043F\u0435\u0440\u0435\u043C\
|
||||
\u0435\u043D\u043D\u044B\u0445\r\n{% set raw_to = filter_values('last_day_of_month_dt_txt')[0]\
|
||||
\ \r\n if filter_values('last_day_of_month_dt_txt') else '01.05.2025'\
|
||||
\ %}\r\n\r\n{# \u0440\u0430\u0437\u0431\u0438\u0432\u0430\u0435\u043C \xABDD.MM.YYYY\xBB\
|
||||
\ \u043D\u0430 \u0447\u0430\u0441\u0442\u0438 #}\r\n{% set to_parts = raw_to.split('.')\
|
||||
\ %}\r\n\r\n{# \u0441\u043E\u0431\u0438\u0440\u0430\u0435\u043C ISO\u2011\u0441\u0442\
|
||||
\u0440\u043E\u043A\u0443 \xABYYYY-MM-DD\xBB #}\r\n{% set to_dt = to_parts[2] \
|
||||
\ ~ '-' ~ to_parts[1] ~ '-' ~ to_parts[0] %}\r\n\r\nwith \r\ncp_relations_type\
|
||||
\ AS (\r\n select * from ( SELECT \r\n ctd.counterparty_code AS counterparty_code,\r\
|
||||
\n min(dt_from) as dt_from,\r\n max(dt_to) as dt_to,\r\n crt.relation_type_code\
|
||||
\ || ' ' || crt.relation_type_name AS relation_type_code_name\r\n FROM\r\n \
|
||||
\ dm_view.counterparty_td ctd\r\n JOIN dm_view.counterparty_relation_type_texts\
|
||||
\ crt \r\n ON ctd.relation_type_code = crt.relation_type_code\r\n GROUP\
|
||||
\ BY\r\n ctd.counterparty_code, ctd.counterparty_full_name,\r\n crt.relation_type_code,crt.relation_type_name)\r\
|
||||
\n WHERE \r\n dt_from <= toDate('{{to_dt }}') AND \r\n \
|
||||
\ dt_to >= toDate('{{to_dt }}')\r\n ),\r\nt_debt as \r\n(SELECT dt, \r\n\
|
||||
counterparty_search_name,\r\ncp_relations_type.relation_type_code_name as relation_type_code_name,\r\
|
||||
\nunit_balance_code || ' ' || unit_balance_name as unit_balance_code_name,\r\n'1.\
|
||||
\ \u0421\u0443\u043C\u043C\u0430' as attribute,\r\nsum(debt_balance_subposition_no_revaluation_usd_amount)\
|
||||
\ as debt_amount,\r\nsumIf(debt_balance_subposition_no_revaluation_usd_amount,dt_overdue\
|
||||
\ < dt) as overdue_amount\r\nfrom dm_view.account_debt_for_working_capital t_debt\r\
|
||||
\njoin cp_relations_type ON\r\ncp_relations_type.counterparty_code = t_debt.counterparty_code\r\
|
||||
\nwhere dt = toLastDayOfMonth(dt)\r\nand match(general_ledger_account_code,'((62)|(60)|(76))')\r\
|
||||
\nand debit_or_credit = 'S'\r\nand account_type = 'D'\r\nand dt between addMonths(toDate('{{to_dt\
|
||||
\ }}'),-12) and toDate('{{to_dt }}')\r\ngroup by dt, counterparty_search_name,unit_balance_code_name,relation_type_code_name\r\
|
||||
\n),\r\n\r\nt_transaction_count_base as \r\n(\r\nselect *,\r\ncp_relations_type.relation_type_code_name\
|
||||
\ as relation_type_code_name,\r\nunit_balance_code || ' ' || unit_balance_name as\
|
||||
\ unit_balance_code_name,\r\n case when dt_overdue<dt_clearing then\r\n \
|
||||
\ dateDiff(day, dt_overdue, dt_clearing) \r\n else 0\r\n end\
|
||||
\ as overdue_days\r\nfrom dm_view.accounting_documents_leading_to_debt t_docs\r\n\
|
||||
join cp_relations_type ON\r\ncp_relations_type.counterparty_code = t_docs.counterparty_code\r\
|
||||
\nwhere 1=1\r\n\r\nand match(general_ledger_account_code,'((62)|(60)|(76))')\r\n\
|
||||
and debit_or_credit = 'S'\r\nand account_type = 'D'\r\n)\r\n\r\nselect * from t_debt\r\
|
||||
\n\r\nunion all \r\n\r\nselect toLastDayOfMonth(dt_debt) as dt, \r\ncounterparty_search_name,\r\
|
||||
\nrelation_type_code_name,\r\nunit_balance_code_name,\r\n'2. \u043A\u043E\u043B\u0438\
|
||||
\u0447\u0435\u0441\u0442\u0432\u043E \u0442\u0440\u0430\u043D\u0437\u0430\u043A\u0446\
|
||||
\u0438\u0439 \u0432 \u043C\u0435\u0441\u044F\u0446' as attribute,\r\ncount(1) as\
|
||||
\ debt_amount,\r\nnull as overdue_amount\r\nfrom t_transaction_count_base\r\nwhere\
|
||||
\ dt_debt between addMonths(toDate('{{to_dt }}'),-12) and toDate('{{to_dt }}')\r\
|
||||
\ngroup by toLastDayOfMonth(dt_debt), \r\ncounterparty_search_name,\r\nrelation_type_code_name,\r\
|
||||
\nunit_balance_code_name,attribute\r\n\r\nunion all \r\n\r\nselect toLastDayOfMonth(dt_clearing)\
|
||||
\ as dt, \r\ncounterparty_search_name,\r\nrelation_type_code_name,\r\nunit_balance_code_name,\r\
|
||||
\n'2. \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0442\u0440\u0430\
|
||||
\u043D\u0437\u0430\u043A\u0446\u0438\u0439 \u0432 \u043C\u0435\u0441\u044F\u0446\
|
||||
' as attribute,\r\nnull as debt_amount,\r\ncount(1) as overdue_amount\r\nfrom t_transaction_count_base\r\
|
||||
\nwhere dt_clearing between addMonths(toDate('{{to_dt }}'),-12) and toDate('{{to_dt\
|
||||
\ }}')\r\nand overdue_days > 0\r\ngroup by toLastDayOfMonth(dt_clearing), \r\ncounterparty_search_name,\r\
|
||||
\nrelation_type_code_name,\r\nunit_balance_code_name,attribute\r\n\r\nunion all\
|
||||
\ \r\n\r\nselect toLastDayOfMonth(dt_clearing) as dt, \r\ncounterparty_search_name,\r\
|
||||
\nrelation_type_code_name,\r\nunit_balance_code_name,\r\nmultiIf(\r\noverdue_days\
|
||||
\ < 30,'3. \u0434\u043E 30',\r\noverdue_days between 30 and 60, '4. \u043E\u0442\
|
||||
\ 30 \u0434\u043E 60',\r\noverdue_days between 61 and 90, '5. \u043E\u0442 61 \u0434\
|
||||
\u043E 90',\r\noverdue_days>90,'6. \u0431\u043E\u043B\u0435\u0435 90 \u0434\u043D\
|
||||
',\r\nnull\r\n)\r\n as attribute,\r\nnull as debt_amount,\r\ncount(1) as overdue_amount\r\
|
||||
\nfrom t_transaction_count_base\r\nwhere dt_clearing between addMonths(toDate('{{to_dt\
|
||||
\ }}'),-12) and toDate('{{to_dt }}')\r\nand overdue_days > 0\r\ngroup by toLastDayOfMonth(dt_clearing),\
|
||||
\ \r\ncounterparty_search_name,\r\nrelation_type_code_name,\r\nattribute,unit_balance_code_name,attribute\r\
|
||||
\n"
|
||||
params: null
|
||||
template_params: null
|
||||
filter_select_enabled: true
|
||||
fetch_values_predicate: null
|
||||
extra: null
|
||||
normalize_columns: false
|
||||
uuid: 9e645dc0-da25-4f61-9465-6e649b0bc4b1
|
||||
metrics:
|
||||
- metric_name: m_debt_amount
|
||||
verbose_name: "\u0414\u0417, $"
|
||||
metric_type: count
|
||||
expression: sum(debt_amount)
|
||||
description: null
|
||||
d3format: null
|
||||
currency: null
|
||||
extra:
|
||||
warning_markdown: ''
|
||||
warning_text: null
|
||||
- metric_name: m_overdue_amount
|
||||
verbose_name: "\u041F\u0414\u0417, $"
|
||||
metric_type: null
|
||||
expression: sum(overdue_amount)
|
||||
description: null
|
||||
d3format: null
|
||||
currency: null
|
||||
extra:
|
||||
warning_markdown: ''
|
||||
warning_text: null
|
||||
columns:
|
||||
- column_name: debt_amount
|
||||
verbose_name: null
|
||||
is_dttm: false
|
||||
is_active: true
|
||||
type: Nullable(Decimal(38, 2))
|
||||
advanced_data_type: null
|
||||
groupby: true
|
||||
filterable: true
|
||||
expression: null
|
||||
description: null
|
||||
python_date_format: null
|
||||
extra:
|
||||
warning_markdown: null
|
||||
- column_name: overdue_amount
|
||||
verbose_name: null
|
||||
is_dttm: false
|
||||
is_active: true
|
||||
type: Nullable(Decimal(38, 2))
|
||||
advanced_data_type: null
|
||||
groupby: true
|
||||
filterable: true
|
||||
expression: null
|
||||
description: null
|
||||
python_date_format: null
|
||||
extra:
|
||||
warning_markdown: null
|
||||
- column_name: dt
|
||||
verbose_name: null
|
||||
is_dttm: true
|
||||
is_active: true
|
||||
type: Nullable(Date)
|
||||
advanced_data_type: null
|
||||
groupby: true
|
||||
filterable: true
|
||||
expression: null
|
||||
description: null
|
||||
python_date_format: null
|
||||
extra:
|
||||
warning_markdown: null
|
||||
- column_name: unit_balance_code_name
|
||||
verbose_name: null
|
||||
is_dttm: false
|
||||
is_active: true
|
||||
type: Nullable(String)
|
||||
advanced_data_type: null
|
||||
groupby: true
|
||||
filterable: true
|
||||
expression: null
|
||||
description: null
|
||||
python_date_format: null
|
||||
extra:
|
||||
warning_markdown: null
|
||||
- column_name: relation_type_code_name
|
||||
verbose_name: null
|
||||
is_dttm: false
|
||||
is_active: true
|
||||
type: Nullable(String)
|
||||
advanced_data_type: null
|
||||
groupby: true
|
||||
filterable: true
|
||||
expression: null
|
||||
description: null
|
||||
python_date_format: null
|
||||
extra:
|
||||
warning_markdown: null
|
||||
- column_name: counterparty_search_name
|
||||
verbose_name: null
|
||||
is_dttm: false
|
||||
is_active: true
|
||||
type: Nullable(String)
|
||||
advanced_data_type: null
|
||||
groupby: true
|
||||
filterable: true
|
||||
expression: null
|
||||
description: null
|
||||
python_date_format: null
|
||||
extra:
|
||||
warning_markdown: null
|
||||
- column_name: attribute
|
||||
verbose_name: null
|
||||
is_dttm: false
|
||||
is_active: true
|
||||
type: Nullable(String)
|
||||
advanced_data_type: null
|
||||
groupby: true
|
||||
filterable: true
|
||||
expression: null
|
||||
description: null
|
||||
python_date_format: null
|
||||
extra:
|
||||
warning_markdown: null
|
||||
version: 1.0.0
|
||||
database_uuid: 97aced68-326a-4094-b381-27980560efa9
|
||||
@@ -0,0 +1,3 @@
|
||||
version: 1.0.0
|
||||
type: Dashboard
|
||||
timestamp: '2026-01-14T11:21:08.078620+00:00'
|
||||
58
specs/011-git-integration-dashboard/contracts/api.md
Normal file
58
specs/011-git-integration-dashboard/contracts/api.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# API Contracts: Git Integration Plugin
|
||||
|
||||
## Git Configuration
|
||||
|
||||
### `GET /api/git/config`
|
||||
List all Git server configurations.
|
||||
|
||||
### `POST /api/git/config`
|
||||
Create a new Git server configuration.
|
||||
- **Body**: `GitServerConfig` (Pydantic model)
|
||||
|
||||
### `POST /api/git/config/test`
|
||||
Test connection to a Git server.
|
||||
- **Body**: `GitServerConfig`
|
||||
- **Response**: `{"status": "success" | "error", "message": String}`
|
||||
|
||||
## Repository & Branch Management
|
||||
|
||||
### `GET /api/git/repositories/{dashboard_id}/branches`
|
||||
List all branches for a dashboard's repository.
|
||||
|
||||
### `POST /api/git/repositories/{dashboard_id}/branches`
|
||||
Create a new branch.
|
||||
- **Body**: `{"name": String, "from_branch": String}`
|
||||
|
||||
### `POST /api/git/repositories/{dashboard_id}/checkout`
|
||||
Switch to a specific branch.
|
||||
- **Body**: `{"name": String}`
|
||||
|
||||
## Git Operations
|
||||
|
||||
### `POST /api/git/repositories/{dashboard_id}/commit`
|
||||
Commit changes to the current branch.
|
||||
- **Body**: `{"message": String, "files": List[String]}`
|
||||
|
||||
### `POST /api/git/repositories/{dashboard_id}/push`
|
||||
Push local commits to remote.
|
||||
|
||||
### `POST /api/git/repositories/{dashboard_id}/pull`
|
||||
Pull changes from remote.
|
||||
|
||||
## Conflict Resolution
|
||||
|
||||
### `GET /api/git/repositories/{dashboard_id}/conflicts`
|
||||
List active conflicts for a repository.
|
||||
|
||||
### `POST /api/git/repositories/{dashboard_id}/resolve`
|
||||
Resolve a conflict for a specific file.
|
||||
- **Body**: `{"file_path": String, "resolution": "mine" | "theirs" | "manual", "content": Optional[String]}`
|
||||
|
||||
## Deployment
|
||||
|
||||
### `GET /api/git/environments`
|
||||
List deployment environments.
|
||||
|
||||
### `POST /api/git/repositories/{dashboard_id}/deploy`
|
||||
Deploy dashboard from current branch to target environment.
|
||||
- **Body**: `{"environment_id": UUID}`
|
||||
56
specs/011-git-integration-dashboard/data-model.md
Normal file
56
specs/011-git-integration-dashboard/data-model.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Data Model: Git Integration Plugin
|
||||
|
||||
## Entities
|
||||
|
||||
### GitServerConfig
|
||||
- **id**: UUID (Primary Key)
|
||||
- **name**: String (Display name)
|
||||
- **provider**: Enum (GITHUB, GITLAB, GITEA)
|
||||
- **url**: String (e.g., https://github.com)
|
||||
- **pat**: String (Encrypted/Sensitive)
|
||||
- **default_repository**: String (e.g., org/dashboards)
|
||||
- **status**: Enum (CONNECTED, FAILED, UNKNOWN)
|
||||
- **last_validated**: DateTime
|
||||
|
||||
### GitRepository
|
||||
- **id**: UUID (Primary Key)
|
||||
- **dashboard_id**: Integer (Link to Superset Dashboard ID)
|
||||
- **config_id**: UUID (FK to GitServerConfig)
|
||||
- **remote_url**: String
|
||||
- **local_path**: String (Relative to backend storage)
|
||||
- **current_branch**: String
|
||||
- **sync_status**: Enum (CLEAN, DIRTY, CONFLICT)
|
||||
|
||||
### Branch
|
||||
- **name**: String
|
||||
- **commit_hash**: String
|
||||
- **is_remote**: Boolean
|
||||
- **last_updated**: DateTime
|
||||
|
||||
### Commit
|
||||
- **hash**: String (Primary Key)
|
||||
- **author**: String
|
||||
- **email**: String
|
||||
- **timestamp**: DateTime
|
||||
- **message**: String
|
||||
- **files_changed**: List[String]
|
||||
|
||||
### Conflict
|
||||
- **repository_id**: UUID (FK to GitRepository)
|
||||
- **file_path**: String
|
||||
- **our_content**: String
|
||||
- **their_content**: String
|
||||
- **base_content**: String
|
||||
|
||||
### DeploymentEnvironment
|
||||
- **id**: UUID (Primary Key)
|
||||
- **name**: String (e.g., Production, Staging)
|
||||
- **superset_url**: String
|
||||
- **superset_token**: String (Sensitive)
|
||||
- **is_active**: Boolean
|
||||
|
||||
## Relationships
|
||||
- **GitServerConfig** (1) <-> (*) **GitRepository**
|
||||
- **GitRepository** (1) <-> (*) **Branch**
|
||||
- **Branch** (1) <-> (*) **Commit**
|
||||
- **GitRepository** (1) <-> (*) **DeploymentEnvironment** (Via deployment logs/config)
|
||||
102
specs/011-git-integration-dashboard/plan.md
Normal file
102
specs/011-git-integration-dashboard/plan.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# Implementation Plan: Git Integration Plugin for Dashboard Development
|
||||
|
||||
**Branch**: `011-git-integration-dashboard` | **Date**: 2026-01-22 | **Spec**: [spec.md](specs/011-git-integration-dashboard/spec.md)
|
||||
**Input**: Feature specification from `/specs/011-git-integration-dashboard/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Implement a Git integration plugin that allows dashboard developers to version control their Superset dashboards. The plugin will support GitLab, GitHub, and Gitea, enabling branch management, committing/pushing changes (as unpacked Superset exports), and deploying to target environments via the Superset API.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Python 3.9+ (Backend), Node.js 18+ (Frontend)
|
||||
**Primary Dependencies**: FastAPI, SvelteKit, GitPython (or CLI git), Pydantic, SQLAlchemy, Superset API
|
||||
**Storage**: SQLite (for config/history), Filesystem (local Git repositories)
|
||||
**Testing**: pytest (Backend), SvelteKit testing utilities (Frontend)
|
||||
**Target Platform**: Linux server
|
||||
**Project Type**: Web application (Frontend + Backend)
|
||||
**Performance Goals**: Branch switching < 5s, Search/Filter history < 2s
|
||||
**Constraints**: Offline mode support, Superset API dependency for deployment, PAT-based authentication
|
||||
**Scale/Scope**: 1 repository per dashboard, support for up to 1000 commits per repo
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
1. **Semantic Protocol Compliance**: All new modules must include headers, `[DEF]` anchors, and `@RELATION` tags as per `semantic_protocol.md`.
|
||||
2. **Causal Validity**: API contracts and data models must be defined in `specs/` before implementation.
|
||||
3. **Everything is a Plugin**: The Git integration must be implemented as a `PluginBase` subclass in `backend/src/plugins/`.
|
||||
4. **Design by Contract**: Use Pydantic models for request/response validation and internal state transitions.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/[###-feature]/
|
||||
├── plan.md # This file (/speckit.plan command output)
|
||||
├── research.md # Phase 0 output (/speckit.plan command)
|
||||
├── data-model.md # Phase 1 output (/speckit.plan command)
|
||||
├── quickstart.md # Phase 1 output (/speckit.plan command)
|
||||
├── contracts/ # Phase 1 output (/speckit.plan command)
|
||||
└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
<!--
|
||||
ACTION REQUIRED: Replace the placeholder tree below with the concrete layout
|
||||
for this feature. Delete unused options and expand the chosen structure with
|
||||
real paths (e.g., apps/admin, packages/something). The delivered plan must
|
||||
not include Option labels.
|
||||
-->
|
||||
|
||||
```text
|
||||
backend/
|
||||
├── src/
|
||||
│ ├── api/routes/git.py # Git integration endpoints
|
||||
│ ├── models/git.py # Git-specific Pydantic/SQLAlchemy models
|
||||
│ ├── plugins/git_plugin.py # PluginBase implementation
|
||||
│ └── services/git_service.py # Core Git logic (GitPython wrapper)
|
||||
└── tests/
|
||||
└── plugins/test_git.py
|
||||
|
||||
frontend/
|
||||
├── src/
|
||||
│ ├── components/git/ # Git UI components (BranchSelector, CommitModal, ConflictResolver)
|
||||
│ ├── routes/settings/git/ # Git configuration pages
|
||||
│ └── services/gitService.js # API client for Git operations
|
||||
└── tests/
|
||||
|
||||
**Structure Decision**: Web application structure as the project has both FastAPI backend and SvelteKit frontend.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
> **Fill ONLY if Constitution Check has violations that must be justified**
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
|-----------|------------|-------------------------------------|
|
||||
| [e.g., 4th project] | [current need] | [why 3 projects insufficient] |
|
||||
[e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] |
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 2: Backend Implementation (Plugin & Service)
|
||||
1. **Git Service**: Implement `GitService` using `GitPython`. Focus on:
|
||||
* Repo initialization and cloning.
|
||||
* Branch management (list, create, checkout).
|
||||
* Stage, commit, push, pull.
|
||||
2. **Git Plugin**: Implement `GitPlugin(PluginBase)`.
|
||||
* Integrate with `superset_tool` for exporting/importing dashboards.
|
||||
* Handle unpacking ZIP exports into the repo structure.
|
||||
3. **API Routes**: Implement `/api/git/*` endpoints.
|
||||
|
||||
### Phase 3: Frontend Implementation
|
||||
1. **Configuration UI**: Settings page for `GitServerConfig`.
|
||||
2. **Dashboard Integration**: Add Git controls to the Dashboard view.
|
||||
* Branch selector.
|
||||
* Commit/Push/Pull buttons.
|
||||
3. **Conflict Resolution UI**: Implementation of "Keep Mine/Theirs" file picker.
|
||||
|
||||
### Phase 4: Deployment Integration
|
||||
1. **Environment Management**: CRUD for `DeploymentEnvironment`.
|
||||
2. **Deployment Logic**: Trigger Superset Import API on target servers.
|
||||
40
specs/011-git-integration-dashboard/quickstart.md
Normal file
40
specs/011-git-integration-dashboard/quickstart.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Quickstart: Git Integration Plugin
|
||||
|
||||
## Setup
|
||||
|
||||
1. **Install Dependencies**:
|
||||
```bash
|
||||
cd backend && .venv/bin/pip install GitPython
|
||||
```
|
||||
|
||||
2. **Configure Git Server**:
|
||||
- Go to Settings -> Git Integration
|
||||
- Click "Add Server"
|
||||
- Select Provider (e.g., GitLab)
|
||||
- Enter Server URL and Personal Access Token (PAT)
|
||||
- Click "Test Connection" and "Save"
|
||||
|
||||
3. **Link Dashboard to Git**:
|
||||
- Navigate to the Dashboard view
|
||||
- Select a dashboard
|
||||
- Click "Enable Git Integration"
|
||||
- Select the Git server and provide repository path (e.g., `my-org/my-dashboard-repo`)
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### Versioning Changes
|
||||
1. Make changes to the dashboard in Superset.
|
||||
2. In the Git Integration panel, click "Commit".
|
||||
3. Enter a commit message and select files (metadata, charts, etc.).
|
||||
4. Click "Push" to sync with remote.
|
||||
|
||||
### Branching
|
||||
1. Click "New Branch".
|
||||
2. Enter branch name (e.g., `feature/new-charts`).
|
||||
3. The dashboard state is now tracked on this branch.
|
||||
|
||||
### Deployment
|
||||
1. Ensure changes are committed and pushed.
|
||||
2. Click "Deploy".
|
||||
3. Select target environment (e.g., "Production").
|
||||
4. Monitor deployment logs for success.
|
||||
34
specs/011-git-integration-dashboard/research.md
Normal file
34
specs/011-git-integration-dashboard/research.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Research: Git Integration Plugin
|
||||
|
||||
## Unknowns & Clarifications
|
||||
|
||||
1. **Git Library**: Should we use `GitPython` or call `git` CLI directly?
|
||||
- **Decision**: Use `GitPython`.
|
||||
- **Rationale**: It provides a high-level API for Git operations, making it easier to handle branches, commits, and remotes programmatically compared to parsing CLI output.
|
||||
- **Alternatives considered**: `pygit2` (faster but requires libgit2), `subprocess.run(["git", ...])` (simple but brittle).
|
||||
|
||||
2. **Git Provider API Integration**: How to handle different providers (GitHub, GitLab, Gitea) for connection testing?
|
||||
- **Decision**: Use a unified provider interface with provider-specific implementations.
|
||||
- **Rationale**: While Git operations are standard, testing connections and potentially creating repositories might require provider-specific REST APIs.
|
||||
- **Alternatives considered**: Generic Git clone test (slower, requires local disk space).
|
||||
|
||||
3. **Superset Export/Import**: How to handle the "unpacked" requirement?
|
||||
- **Decision**: Use the existing `superset_tool` logic or similar to export as ZIP and then unpack to the Git directory.
|
||||
- **Rationale**: Superset's native export is a ZIP. To fulfill FR-019, we must unpack this ZIP into the repository structure.
|
||||
|
||||
4. **Merge Conflict UI**: How to implement "Keep Mine/Theirs" in a web UI?
|
||||
- **Decision**: Implement a file-based conflict resolver in the Frontend.
|
||||
- **Rationale**: Since the data is YAML, we can show a list of conflicting files and let the user pick the version.
|
||||
- **Alternatives considered**: Full 3-way merge UI (too complex for MVP).
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Security**: Never store PATs in plain text in logs. Use environment variables or encrypted storage if possible (though SQLite is the current project standard).
|
||||
- **Concurrency**: Git operations on the same repository should be serialized to avoid index locks.
|
||||
- **Repository Isolation**: Each dashboard gets its own directory/repository to prevent cross-dashboard pollution.
|
||||
|
||||
## Findings Consolidations
|
||||
|
||||
- **Decision**: Use `GitPython` for core Git logic.
|
||||
- **Decision**: Use Provider-specific API clients for connection validation.
|
||||
- **Decision**: Unpack Superset exports into `dashboard/`, `charts/`, `datasets/`, `databases/` directories.
|
||||
@@ -22,16 +22,16 @@
|
||||
|
||||
### User Story 1 - Configure Git Server Connection (Priority: P1)
|
||||
|
||||
A dashboard developer needs to connect the system to their GitLab server to enable version control for dashboard development. They want to configure the Git server URL, authentication credentials, and repository details through a simple form interface.
|
||||
A dashboard developer needs to connect the system to their Git server (GitLab, GitHub, or Gitea) to enable version control for dashboard development. They want to configure the Git server provider, URL, authentication credentials, and repository details through a simple form interface.
|
||||
|
||||
**Why this priority**: This is the foundational requirement - without Git server configuration, no other Git functionality can work. It's the entry point for all Git operations.
|
||||
|
||||
**Independent Test**: Can be fully tested by configuring a GitLab server connection and verifying the connection test succeeds, delivering the ability to establish Git server connectivity.
|
||||
**Independent Test**: Can be fully tested by configuring a Git server connection (e.g., GitHub) and verifying the connection test succeeds, delivering the ability to establish Git server connectivity.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a user is on the Git integration settings page, **When** they enter valid GitLab server URL and API token, **Then** the system successfully validates the connection
|
||||
2. **Given** a user enters invalid GitLab credentials, **When** they test the connection, **Then** the system displays a clear error message indicating authentication failure
|
||||
1. **Given** a user is on the Git integration settings page, **When** they select a provider (GitLab/GitHub/Gitea) and enter valid server URL and PAT, **Then** the system successfully validates the connection
|
||||
2. **Given** a user enters invalid Git credentials, **When** they test the connection, **Then** the system displays a clear error message indicating authentication failure
|
||||
3. **Given** a user has configured a Git server, **When** they save the settings, **Then** the configuration is persisted and can be retrieved later
|
||||
|
||||
---
|
||||
@@ -113,25 +113,28 @@ A dashboard developer needs to view the commit history and changes made to dashb
|
||||
|
||||
## Clarifications
|
||||
|
||||
### Session 2026-01-18
|
||||
- Q: What is the primary data format for storing dashboards in the Git repository? → A: YAML files (more human-readable for diffs)
|
||||
- Q: How should the system handle merge conflicts during synchronization? → A: Built-in UI for basic resolution (Mine/Theirs/Manual)
|
||||
|
||||
### Session 2026-01-22
|
||||
- Q: Что именно должно входить в состав данных дашборда в Git-репозитории? → A: Распакованный архив экспорта Superset (YAML файлы: метаданные, чарты, датасеты, базы данных).
|
||||
- Q: Какова структура хранения дашбордов в Git-репозитории? → A: Один репозиторий соответствует одному дашборду.
|
||||
- Q: Как должен происходить деплой на целевое окружение после коммита? → A: Импорт через API (Superset Import API).
|
||||
- Q: Как система должна обрабатывать конфликты слияния (merge conflicts)? → A: UI для выбора версии (Keep Mine / Keep Theirs) на уровне файлов.
|
||||
- Q: Как должен происходить выбор дашборда для работы с Git? → A: Выбор конкретного дашборда из списка в UI.
|
||||
- Q: What triggers a deployment to a target environment? → A: Manual trigger by user from UI
|
||||
- Q: How should the system handle authentication with GitLab? → A: Personal Access Token (PAT)
|
||||
- Q: What should be the scope of a "Dashboard" in the Git repository? → A: Directory per dashboard (metadata + assets)
|
||||
- Q: How should the system handle authentication for the different providers (GitHub, GitLab, Gitea)? → A: Option [A] - Personal Access Token (PAT) for all providers
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: System MUST allow users to configure Git server connection settings including server URL, authentication via Personal Access Token (PAT), and repository details
|
||||
- **FR-002**: System MUST support GitLab as the primary Git server with extensible architecture for other Git servers
|
||||
- **FR-003**: System MUST validate Git server connection using the provided PAT before saving configuration
|
||||
- **FR-001**: System MUST allow users to configure Git server connection settings including provider type (GitHub, GitLab, Gitea), server URL, authentication via Personal Access Token (PAT), and repository details
|
||||
- **FR-002**: System MUST support GitLab, GitHub, and Gitea as supported Git server providers
|
||||
- **FR-003**: System MUST validate Git server connection using the provided PAT for the selected provider before saving configuration
|
||||
- **FR-004**: Users MUST be able to view all available branches from the configured Git repository
|
||||
- **FR-005**: Users MUST be able to create new branches both locally and remotely with proper naming validation
|
||||
- **FR-006**: Users MUST be able to switch between existing branches and have dashboard content update accordingly
|
||||
- **FR-007**: System MUST allow users to commit dashboard changes with commit messages and optional file selection
|
||||
- **FR-008**: System MUST support pushing local commits to remote repository branches
|
||||
- **FR-009**: System MUST support pulling changes from remote repository to local working directory
|
||||
- **FR-010**: System MUST handle merge conflicts with a built-in UI providing "Keep Mine", "Keep Theirs", and "Manual Edit" resolution options
|
||||
- **FR-010**: System MUST handle merge conflicts with a built-in UI providing "Keep Mine", "Keep Theirs", and "Manual Edit" (via a text area editor for YAML content) resolution options
|
||||
- **FR-011**: Users MUST be able to configure multiple target environments for dashboard deployment
|
||||
- **FR-012**: System MUST allow users to manually trigger deployment to a selected target environment from the UI
|
||||
- **FR-013**: System MUST validate deployment configuration before initiating deployment process
|
||||
@@ -140,7 +143,7 @@ A dashboard developer needs to view the commit history and changes made to dashb
|
||||
- **FR-016**: System MUST display detailed changes included in each commit for audit purposes
|
||||
- **FR-017**: System MUST handle PAT expiration gracefully with re-authentication prompts
|
||||
- **FR-018**: System MUST provide offline mode functionality when Git server is unavailable
|
||||
- **FR-019**: System MUST validate dashboard files before committing to ensure they are properly formatted in YAML within their respective dashboard directories
|
||||
- **FR-019**: System MUST store and validate dashboard data as a standard unpacked Superset export (YAML files for dashboard metadata, charts, datasets, and database connections) within their respective directories.
|
||||
- **FR-020**: Users MUST be able to search and filter commit history by date, author, or message content
|
||||
- **FR-021**: System MUST support rollback functionality to previous dashboard versions via Git operations
|
||||
|
||||
@@ -151,16 +154,12 @@ A dashboard developer needs to view the commit history and changes made to dashb
|
||||
- **Commit**: Represents a Git commit with properties like commit hash, author, timestamp, commit message, and list of changed files
|
||||
- **Environment**: Represents a deployment target environment with properties like name, URL, authentication details, and deployment status
|
||||
- **DashboardChange**: Represents changes made to dashboard directories (YAML metadata + assets) including file paths, change type (add/modify/delete), and content differences
|
||||
- **Branch**: Represents a Git branch with properties like name, commit hash, last updated timestamp, and remote tracking status
|
||||
- **Commit**: Represents a Git commit with properties like commit hash, author, timestamp, commit message, and list of changed files
|
||||
- **Environment**: Represents a deployment target environment with properties like name, URL, authentication details, and deployment status
|
||||
- **DashboardChange**: Represents changes made to dashboard files (YAML format) including file paths, change type (add/modify/delete), and content differences
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: Users can successfully configure a GitLab server connection and validate it within 2 minutes
|
||||
- **SC-001**: Users can successfully configure a supported Git server connection (GitLab, GitHub, or Gitea) and validate it within 2 minutes
|
||||
- **SC-002**: Dashboard branch switching operations complete within 5 seconds for repositories with up to 100 commits
|
||||
- **SC-003**: Commit and push operations succeed in 95% of attempts under normal network conditions
|
||||
- **SC-004**: Deployment to target environments completes successfully within 30 seconds for standard dashboard configurations
|
||||
|
||||
83
specs/011-git-integration-dashboard/tasks.md
Normal file
83
specs/011-git-integration-dashboard/tasks.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Tasks: Git Integration Plugin for Dashboard Development
|
||||
|
||||
Feature: 011-git-integration-dashboard
|
||||
|
||||
## Phase 1: Setup
|
||||
Goal: Initialize project structure and dependencies.
|
||||
|
||||
- [ ] T001 Add `GitPython` to `backend/requirements.txt`
|
||||
- [ ] T002 Create git plugin directory structure in `backend/src/plugins/git/` and `frontend/src/components/git/`
|
||||
|
||||
## Phase 2: Foundational
|
||||
Goal: Define data models and base classes for Git integration.
|
||||
|
||||
- [ ] T003 [P] Create SQLAlchemy models for `GitServerConfig` and `GitRepository` in `backend/src/models/git.py`
|
||||
- [ ] T004 [P] Create Pydantic schemas for Git entities in `backend/src/api/routes/git_schemas.py`
|
||||
- [ ] T005 Implement `GitService` base logic (init, clone) in `backend/src/services/git_service.py`
|
||||
- [ ] T006 Implement `GitPlugin(PluginBase)` skeleton in `backend/src/plugins/git_plugin.py`
|
||||
|
||||
## Phase 3: User Story 1 - Configure Git Server Connection (P1)
|
||||
Goal: Enable connection to Git servers (GitHub, GitLab, Gitea) via PAT.
|
||||
Independent Test: Configure a Git server connection and verify "Test Connection" succeeds.
|
||||
|
||||
- [ ] T007 [US1] Implement Git provider connection validation logic in `backend/src/services/git_service.py`
|
||||
- [ ] T008 [US1] Implement `/api/git/config` and `/api/git/config/test` endpoints in `backend/src/api/routes/git.py`
|
||||
- [ ] T009 [P] [US1] Create Git configuration service in `frontend/src/services/gitService.js`
|
||||
- [ ] T010 [US1] Implement Git server settings page in `frontend/src/routes/settings/git/+page.svelte`
|
||||
|
||||
## Phase 4: User Story 2 - Dashboard Branch Management (P1)
|
||||
Goal: Manage branches for dashboard repositories.
|
||||
Independent Test: Create a new branch, switch to it, and verify the local repository state updates.
|
||||
|
||||
- [ ] T011 [US2] Implement branch listing and creation logic in `backend/src/services/git_service.py`
|
||||
- [ ] T012 [US2] Implement branch checkout logic in `backend/src/services/git_service.py`
|
||||
- [ ] T013 [US2] Implement branch management endpoints in `backend/src/api/routes/git.py`
|
||||
- [ ] T014 [P] [US2] Create `BranchSelector` component in `frontend/src/components/git/BranchSelector.svelte`
|
||||
- [ ] T015 [US2] Integrate branch management into Dashboard view in `frontend/src/pages/Dashboard.svelte`
|
||||
|
||||
## Phase 5: User Story 3 - Dashboard Synchronization with Git (P1)
|
||||
Goal: Commit, push, and pull dashboard changes.
|
||||
Independent Test: Modify a dashboard, commit changes, push to remote, and verify changes on the Git server.
|
||||
|
||||
- [ ] T016 [US3] Implement Superset export unpacking logic (YAML files) in `backend/src/plugins/git_plugin.py`
|
||||
- [ ] T017 [US3] Implement commit, push, and pull logic in `backend/src/services/git_service.py`
|
||||
- [ ] T018 [US3] Implement sync endpoints (commit, push, pull) in `backend/src/api/routes/git.py`
|
||||
- [ ] T019 [P] [US3] Create `CommitModal` component in `frontend/src/components/git/CommitModal.svelte`
|
||||
- [ ] T020 [US3] Implement sync controls (Commit/Push/Pull) in `frontend/src/pages/Dashboard.svelte`
|
||||
- [ ] T021 [US3] Implement conflict detection and resolution logic in `backend/src/services/git_service.py`
|
||||
- [ ] T022 [US3] Implement conflict resolution endpoints in `backend/src/api/routes/git.py`
|
||||
- [ ] T023 [P] [US3] Create `ConflictResolver` component in `frontend/src/components/git/ConflictResolver.svelte`
|
||||
|
||||
## Phase 6: User Story 4 - Environment Deployment (P2)
|
||||
Goal: Deploy dashboard changes to target environments.
|
||||
Independent Test: Select a target environment and trigger deployment, verifying the dashboard is updated on the target Superset instance.
|
||||
|
||||
- [ ] T024 [P] [US4] Implement `DeploymentEnvironment` model in `backend/src/models/git.py`
|
||||
- [ ] T025 [US4] Implement deployment logic (Superset Import API) in `backend/src/plugins/git_plugin.py`
|
||||
- [ ] T026 [US4] Implement deployment endpoints in `backend/src/api/routes/git.py`
|
||||
- [ ] T027 [US4] Create environment management UI in `frontend/src/routes/settings/environments/+page.svelte`
|
||||
- [ ] T028 [US4] Implement deployment trigger in `frontend/src/pages/Dashboard.svelte`
|
||||
|
||||
## Phase 7: User Story 5 - Git History and Change Tracking (P3)
|
||||
Goal: View dashboard commit history and changes.
|
||||
Independent Test: Open the history view and verify the list of commits matches the Git repository history.
|
||||
|
||||
- [ ] T029 [US5] Implement commit history retrieval in `backend/src/services/git_service.py`
|
||||
- [ ] T030 [US5] Implement history endpoint in `backend/src/api/routes/git.py`
|
||||
- [ ] T031 [P] [US5] Create `CommitHistory` component in `frontend/src/components/git/CommitHistory.svelte`
|
||||
|
||||
## Phase 8: Polish & Cross-cutting Concerns
|
||||
- [ ] T032 Add error handling and loading states to all Git UI components
|
||||
- [ ] T033 Implement offline mode checks for Git operations
|
||||
- [ ] T034 Final integration testing of the complete Git workflow
|
||||
|
||||
## Dependencies
|
||||
- US1 is a prerequisite for all other stories.
|
||||
- US2 and US3 are closely related; US2 (branches) should precede US3 (sync).
|
||||
- US4 depends on US3 (changes must be committed to be deployed).
|
||||
- US5 is independent but requires commits to exist.
|
||||
|
||||
## Implementation Strategy
|
||||
1. **MVP**: Complete Phase 1-3 (Setup, Foundational, and US1) to allow Git server configuration.
|
||||
2. **Core Workflow**: Complete Phase 4-5 (Branches and Sync) to enable version control.
|
||||
3. **Extension**: Complete Phase 6-7 (Deployment and History).
|
||||
Reference in New Issue
Block a user