diff --git a/i18n/README.jp.md b/i18n/README.jp.md index 6b86abef28d..e49da8f323c 100644 --- a/i18n/README.jp.md +++ b/i18n/README.jp.md @@ -9,13 +9,17 @@ [Supabase](https://supabase.com)は、オープンソースの Firebase 代替製品です。エンタープライズグレードのオープンソースツールを使って、Firebase の機能を構築しています。 -- [x] ホスティングされた Postgres データベース -- [x] リアルタイムサブスクリプション -- [x] 認証・認可 +- [x] ホスティングされた Postgres データベース [Docs](https://supabase.com/docs/guides/database) +- [x] 認証・認可 [Docs](https://supabase.com/docs/guides/auth) - [x] API を自動生成 -- [x] ダッシュボード -- [x] ストレージ + - [x] REST [Docs](https://supabase.com/docs/guides/api#rest-api) + - [x] リアルタイムサブスクリプション [Docs](https://supabase.com/docs/guides/api#realtime-api) + - [x] GraphQL (Beta) [Docs](https://supabase.com/docs/guides/api#graphql-api) - [x] 関数 + - [x] データベース関数 [Docs](https://supabase.com/docs/guides/database/functions) + - [x] Edge Functions [Docs](https://supabase.com/docs/guides/functions) +- [x] ストレージ +- [x] ダッシュボード ![Supabase Dashboard](https://raw.githubusercontent.com/supabase/supabase/master/apps/www/public/images/github/supabase-dashboard.png) @@ -23,11 +27,14 @@ 詳しいドキュメントは[supabase.com/docs](https://supabase.com/docs)をご覧ください。 +コントリビュート方法は[Getting Started](./DEVELOPERS.md)をご覧ください。 + ## コミュニティとサポート - [コミュニティフォーラム](https://github.com/supabase/supabase/discussions) どんな時に使うか:構築の手助け、データベースのベストプラクティスに関する議論など - [GitHub Issue](https://github.com/supabase/supabase/issues) どんな時に使うか: Supabase で起こったバグやエラーについて - [Email サポート](https://supabase.com/docs/support#business-support) どんな時に使うか: ユーザー自身のデータベースやインフラに何か問題が発生した場合 +- [Discord](https://discord.supabase.com) どんな時に使うか: アプリケーションの共有やコミュニティとの交流 ## ステータス @@ -36,9 +43,9 @@ - [x] Public Beta: 企業以外のほとんどのユースケースに耐えうる十分な安定性を確保。 - [ ] Public: 実用的な用途に対応 -現在、Public Beta を実施しています。このリポジトリの"release"にてメジャーアップデートに関する情報を発信しています。 +現在、Public Beta を実施しています。このリポジトリの"releases"にてメジャーアップデートに関する情報を発信しています。 -Watch this repo +Watch this repo --- @@ -49,9 +56,9 @@ Supabase は、オープンソースのツールを組み合わせてできて **現在のアーキテクチャ** Supabase は[ホスティングされたプラットフォーム](https://app.supabase.com)です。登録するだけで、何もインストールせずに使い始めることができます。 -更に現在ローカルでの開発環境を整えており、これはプラットフォームの安定性と並んで今最優先で進めているプロジェクトになります。 +さらに、 [セルフホスティング](https://supabase.com/docs/guides/hosting/overview) や [ローカル開発](https://supabase.com/docs/guides/local-development)も可能です。 -![アーキテクチャー](https://supabase.com/docs/assets/images/supabase-architecture-9050a7317e9ec7efb7807f5194122e48.png) +![アーキテクチャー](https://user-images.githubusercontent.com/70828596/187547862-ffa9d058-0c3a-4851-a3e7-92ccfca4b596.png) - [PostgreSQL](https://www.postgresql.org/)は、30 年以上にわたって開発・改善されてきたオブジェクトリレーショナルデータベースシステムで、信頼性、機能の堅牢性、パフォーマンスの面で高い評価を得ています。 - [Realtime](https://github.com/supabase/realtime)は、PostgreSQL の insert、update、delete の情報を WebSocket で受信できる Elixir サーバです。Supabase は Postgres に組み込まれたレプリケーション機能をリッスンし、レプリケーションのバイトストリームを JSON に変換し、その JSON を WebSocket でブロードキャストします。 @@ -65,17 +72,125 @@ Supabase は[ホスティングされたプラットフォーム](https://app.su Supabase クライアントライブラリはモジュール化されています。それぞれのサブライブラリが、一つの外部システムのための独立した実装となっています。こうすることで、既存のツールをサポートしています。 -- **`supabase-{lang}`**: 下記全てのライブラリを内包したクライアントライブラリ - - `postgrest-{lang}`: [PostgREST](https://github.com/postgrest/postgrest)用のクライアントライブラリ - - `realtime-{lang}`: [Realtime](https://github.com/supabase/realtime)用のクライアントライブラリ - - `gotrue-{lang}`: [GoTrue](https://github.com/netlify/gotrue)用のクライアントライブラリ - -| レポジトリ | 公式 | コミュニティ | -| --------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| **`supabase-{lang}`** | [`JS`](https://github.com/supabase/supabase-js) | [`C#`](https://github.com/supabase/supabase-csharp) \| [`Dart`](https://github.com/supabase/supabase-dart) \| [`Python`](https://github.com/supabase/supabase-py) \| `Rust` \| [`Ruby`](https://github.com/supabase/supabase-rb) \| `Go` | -| `postgrest-{lang}` | [`JS`](https://github.com/supabase/postgrest-js) | [`C#`](https://github.com/supabase/postgrest-csharp) \| [`Dart`](https://github.com/supabase/postgrest-dart) \| [`Python`](https://github.com/supabase/postgrest-py) \| [`Rust`](https://github.com/supabase/postgrest-rs) \| [`Ruby`](https://github.com/supabase/postgrest-rb) \| [`Go`](https://github.com/supabase/postgrest-go) | -| `realtime-{lang}` | [`JS`](https://github.com/supabase/realtime-js) | [`C#`](https://github.com/supabase/realtime-csharp) \| [`Dart`](https://github.com/supabase/realtime-dart) \| [`Python`](https://github.com/supabase/realtime-py) \| `Rust` \| `Ruby` \| `Go` | -| `gotrue-{lang}` | [`JS`](https://github.com/supabase/gotrue-js) | [`C#`](https://github.com/supabase/gotrue-csharp) \| [`Dart`](https://github.com/supabase/gotrue-dart) \| [`Python`](https://github.com/supabase/gotrue-py) \| `Rust` \| `Ruby` \| `Go` | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
言語クライアント機能別クライアント (Supabaseクライアントに同梱)
SupabasePostgRESTGoTrueRealtimeStorageFunctions
⚡️ 公式 ⚡️
JavaScript (TypeScript)supabase-jspostgrest-jsgotrue-jsrealtime-jsstorage-jsfunctions-js
💚 コミュニティ 💚
C#supabase-csharppostgrest-csharpgotrue-csharprealtime-csharpstorage-csharpfunctions-csharp
Dart (Flutter)supabase-dartpostgrest-dartgotrue-dartrealtime-dartstorage-dartfunctions-dart
Go-postgrest-go--storage-go-
Java--gotrue-java---
Kotlin-postgrest-ktgotrue-kt---
Pythonsupabase-pypostgrest-pygotrue-pyrealtime-pystorage-pyfunctions-py
Rubysupabase-rbpostgrest-rb----
Rust-postgrest-rs----
Swiftsupabase-swiftpostgrest-swiftgotrue-swiftrealtime-swiftstorage-swift-
diff --git a/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabaseApiColumnRender.tsx b/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabaseApiColumnRender.tsx index 179d182710d..fc5e883d2a0 100644 --- a/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabaseApiColumnRender.tsx +++ b/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabaseApiColumnRender.tsx @@ -1,16 +1,19 @@ -import { ResponseCodeFormatter, TimestampLocalFormatter } from '../LogsFormatters' +import { + ResponseCodeFormatter, + RowLayout, + TextFormatter, + TimestampLocalFormatter, +} from '../LogsFormatters' export default [ { formatter: (data: any) => ( -
+ -
- - {data.row.method} - {data.row.path} -
-
+ + + + ), }, ] diff --git a/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabasePostgresColumnRender.tsx b/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabasePostgresColumnRender.tsx index e0f5df77216..26dcc8d23a2 100644 --- a/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabasePostgresColumnRender.tsx +++ b/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DatabasePostgresColumnRender.tsx @@ -1,19 +1,18 @@ -import { SeverityFormatter, TimestampLocalFormatter } from '../LogsFormatters' +import { + RowLayout, + SeverityFormatter, + TextFormatter, + TimestampLocalFormatter, +} from '../LogsFormatters' export default [ { formatter: (data: any) => ( -
-
- -
- -
-
-
- {data.row.event_message} -
-
+ + + + + ), }, ] diff --git a/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DefaultPreviewColumnRenderer.tsx b/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DefaultPreviewColumnRenderer.tsx index adcf1c7ab1f..4f84b89bba9 100644 --- a/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DefaultPreviewColumnRenderer.tsx +++ b/studio/components/interfaces/Settings/Logs/LogColumnRenderers/DefaultPreviewColumnRenderer.tsx @@ -1,16 +1,13 @@ import { PreviewLogData } from '..' -import { TimestampLocalFormatter } from '../LogsFormatters' +import { RowLayout, TextFormatter, TimestampLocalFormatter } from '../LogsFormatters' -const DefaultPreviewColumnRenderer = [ +export default [ { - formatter: (data: { row: PreviewLogData }) => { - return ( -
- - {data.row.event_message} -
- ) - }, + formatter: (data: { row: PreviewLogData }) => ( + + + + + ), }, ] -export default DefaultPreviewColumnRenderer diff --git a/studio/components/interfaces/Settings/Logs/LogColumnRenderers/FunctionsEdgeColumnRender.tsx b/studio/components/interfaces/Settings/Logs/LogColumnRenderers/FunctionsEdgeColumnRender.tsx index bb495ab5deb..3b53839536d 100644 --- a/studio/components/interfaces/Settings/Logs/LogColumnRenderers/FunctionsEdgeColumnRender.tsx +++ b/studio/components/interfaces/Settings/Logs/LogColumnRenderers/FunctionsEdgeColumnRender.tsx @@ -1,36 +1,19 @@ -import { HeaderFormmater, ResponseCodeFormatter, TimestampLocalFormatter } from '../LogsFormatters' +import { + ResponseCodeFormatter, + RowLayout, + TextFormatter, + TimestampLocalFormatter, +} from '../LogsFormatters' export default [ { - key: 'timestamp', - headerRenderer: () => ( -
- -
+ formatter: (data: any) => ( + + + + + + ), - name: 'timestamp', - formatter: (data: any) => , - width: 128, - }, - { - key: 'status_code', - headerRenderer: () => , - name: 'status_code', - formatter: (data: any) => , - - width: 0, - resizable: true, - }, - { - key: 'method', - headerRenderer: () => , - width: 0, - resizable: true, - }, - { - key: 'id', - headerRenderer: () => , - name: 'id', - resizable: true, }, ] diff --git a/studio/components/interfaces/Settings/Logs/LogColumnRenderers/FunctionsLogsColumnRender.tsx b/studio/components/interfaces/Settings/Logs/LogColumnRenderers/FunctionsLogsColumnRender.tsx index 264067087d9..ec3b36648dd 100644 --- a/studio/components/interfaces/Settings/Logs/LogColumnRenderers/FunctionsLogsColumnRender.tsx +++ b/studio/components/interfaces/Settings/Logs/LogColumnRenderers/FunctionsLogsColumnRender.tsx @@ -1,36 +1,22 @@ -import { HeaderFormmater, SeverityFormatter, TimestampLocalFormatter } from '../LogsFormatters' +import { + RowLayout, + SeverityFormatter, + TextFormatter, + TimestampLocalFormatter, +} from '../LogsFormatters' export default [ { - key: 'timestamp', - headerRenderer: () => ( -
- -
- ), - name: 'timestamp', formatter: (data: any) => ( - + + + {data.row.event_type === 'uncaughtException' ? ( + + ) : ( + + )} + + ), - width: 128, - resizable: true, - }, - { - key: 'level', - headerRenderer: () => , - name: 'level', - formatter: (data: any) => { - if (data.row.event_type === 'uncaughtException') { - return - } - return - }, - width: 24, - resizable: true, - }, - { - key: 'event_message', - headerRenderer: () => , - resizable: true, }, ] diff --git a/studio/components/interfaces/Settings/Logs/LogsFormatters.tsx b/studio/components/interfaces/Settings/Logs/LogsFormatters.tsx index 1ac89c1f5ae..63930ef3f94 100644 --- a/studio/components/interfaces/Settings/Logs/LogsFormatters.tsx +++ b/studio/components/interfaces/Settings/Logs/LogsFormatters.tsx @@ -6,8 +6,18 @@ import { IconAlertCircle, IconInfo } from '@supabase/ui' import dayjs from 'dayjs' +import React from 'react' import { isUnixMicro, unixMicroToIsoTimestamp } from '.' +export const RowLayout: React.FC = ({ children }) => ( +
{children}
+) + +export const TextFormatter: React.FC<{ className?: string; value: string }> = ({ + value, + className, +}) => {value} + export const ResponseCodeFormatter = ({ value }: any) => { if (!value) { return ( @@ -109,6 +119,9 @@ export const SeverityFormatter = ({ const uppercasedValue = value.toUpperCase() const text = uppercase ? uppercasedValue : value + const Layout: React.FC<{ className?: string }> = ({ className, children }) => ( +
{children}
+ ) switch (uppercasedValue) { case 'UNCAUGHTEXCEPTION': @@ -116,12 +129,12 @@ export const SeverityFormatter = ({ case 'FATAL': case 'ERROR': return ( -
+
{text} -
+ ) break @@ -129,45 +142,45 @@ export const SeverityFormatter = ({ case 'DEBUG': return ( -
+
{text} -
+ ) break case 'LOG': return ( -
+
{text} -
+ ) break case 'WARNING': return ( -
+
{text} -
+ ) break // All other responses default: return ( -
+
-
+ ) break } diff --git a/studio/components/to-be-cleaned/SqlEditor/TabSqlQuery.js b/studio/components/to-be-cleaned/SqlEditor/TabSqlQuery.js index 3fbdfcd0174..2b46001a02b 100644 --- a/studio/components/to-be-cleaned/SqlEditor/TabSqlQuery.js +++ b/studio/components/to-be-cleaned/SqlEditor/TabSqlQuery.js @@ -78,6 +78,7 @@ const TabSqlQuery = observer(() => {
@@ -88,7 +89,7 @@ const TabSqlQuery = observer(() => { }) export default TabSqlQuery -const MonacoEditor = ({ error, updateSqlSnippet }) => { +const MonacoEditor = ({ error, updateSqlSnippet, setUpdatingRequired }) => { const sqlEditorStore = useSqlStore() const editorRef = useRef(null) const monacoRef = useRef(null) @@ -173,6 +174,10 @@ const MonacoEditor = ({ error, updateSqlSnippet }) => { // this is so any SQL run will be whatever is currently in monaco editor sqlEditorStore.activeTab.setQuery(value) + // inform the content store that the SQL has changed and needs to be persisted + // this is so we can block the tab being closed if an update is required + setUpdatingRequired?.() + // debounce changes debounceUpdateSqlSnippet(value) } diff --git a/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerColumn.js b/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerColumn.js index 8972c794999..eb8be9e7145 100644 --- a/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerColumn.js +++ b/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerColumn.js @@ -233,7 +233,7 @@ const FileExplorerColumn = ({ {/* Drag drop upload CTA for when column is empty */} {column.items.length === 0 && column.status !== STORAGE_ROW_STATUS.LOADING && (
- +

Drop your files here

Or upload them via the "Upload file" button above diff --git a/studio/pages/_app.tsx b/studio/pages/_app.tsx index 3d3cfcbf0c0..d9a8d280b26 100644 --- a/studio/pages/_app.tsx +++ b/studio/pages/_app.tsx @@ -52,6 +52,37 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) { handleEmailVerificationError() }, []) + const getSavingState = () => rootStore.content.savingState + + // prompt the user if they try and leave with unsaved content store changes + useEffect(() => { + const warningText = 'You have unsaved changes - are you sure you wish to leave this page?' + + const handleWindowClose = (e: BeforeUnloadEvent) => { + const savingState = getSavingState() + + const unsavedChanges = + savingState === 'UPDATING_REQUIRED' || + savingState === 'UPDATING' || + savingState === 'UPDATING_FAILED' + + if (!unsavedChanges) { + return + } + + e.preventDefault() + + return (e.returnValue = warningText) + } + + window.addEventListener('beforeunload', handleWindowClose) + + return () => { + window.removeEventListener('beforeunload', handleWindowClose) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + const getLayout = Component.getLayout ?? ((page) => page) return ( diff --git a/studio/stores/project/ProjectContentStore.ts b/studio/stores/project/ProjectContentStore.ts index 3298980145b..13d35d18297 100644 --- a/studio/stores/project/ProjectContentStore.ts +++ b/studio/stores/project/ProjectContentStore.ts @@ -15,7 +15,13 @@ export interface IProjectContentStore { isLoading: boolean isInitialized: boolean isLoaded: boolean - savingState: 'IDLE' | 'CREATING' | 'CREATING_FAILED' | 'UPDATING' | 'UPDATING_FAILED' + savingState: + | 'IDLE' + | 'CREATING' + | 'CREATING_FAILED' + | 'UPDATING_REQUIRED' + | 'UPDATING' + | 'UPDATING_FAILED' error: any recentLogSqlSnippets: LogSqlSnippets.Content[] @@ -81,6 +87,7 @@ export interface IProjectContentStore { del(id: any): Promise<{ data: boolean; error: unknown }> delOptimistically(id: string): { data: boolean; error: null } + setUpdatingRequired(): void } export default class ProjectContentStore implements IProjectContentStore { @@ -102,7 +109,13 @@ export default class ProjectContentStore implements IProjectContentStore { recentLogSqlSnippets: LogSqlSnippets.Content[] = [] state = this.STATES.INITIAL - savingState: 'IDLE' | 'CREATING' | 'CREATING_FAILED' | 'UPDATING' | 'UPDATING_FAILED' + savingState: + | 'IDLE' + | 'CREATING' + | 'CREATING_FAILED' + | 'UPDATING_REQUIRED' + | 'UPDATING' + | 'UPDATING_FAILED' error = null constructor(rootStore: IRootStore, options: { projectRef: string }) { @@ -354,6 +367,12 @@ export default class ProjectContentStore implements IProjectContentStore { return { data: true, error: null } } + setUpdatingRequired() { + if (this.savingState === 'IDLE' || this.savingState === 'UPDATING_FAILED') { + this.savingState = 'UPDATING_REQUIRED' + } + } + setProjectRef(ref?: string) { if (ref) { this.projectRef = ref diff --git a/studio/tsconfig.json b/studio/tsconfig.json index 71436a2fdd4..200eb6a9998 100644 --- a/studio/tsconfig.json +++ b/studio/tsconfig.json @@ -14,7 +14,8 @@ "isolatedModules": true, "jsx": "preserve", "baseUrl": ".", - "downlevelIteration": true + "downlevelIteration": true, + "incremental": true }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"], "exclude": ["node_modules"]