diff --git a/.github/scripts/algolia.py b/.github/scripts/algolia.py new file mode 100644 index 00000000000..5071ea58006 --- /dev/null +++ b/.github/scripts/algolia.py @@ -0,0 +1,118 @@ +import os +from re import S +import sys +import json +from bs4 import BeautifulSoup +from algoliasearch.search_client import SearchClient + +url = "docs.dapr.io" +if len(sys.argv) > 1: + starting_directory = os.path.join(os.getcwd(), str(sys.argv[1])) +else: + starting_directory = os.getcwd() + +ALGOLIA_APP_ID = os.getenv('ALGOLIA_APP_ID') +ALGOLIA_API_KEY = os.getenv('ALGOLIA_API_WRITE_KEY') +ALGOLIA_INDEX_NAME = os.getenv('ALGOLIA_INDEX_NAME') + +client = SearchClient.create(ALGOLIA_APP_ID, ALGOLIA_API_KEY) +index = client.init_index(ALGOLIA_INDEX_NAME) + +excluded_files = [ + "404.html", +] + +exluded_directories = [ + "zh-hans", +] + +rankings = { + "Getting started": 0, + "Concepts": 100, + "Developing applications": 200, + "Operations": 300, + "Reference": 400, + "Contributing": 500, + "Home": 600 +} + +def scan_directory(directory: str, pages: list): + if os.path.basename(directory) in exluded_directories: + print(f'Skipping directory: {directory}') + return + for file in os.listdir(directory): + path = os.path.join(directory, file) + if os.path.isfile(path): + if file.endswith(".html") and file not in excluded_files: + if '' not in open(path, encoding="utf8").read(): + print(f'Indexing: {path}') + pages.append(path) + else: + print(f'Skipping hidden page: {path}') + else: + scan_directory(path, pages) + +def parse_file(path: str): + data = {} + data["hierarchy"] = {} + data["rank"] = 999 + data["subrank"] = 99 + data["type"] = "lvl2" + data["lvl0"] = "" + data["lvl1"] = "" + data["lvl2"] = "" + data["lvl3"] = "" + text = "" + subrank = 0 + with open(path, "r", errors='ignore') as file: + content = file.read() + soup = BeautifulSoup(content, "html.parser") + for meta in soup.find_all("meta"): + if meta.get("name") == "description": + data["lvl2"] = meta.get("content") + data["hierarchy"]["lvl1"] = meta.get("content") + elif meta.get("property") == "og:title": + data["lvl0"] = meta.get("content") + data["hierarchy"]["lvl0"] = meta.get("content") + data["hierarchy"]["lvl2"] = meta.get("content") + elif meta.get("property") == "og:url": + data["url"] = meta.get("content") + data["path"] = meta.get("content").split(url)[1] + data["objectID"] = meta.get("content").split(url)[1] + breadcrumbs = soup.find_all("li", class_="breadcrumb-item") + try: + subrank = len(breadcrumbs) + data["subrank"] = subrank + except: + subrank = 99 + data["subrank"] = 99 + for bc in breadcrumbs: + section = bc.text.strip() + data["lvl1"] = section + data["hierarchy"]["lvl0"] = section + try: + data["rank"] = rankings[section] + subrank + except: + print(f"Rank not found for section {section}") + data["rank"] = 998 + break + for p in soup.find_all("p"): + if p.text != "": + text = text + p.text + data["text"] = text + return data + +def index_payload(payload): + res = index.replace_all_objects(payload) + res.wait() + + +if __name__ == "__main__": + pages = [] + payload = [] + scan_directory(starting_directory, pages) + for page in pages: + data = parse_file(page) + if "objectID" in data: + payload.append(data) + index_payload(payload) diff --git a/.github/workflows/website-root.yml b/.github/workflows/website-root.yml index 0265713f715..ed8c3b491f1 100644 --- a/.github/workflows/website-root.yml +++ b/.github/workflows/website-root.yml @@ -1,6 +1,7 @@ name: Azure Static Web App Root on: + workflow_dispatch: push: branches: - v1.11 @@ -9,35 +10,65 @@ on: branches: - v1.11 +concurrency: + # Cancel the previously triggered build for only PR build. + group: website-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + jobs: build_and_deploy_job: - if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') + name: Build Hugo Website + if: github.event.action != 'closed' runs-on: ubuntu-latest - name: Build and Deploy Job + env: + SWA_BASE: 'proud-bay-0e9e0e81e' + HUGO_ENV: production steps: - - uses: actions/checkout@v3 + - name: Checkout docs repo + uses: actions/checkout@v3 + with: + submodules: true + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: '14' + - name: Setup Hugo + uses: peaceiris/actions-hugo@v2.5.0 with: - submodules: recursive - fetch-depth: 0 + hugo-version: 0.102.3 + extended: true - name: Setup Docsy - run: cd daprdocs && git submodule update --init --recursive && sudo npm install -D --save autoprefixer && sudo npm install -D --save postcss-cli - - name: Build And Deploy - id: builddeploy + run: | + cd daprdocs + git submodule update --init --recursive + sudo npm install -D --save autoprefixer + sudo npm install -D --save postcss-cli + - name: Build Hugo Website + run: | + cd daprdocs + git config --global --add safe.directory /github/workspace + if [ $GITHUB_EVENT_NAME == 'pull_request' ]; then + STAGING_URL="https://${SWA_BASE}-${{github.event.number}}.westus2.azurestaticapps.net/" + fi + hugo ${STAGING_URL+-b "$STAGING_URL"} + - name: Deploy docs site uses: Azure/static-web-apps-deploy@v1 - env: - HUGO_ENV: production - HUGO_VERSION: "0.100.2" with: azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_PROUD_BAY_0E9E0E81E }} - skip_deploy_on_missing_secrets: true - repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) + repo_token: ${{ secrets.GITHUB_TOKEN }} action: "upload" - app_location: "/daprdocs" - app_build_command: "git config --global --add safe.directory /github/workspace && hugo" - output_location: "public" - skip_api_build: true + app_location: "daprdocs/public/" + api_location: "daprdocs/public/" + output_location: "" + skip_app_build: true + - name: Upload Hugo artifacts + uses: actions/upload-artifact@v3 + with: + name: hugo_build + path: ./daprdocs/public/ + if-no-files-found: error - close_pull_request_job: + close_staging_site: if: github.event_name == 'pull_request' && github.event.action == 'closed' runs-on: ubuntu-latest name: Close Pull Request Job @@ -48,3 +79,29 @@ jobs: with: azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_PROUD_BAY_0E9E0E81E }} action: "close" + + algolia_index: + name: Index site for Algolia + if: github.event_name == 'push' + needs: ['build_and_deploy_job'] + runs-on: ubuntu-latest + env: + ALGOLIA_APP_ID: ${{ secrets.ALGOLIA_APP_ID }} + ALGOLIA_API_WRITE_KEY: ${{ secrets.ALGOLIA_API_WRITE_KEY }} + ALGOLIA_INDEX_NAME: daprdocs + steps: + - name: Checkout docs repo + uses: actions/checkout@v2 + with: + submodules: false + - name: Download Hugo artifacts + uses: actions/download-artifact@v3 + with: + name: hugo_build + path: site/ + - name: Install Python packages + run: | + pip install --upgrade bs4 + pip install --upgrade 'algoliasearch>=2.0,<3.0' + - name: Index site + run: python ./.github/scripts/algolia.py ./site diff --git a/daprdocs/assets/scss/_code.scss b/daprdocs/assets/scss/_code.scss index dd05e51bf1b..49ad9c8b36a 100644 --- a/daprdocs/assets/scss/_code.scss +++ b/daprdocs/assets/scss/_code.scss @@ -1,38 +1,12 @@ // Code formatting. -.copy-code-button { - color: #272822; - background-color: #FFF; - border-color: #0D2192; - border: 2px solid; - border-radius: 3px 3px 0px 0px; - - /* right-align */ - display: block; - margin-left: auto; - margin-right: 0; - - margin-bottom: -2px; - padding: 3px 8px; - font-size: 0.8em; +.highlight .copy-icon { + position: absolute; + right: 20px; + top: 18px; + opacity: 0.7; } -.copy-code-button:hover { - cursor: pointer; - background-color: #F2F2F2; -} - -.copy-code-button:focus { - /* Avoid an ugly focus outline on click in Chrome, - but darken the button for accessibility. - See https://stackoverflow.com/a/25298082/1481479 */ - background-color: #E6E6E6; - outline: 0; -} - -.copy-code-button:active { - background-color: #D9D9D9; -} .highlight pre { /* Avoid pushing up the copy buttons. */ @@ -40,25 +14,31 @@ } .td-content { - // Highlighted code. + + // Highlighted code. .highlight { @extend .card; - + margin: 0rem 0; padding: 0rem; margin-bottom: 2rem; max-width: 100%; - + + border: none; + pre { margin: 0; padding: 1rem; + border-radius: 10px; } } // Inline code - p code, li > code, table code { + p code, + li>code, + table code { color: inherit; padding: 0.2em 0.4em; margin: 0; @@ -78,11 +58,11 @@ word-wrap: normal; background-color: $gray-100; padding: $spacer; - + max-width: 100%; - > code { - background-color: inherit !important; + >code { + background-color: inherit !important; padding: 0; margin: 0; font-size: 100%; diff --git a/daprdocs/content/en/developing-applications/building-blocks/pubsub/pubsub-cloudevents.md b/daprdocs/content/en/developing-applications/building-blocks/pubsub/pubsub-cloudevents.md index 251d3f234c1..51d442f8a71 100644 --- a/daprdocs/content/en/developing-applications/building-blocks/pubsub/pubsub-cloudevents.md +++ b/daprdocs/content/en/developing-applications/building-blocks/pubsub/pubsub-cloudevents.md @@ -92,7 +92,7 @@ You can add additional fields to a custom CloudEvent that are not part of the of Publish a CloudEvent to the `orders` topic: ```bash -dapr publish --publish-app-id orderprocessing --pubsub order-pub-sub --topic orders --data '{"specversion" : "1.0", "type" : "com.dapr.cloudevent.sent", "source" : "testcloudeventspubsub", "subject" : "Cloud Events Test", "id" : "someCloudEventId", "time" : "2021-08-02T09:00:00Z", "datacontenttype" : "application/cloudevents+json", "data" : {"orderId": "100"}}' +dapr publish --publish-app-id orderprocessing --pubsub order-pub-sub --topic orders --data '{\"orderId\": \"100\"}' ``` {{% /codetab %}} diff --git a/daprdocs/content/en/operations/monitoring/metrics/azure-monitor.md b/daprdocs/content/en/operations/monitoring/metrics/azure-monitor.md index d63b820ea56..3011ef399b4 100644 --- a/daprdocs/content/en/operations/monitoring/metrics/azure-monitor.md +++ b/daprdocs/content/en/operations/monitoring/metrics/azure-monitor.md @@ -15,118 +15,120 @@ description: "Enable Dapr metrics and logs with Azure Monitor for Azure Kubernet ## Enable Prometheus metric scrape using config map -1. Make sure that omsagents are running - -```bash -$ kubectl get pods -n kube-system -NAME READY STATUS RESTARTS AGE -... -omsagent-75qjs 1/1 Running 1 44h -omsagent-c7c4t 1/1 Running 0 44h -omsagent-rs-74f488997c-dshpx 1/1 Running 1 44h -omsagent-smtk7 1/1 Running 1 44h -... -``` - -2. Apply config map to enable Prometheus metrics endpoint scrape. - -You can use [azm-config-map.yaml](/docs/azm-config-map.yaml) to enable prometheus metrics endpoint scrape. - -If you installed Dapr to the different namespace, you need to change the `monitor_kubernetes_pod_namespaces` array values. For example: - -```yaml -... - prometheus-data-collection-settings: |- - [prometheus_data_collection_settings.cluster] - interval = "1m" - monitor_kubernetes_pods = true - monitor_kubernetes_pods_namespaces = ["dapr-system", "default"] - [prometheus_data_collection_settings.node] - interval = "1m" -... -``` - -Apply config map: - -```bash -kubectl apply -f ./azm-config.map.yaml -``` +1. Make sure that Azure Monitor Agents (AMA) are running. + + ```bash + $ kubectl get pods -n kube-system + NAME READY STATUS RESTARTS AGE + ... + ama-logs-48kpv 2/2 Running 0 2d13h + ama-logs-mx24c 2/2 Running 0 2d13h + ama-logs-rs-f9bbb9898-vbt6k 1/1 Running 0 30h + ama-logs-sm2mz 2/2 Running 0 2d13h + ama-logs-z7p4c 2/2 Running 0 2d13h + ... + ``` + +1. Apply config map to enable Prometheus metrics endpoint scrape. + + You can use [azm-config-map.yaml](/docs/azm-config-map.yaml) to enable Prometheus metrics endpoint scrape. + + If you installed Dapr to a different namespace, you need to change the `monitor_kubernetes_pod_namespaces` array values. For example: + + ```yaml + ... + prometheus-data-collection-settings: |- + [prometheus_data_collection_settings.cluster] + interval = "1m" + monitor_kubernetes_pods = true + monitor_kubernetes_pods_namespaces = ["dapr-system", "default"] + [prometheus_data_collection_settings.node] + interval = "1m" + ... + ``` + + Apply config map: + + ```bash + kubectl apply -f ./azm-config.map.yaml + ``` ## Install Dapr with JSON formatted logs -1. Install Dapr with enabling JSON-formatted logs - -```bash -helm install dapr dapr/dapr --namespace dapr-system --set global.logAsJson=true -``` - -2. Enable JSON formatted log in Dapr sidecar and add Prometheus annotations. - -> Note: OMS Agent scrapes the metrics only if replicaset has Prometheus annotations. - -Add `dapr.io/log-as-json: "true"` annotation to your deployment yaml. - -Example: -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pythonapp - namespace: default - labels: - app: python -spec: - replicas: 1 - selector: - matchLabels: - app: python - template: - metadata: - labels: - app: python - annotations: - dapr.io/enabled: "true" - dapr.io/app-id: "pythonapp" - dapr.io/log-as-json: "true" - prometheus.io/scrape: "true" - prometheus.io/port: "9090" - prometheus.io/path: "/" - -... -``` +1. Install Dapr with enabling JSON-formatted logs. + + ```bash + helm install dapr dapr/dapr --namespace dapr-system --set global.logAsJson=true + ``` + +1. Enable JSON formatted log in Dapr sidecar and add Prometheus annotations. + + > Note: The Azure Monitor Agents (AMA) only sends the metrics if the Prometheus annotations are set. + + Add `dapr.io/log-as-json: "true"` annotation to your deployment yaml. + + Example: + + ```yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: pythonapp + namespace: default + labels: + app: python + spec: + replicas: 1 + selector: + matchLabels: + app: python + template: + metadata: + labels: + app: python + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "pythonapp" + dapr.io/log-as-json: "true" + prometheus.io/scrape: "true" + prometheus.io/port: "9090" + prometheus.io/path: "/" + + ... + ``` ## Search metrics and logs with Azure Monitor -1. Go to Azure Monitor +1. Go to Azure Monitor in the Azure portal. -2. Search Dapr logs +1. Search Dapr **Logs**. -Here is an example query, to parse JSON formatted logs and query logs from dapr system processes. + Here is an example query, to parse JSON formatted logs and query logs from Dapr system processes. -``` -ContainerLog -| extend parsed=parse_json(LogEntry) -| project Time=todatetime(parsed['time']), app_id=parsed['app_id'], scope=parsed['scope'],level=parsed['level'], msg=parsed['msg'], type=parsed['type'], ver=parsed['ver'], instance=parsed['instance'] -| where level != "" -| sort by Time -``` + ``` + ContainerLog + | extend parsed=parse_json(LogEntry) + | project Time=todatetime(parsed['time']), app_id=parsed['app_id'], scope=parsed['scope'],level=parsed['level'], msg=parsed['msg'], type=parsed['type'], ver=parsed['ver'], instance=parsed['instance'] + | where level != "" + | sort by Time + ``` -3. Search metrics +1. Search **Metrics**. -This query, queries process_resident_memory_bytes Prometheus metrics for Dapr system processes and renders timecharts + This query, queries `process_resident_memory_bytes` Prometheus metrics for Dapr system processes and renders timecharts. -``` -InsightsMetrics -| where Namespace == "prometheus" and Name == "process_resident_memory_bytes" -| extend tags=parse_json(Tags) -| project TimeGenerated, Name, Val, app=tostring(tags['app']) -| summarize memInBytes=percentile(Val, 99) by bin(TimeGenerated, 1m), app -| where app startswith "dapr-" -| render timechart -``` + ``` + InsightsMetrics + | where Namespace == "prometheus" and Name == "process_resident_memory_bytes" + | extend tags=parse_json(Tags) + | project TimeGenerated, Name, Val, app=tostring(tags['app']) + | summarize memInBytes=percentile(Val, 99) by bin(TimeGenerated, 1m), app + | where app startswith "dapr-" + | render timechart + ``` -# References +## References -* [Configure scraping of Prometheus metrics with Azure Monitor for containers](https://docs.microsoft.com/azure/azure-monitor/insights/container-insights-prometheus-integration) -* [Configure agent data collection for Azure Monitor for containers](https://docs.microsoft.com/azure/azure-monitor/insights/container-insights-agent-config) -* [Azure Monitor Query](https://docs.microsoft.com/azure/azure-monitor/log-query/query-language) +- [Configure scraping of Prometheus metrics with Azure Monitor for containers](https://docs.microsoft.com/azure/azure-monitor/insights/container-insights-prometheus-integration) +- [Configure agent data collection for Azure Monitor for containers](https://docs.microsoft.com/azure/azure-monitor/insights/container-insights-agent-config) +- [Azure Monitor Query](https://docs.microsoft.com/azure/azure-monitor/log-query/query-language) diff --git a/daprdocs/content/en/reference/components-reference/supported-bindings/storagequeues.md b/daprdocs/content/en/reference/components-reference/supported-bindings/storagequeues.md index 5e0d89330bb..e3296660123 100644 --- a/daprdocs/content/en/reference/components-reference/supported-bindings/storagequeues.md +++ b/daprdocs/content/en/reference/components-reference/supported-bindings/storagequeues.md @@ -27,6 +27,8 @@ spec: value: "***********" - name: queueName value: "myqueue" +# - name: pollingInterval +# value: "30s" # - name: ttlInSeconds # value: "60" # - name: decodeBase64 @@ -50,6 +52,7 @@ The above example uses secrets as plain strings. It is recommended to use a secr | `accountName` | Y | Input/Output | The name of the Azure Storage account | `"account1"` | | `accountKey` | Y* | Input/Output | The access key of the Azure Storage account. Only required when not using Azure AD authentication. | `"access-key"` | | `queueName` | Y | Input/Output | The name of the Azure Storage queue | `"myqueue"` | +| `pollingInterval` | N | Output | Set the interval to poll Azure Storage Queues for new messages, as a Go duration value. Default: `"10s"` | `"30s"` | | `ttlInSeconds` | N | Output | Parameter to set the default message time to live. If this parameter is omitted, messages will expire after 10 minutes. See [also](#specifying-a-ttl-per-message) | `"60"` | | `decodeBase64` | N | Output | Configuration to decode base64 file content before saving to Storage Queues. (In case of saving a file with binary content). Defaults to `false` | `true`, `false` | | `encodeBase64` | N | Output | If enabled base64 encodes the data payload before uploading to Azure storage queues. Default `false`. | `true`, `false` | diff --git a/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-sqlserver.md b/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-sqlserver.md index 4ef3c7dec80..e4f48d547b6 100644 --- a/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-sqlserver.md +++ b/daprdocs/content/en/reference/components-reference/supported-state-stores/setup-sqlserver.md @@ -2,14 +2,16 @@ type: docs title: "Microsoft SQL Server & Azure SQL" linkTitle: "Microsoft SQL Server & Azure SQL" -description: Detailed information on the Microsoft SQL Server and Azure SQL state store component +description: Detailed information on the Microsoft SQL Server state store component aliases: - "/operations/components/setup-state-store/supported-state-stores/setup-sqlserver/" --- ## Component format -To set up Microsoft SQL Server and Azure SQL state stores, create a component of type `state.sqlserver`. See [this guide]({{< ref "howto-get-save-state.md#step-1-setup-a-state-store" >}}) on how to create and apply a state store configuration. +This state store component can be used with both [Microsoft SQL Server](https://learn.microsoft.com/sql/) and [Azure SQL](https://learn.microsoft.com/azure/azure-sql/). + +To set up this state store, create a component of type `state.sqlserver`. See [this guide]({{< ref "howto-get-save-state.md#step-1-setup-a-state-store" >}}) on how to create and apply a state store configuration. ```yaml @@ -21,30 +23,42 @@ spec: type: state.sqlserver version: v1 metadata: - - name: connectionString - value: # Required. - - name: tableName - value: # Optional. defaults to "state" - - name: keyType - value: # Optional. defaults to "string" - - name: keyLength - value: # Optional. defaults to 200. You be used with "string" keyType - - name: schema - value: # Optional. defaults to "dbo" - - name: indexedProperties - value: # Optional. List of IndexedProperties. - - name: metadataTableName # Optional. Name of the table where to store metadata used by Dapr - value: "dapr_metadata" - - name: cleanupIntervalInSeconds # Optional. Cleanup interval in seconds, to remove expired rows - value: 300 - + # Authenticate using SQL Server credentials + - name: connectionString + value: | + Server=myServerName\myInstanceName;Database=myDataBase;User Id=myUsername;Password=myPassword; + + # Authenticate with Azure AD (Azure SQL only) + # "useAzureAD" be set to "true" + - name: useAzureAD + value: true + # Connection string or URL of the Azure SQL database, optionally containing the database + - name: connectionString + value: | + sqlserver://myServerName.database.windows.net:1433?database=myDataBase + + # Other optional fields (listing default values) + - name: tableName + value: "state" + - name: metadataTableName + value: "dapr_metadata" + - name: schema + value: "dbo" + - name: keyType + value: "string" + - name: keyLength + value: "200" + - name: indexedProperties + value: "" + - name: cleanupIntervalInSeconds + value: "3600" ``` {{% alert title="Warning" color="warning" %}} The above example uses secrets as plain strings. It is recommended to use a secret store for the secrets as described [here]({{< ref component-secrets.md >}}). {{% /alert %}} -If you wish to use SQL server as an [actor state store]({{< ref "state_api.md#configuring-state-store-for-actors" >}}), append the following to the yaml. +If you wish to use SQL server as an [actor state store]({{< ref "state_api.md#configuring-state-store-for-actors" >}}), append the following to the metadata: ```yaml - name: actorStateStore @@ -53,24 +67,43 @@ If you wish to use SQL server as an [actor state store]({{< ref "state_api.md#co ## Spec metadata fields +### Authenticate using SQL Server credentials + +The following metadata options are **required** to authenticate using SQL Server credentials. This is supported on both SQL Server and Azure SQL. + +| Field | Required | Details | Example | +|--------|:--------:|---------|---------| +| `connectionString` | Y | The connection string used to connect.
If the connection string contains the database, it must already exist. Otherwise, if the database is omitted, a default database named "Dapr" is created. | `"Server=myServerName\myInstanceName;Database=myDataBase;User Id=myUsername;Password=myPassword;"` | + +### Authenticate using Azure AD + +Authenticating with Azure AD is supported with Azure SQL only. All authentication methods supported by Dapr can be used, including client credentials ("service principal") and Managed Identity. + +| Field | Required | Details | Example | +|--------|:--------:|---------|---------| +| `useAzureAD` | Y | Must be set to `true` to enable the component to retrieve access tokens from Azure AD. | `"true"` | +| `connectionString` | Y | The connection string or URL of the Azure SQL database, **without credentials**.
If the connection string contains the database, it must already exist. Otherwise, if the database is omitted, a default database named "Dapr" is created. | `"sqlserver://myServerName.database.windows.net:1433?database=myDataBase"` | +| `azureTenantId` | N | ID of the Azure AD tenant | `"cd4b2887-304c-47e1-b4d5-65447fdd542b"` | +| `azureClientId` | N | Client ID (application ID) | `"c7dd251f-811f-4ba2-a905-acd4d3f8f08b"` | +| `azureClientSecret` | N | Client secret (application password) | `"Ecy3XG7zVZK3/vl/a2NSB+a1zXLa8RnMum/IgD0E"` | + +### Other metadata options + | Field | Required | Details | Example | |--------------------|:--------:|---------|---------| -| connectionString | Y | The connection string used to connect. If the connection string contains the database it must already exist. If the database is omitted a default database named `"Dapr"` is created. | `"Server=myServerName\myInstanceName;Database=myDataBase;User Id=myUsername;Password=myPassword;"` -| tableName | N | The name of the table to use. Alpha-numeric with underscores. Defaults to `"state"` | `"table_name"` -| keyType | N | The type of key used. Defaults to `"string"` | `"string"` -| keyLength | N | The max length of key. Used along with `"string"` keytype. Defaults to `"200"` | `"200"` -| schema | N | The schema to use. Defaults to `"dbo"` | `"dapr"`,`"dbo"` -| indexedProperties | N | List of IndexedProperties. | `'[{"column": "transactionid", "property": "id", "type": "int"}, {"column": "customerid", "property": "customer", "type": "nvarchar(100)"}]'` -| actorStateStore | N | Indicates that Dapr should configure this component for the actor state store ([more information]({{< ref "state_api.md#configuring-state-store-for-actors" >}})). | `"true"` -| metadataTableName | N | Name of the table Dapr uses to store a few metadata properties. Defaults to `dapr_metadata`. | `"dapr_metadata"` -| cleanupIntervalInSeconds | N | Interval, in seconds, to clean up rows with an expired TTL. Default: `3600` (i.e. 1 hour). Setting this to values <=0 disables the periodic cleanup. | `1800`, `-1` +| `tableName` | N | The name of the table to use. Alpha-numeric with underscores. Defaults to `"state"` | `"table_name"` +| `metadataTableName` | N | Name of the table Dapr uses to store a few metadata properties. Defaults to `dapr_metadata`. | `"dapr_metadata"` +| `keyType` | N | The type of key used. Supported values: `"string"` (default), `"uuid"`, `"integer"`.| `"string"` +| `keyLength` | N | The max length of key. Ignored if "keyType" is not `string`. Defaults to `"200"` | `"200"` +| `schema` | N | The schema to use. Defaults to `"dbo"` | `"dapr"`,`"dbo"` +| `indexedProperties` | N | List of indexed properties, as a string containing a JSON document. | `'[{"column": "transactionid", "property": "id", "type": "int"}, {"column": "customerid", "property": "customer", "type": "nvarchar(100)"}]'` +| `actorStateStore` | N | Indicates that Dapr should configure this component for the actor state store ([more information]({{< ref "state_api.md#configuring-state-store-for-actors" >}})). | `"true"` +| `cleanupIntervalInSeconds` | N | Interval, in seconds, to clean up rows with an expired TTL. Default: `"3600"` (i.e. 1 hour). Setting this to values <=0 disables the periodic cleanup. | `"1800"`, `"-1"` ## Create a Microsoft SQL Server/Azure SQL instance -[Follow the instructions](https://docs.microsoft.com/azure/azure-sql/database/single-database-create-quickstart?view=azuresql&tabs=azure-portal) from the Azure documentation on how to create a SQL database. The database must be created before Dapr consumes it. - -> Note: Microsoft SQL Server/Azure SQL state store also supports SQL Server running on VMs and in Docker.** +[Follow the instructions](https://docs.microsoft.com/azure/azure-sql/database/single-database-create-quickstart?view=azuresql&tabs=azure-portal) from the Azure documentation on how to create a SQL database. The database must be created before Dapr consumes it. In order to setup SQL Server as a state store, you need the following properties: @@ -104,6 +137,7 @@ CREATE CLUSTERED INDEX expiredate_idx ON state(ExpireDate ASC) ``` ## Related links + - [Basic schema for a Dapr component]({{< ref component-schema >}}) - Read [this guide]({{< ref "howto-get-save-state.md#step-2-save-and-retrieve-a-single-state" >}}) for instructions on configuring state store components - [State management building block]({{< ref state-management >}}) diff --git a/daprdocs/layouts/partials/hooks/body-end.html b/daprdocs/layouts/partials/hooks/body-end.html index 695cf863809..79cbc117cd9 100644 --- a/daprdocs/layouts/partials/hooks/body-end.html +++ b/daprdocs/layouts/partials/hooks/body-end.html @@ -1,19 +1,13 @@ + + {{ with .Site.Params.algolia_docsearch }} - - + {{ end }} - - \ No newline at end of file diff --git a/daprdocs/layouts/partials/hooks/head-end.html b/daprdocs/layouts/partials/hooks/head-end.html index 804fe38e9ec..03e91efa215 100644 --- a/daprdocs/layouts/partials/hooks/head-end.html +++ b/daprdocs/layouts/partials/hooks/head-end.html @@ -1,3 +1,3 @@ {{ with .Site.Params.algolia_docsearch }} - + {{ end }} \ No newline at end of file diff --git a/daprdocs/layouts/partials/search-input.html b/daprdocs/layouts/partials/search-input.html new file mode 100644 index 00000000000..22e90024773 --- /dev/null +++ b/daprdocs/layouts/partials/search-input.html @@ -0,0 +1,30 @@ +{{ if .Site.Params.gcs_engine_id -}} + +{{ else if .Site.Params.algolia_docsearch -}} +
+{{ else if .Site.Params.offlineSearch -}} +{{ $offlineSearchIndex := resources.Get "json/offline-search-index.json" | resources.ExecuteAsTemplate "offline-search-index.json" . -}} +{{ if hugo.IsProduction -}} +{{/* Use `md5` as finger print hash function to shorten file name to avoid `file name too long` error. */ -}} +{{ $offlineSearchIndex = $offlineSearchIndex | fingerprint "md5" -}} +{{ end -}} +{{ $offlineSearchLink := $offlineSearchIndex.RelPermalink -}} + + +{{ end -}} diff --git a/daprdocs/static/js/copy-code-button.js b/daprdocs/static/js/copy-code-button.js index 579d2514824..ca5d0e26e90 100644 --- a/daprdocs/static/js/copy-code-button.js +++ b/daprdocs/static/js/copy-code-button.js @@ -1,49 +1,35 @@ -function addCopyButtons(clipboard) { - document.querySelectorAll('pre > code').forEach(function(codeBlock) { - var button = document.createElement('button'); - button.className = 'copy-code-button'; - button.type = 'button'; - button.innerText = 'Copy'; +const highlightClass = document.querySelectorAll('.highlight'); - button.addEventListener('click', function() { - clipboard.writeText(codeBlock.textContent).then( - function() { - button.blur(); +highlightClass.forEach(element => { + const copyIcon = document.createElement('i'); + copyIcon.classList.add('fas', 'fa-copy', 'copy-icon'); + copyIcon.style.color = 'white'; + copyIcon.style.display = 'none'; + element.appendChild(copyIcon); - button.innerText = 'Copied!'; - setTimeout(function() { - button.innerText = 'Copy'; - }, 2000); - }, - function(error) { - button.innerText = 'Error'; - console.error(error); - } - ); - }); + element.addEventListener('mouseenter', () => { + copyIcon.style.display = 'inline'; + }); - var pre = codeBlock.parentNode; - if (pre.parentNode.classList.contains('highlight')) { - var highlight = pre.parentNode; - highlight.parentNode.insertBefore(button, highlight); - } else { - pre.parentNode.insertBefore(button, pre); - } - }); -} + element.addEventListener('mouseleave', () => { + copyIcon.style.display = 'none'; + copyIcon.classList.replace('fa-check', 'fa-copy'); + }); -if (navigator && navigator.clipboard) { - addCopyButtons(navigator.clipboard); -} else { - var script = document.createElement('script'); - script.src = - 'https://cdnjs.cloudflare.com/ajax/libs/clipboard-polyfill/2.7.0/clipboard-polyfill.promise.js'; - script.integrity = 'sha256-waClS2re9NUbXRsryKoof+F9qc1gjjIhc2eT7ZbIv94='; - script.crossOrigin = 'anonymous'; + copyIcon.addEventListener('click', async () => { + const selection = window.getSelection(); + const range = document.createRange(); + range.selectNodeContents(element); + selection.removeAllRanges(); + selection.addRange(range); - script.onload = function() { - addCopyButtons(clipboard); - }; - - document.body.appendChild(script); -} + try { + await navigator.clipboard.writeText(selection.toString()); + console.log('Text copied to clipboard'); + copyIcon.classList.replace('fa-copy', 'fa-check'); + selection.removeAllRanges(); + } catch (error) { + console.error('Failed to copy: ', error); + } + }); +});