diff --git a/CHANGELOG.en.md b/CHANGELOG.en.md
index 51419c06b..20609473a 100644
--- a/CHANGELOG.en.md
+++ b/CHANGELOG.en.md
@@ -5,6 +5,12 @@
# Changelog
+## v5.0.0 - tbd
+
+- **Unified Search integration**
+
+ You can now use the Unified Search to search forms based on the title and the description.
+
## v4.3.0 - 2024-10-04
- **New question type: Files**
diff --git a/css/forms.css b/css/forms.css
index 9d66d1633..62b659990 100644
--- a/css/forms.css
+++ b/css/forms.css
@@ -9,3 +9,14 @@
html {
scroll-padding-top: calc(var(--header-height) + 60px);
}
+
+.icon-forms {
+ background-image: url(../img/forms-dark.svg);
+ filter: var(--background-invert-if-dark);
+}
+
+.icon-forms-white,
+.icon-forms.icon-white {
+ background-image: url(../img/forms.svg);
+ filter: var(--background-invert-if-dark);
+}
diff --git a/l10n/sv.js b/l10n/sv.js
index 7245fe36e..077c7079c 100644
--- a/l10n/sv.js
+++ b/l10n/sv.js
@@ -4,103 +4,167 @@ OC.L10N.register(
"Forms" : "Formulär",
"{user} has shared the form {formTitle} with you" : "{user} har delat formuläret {formTitle} med dig",
"{user} has shared the form {formTitle} with group {group}" : "{user} har delat formuläret {formTitle} med gruppen {group}",
+ "{user} has shared the form {formTitle} with team {circle}" : "{user} har delat formuläret {formTitle} med teamet {circle}",
+ "Your form {formTitle} was answered by {user}" : "Ditt formulär {formTitle} besvarades av {user}",
"Anonymous user" : "Anonym användare",
"A form has been shared with you" : "Ett formulär har delats med dig",
+ "Someone answered a shared form" : "Någon besvarade ett delat formulär",
"Someone answered a form" : "Någon besvarade ett formulär",
+ "Nextcloud Forms" : "Nextcloud formulär",
+ "Select form" : "Välj formulär",
"Timestamp of data load" : "Tidstämpel för datainläsning",
"No" : "Nej",
"Yes" : "Ja",
"Question" : "Fråga",
+ "Answer" : "Svar",
+ "Count" : "Antal",
"Copy" : "Kopiera",
- "Anonymous response" : "Anonymt svar",
+ "Anonymous response" : "Anonymt svar",
"Shared by %s" : "Delad av %s",
- "Forms including questions and submissions" : "Formulär inklusive frågor och inlämningar",
+ "Forms including questions and submissions" : "Formulär inklusive frågor och svar",
"responses" : "svar",
"User ID" : "Användar-ID",
"User display name" : "Användarens visningsnamn",
"Timestamp" : "Tidsstämpel",
"📝 Simple surveys and questionnaires, self-hosted" : "📝 enkla undersökningar och formulär, egenhostade",
+ "**Simple surveys and questionnaires, self-hosted!**\n\n- **📝 Simple design:** No mass of options, only the essentials. Works well on mobile of course.\n- **📊 View & export results:** Results are visualized and can also be exported as CSV in the same format used by Google Forms.\n- **🔒 Data under your control!** Unlike in Google Forms, Typeform, Doodle and others, the survey info and responses are kept private on your instance.\n- **🧑💻 Connect to your software:** Easily integrate Forms into your service with our full-fledged [REST-API](https://github.com/nextcloud/forms/blob/main/docs/API.md).\n- **🙋 Get involved!** We have lots of stuff planned like more question types, collaboration on forms, [and much more](https://github.com/nextcloud/forms/milestones)!" : "**Enkla undersökningar och frågeformulär, självhostade!**\n\n- **📝 Enkel design:** Inte en massa alternativ, bara det väsentliga. Fungerar naturligtvis bra på mobilen.\n- **📊 Visa & exportera resultat:** Resultat visualiseras och kan även exporteras som CSV i samma format som används av Google Forms.\n- **🔒 Data under din kontroll:** Till skillnad från Google Forms, Typeform, Doodle och andra, hålls formulärdata och svar privata på din instans.\n- **🧑💻 Anslut till din mjukvara:** Integrera enkelt Formulär i din egna tjänst med vårt heltäckande [REST-API](https://github.com/nextcloud/forms/blob/main/docs/API.md)\n- **🙋 Engagera dig!** Vi planerar massor av saker, t.ex. fler frågetyper, samarbete på formulär, [och mycket mer](https://github.com/nextcloud/forms/milestones)!",
+ "Forms navigation" : "Formulärnavigation",
"New form" : "Nytt formulär",
- "Shared with you" : "Delad med dig",
- "Loading forms …" : "Laddar formulär ...",
+ "Your forms" : "Dina formulär",
+ "Shared with you" : "Delas med dig",
+ "Archived forms" : "Arkiverade formulär",
+ "Loading forms …" : "Laddar formulär …",
"No forms created yet" : "Inga formulär ännu",
"Create a form" : "Skapa ett formulär",
"Select a form or create a new one" : "Välj ett formulär eller skapa ett nytt",
"Please select a form" : "Välj ett formulär",
"Create new form" : "Skapa nytt formulär",
"An error occurred while loading the forms list" : "Kunde inte ladda listan med formulär",
- "Form not found" : "Hittade inte formuläret",
+ "Form not found" : "Formuläret hittades inte",
"Unable to create a new form" : "Kunde inte skapa ett nytt formulär",
- "Unable to copy form" : "Går ej att kopiera formulär",
+ "Unable to copy form" : "Kunde inte kopiera formulär",
"This form does not exist" : "Detta formulär finns inte",
"Form expired" : "Formuläret har upphört att gälla",
"This form has expired and is no longer taking answers" : "Detta formulär har upphört att gälla och tar inte längre emot svar",
- "Form creation" : "Skapa formulär",
+ "Form creation" : "Formulärskapande",
"Restrict form creation to selected groups" : "Begränsa skapande av formulär till valda grupper",
"Select groups" : "Välj grupper",
- "Form sharing" : "Dela formulär",
+ "Form sharing" : "Formulärdelning",
"Allow sharing by link" : "Tillåt delning via länk",
"Allow sharing to all logged in accounts" : "Tillåt delning till alla inloggade konton",
- "Error while saving configuration" : "Fel när konfigurationen skulle sparas",
+ "Allow showing form to all logged in accounts on sidebar" : "Tillåt visning i sidofältet för alla inloggade konton",
+ "Error while saving configuration" : "Fel vid sparande av konfiguration",
"Error while reloading config" : "Fel vid omladdning av konfiguration",
"Form actions" : "Formuläråtgärder",
"Edit form" : "Redigera formulär",
"Share form" : "Dela formuläret",
"Results" : "Resultat",
"Copy form" : "Kopiera formulär",
+ "Unarchive form" : "Avarkivera formulär",
+ "Archive form" : "Arkivera formulär",
"Delete form" : "Ta bort formuläret",
"Are you sure you want to delete {title}?" : "Vill du ta bort {title}?",
+ "Form closed" : "Formulär stängt",
"Expired {relativeDate}" : "Upphörde {relativeDate}",
"Expires {relativeDate}" : "Upphör {relativeDate}",
+ "Error changing archived state of form" : "Fel vid ändring av arkivstatus för formulär",
"Error while deleting {title}" : "Kunde inte ta bort {title}",
+ "Add multiple options" : "Lägg till flera alternativ",
+ "Add multiple options (one per line)" : "Lägg till flera alternativ (ett per rad)",
"Options" : "Alternativ",
"Cancel" : "Avbryt",
+ "Add options" : "Lägg till alternativ",
+ "Options should be separated by new line!" : "Alternativ måste separeras med nya rader!",
+ "QR code representation of {text}" : "QR-kod för {text}",
"Answer number {index}" : "Svar {index}",
"Delete answer" : "Ta bort svaret",
"Error while saving the answer" : "Kunde inte spara svaret",
"Question number {index}" : "Fråga {index}",
+ "Move question up" : "Flytta upp fråga",
+ "Move question down" : "Flytta ned fråga",
"Title of question number {index}" : "Titel för fråga {index}",
"Required" : "Krävs",
- "Delete question" : "Ta bort frågan",
+ "Technical name of the question" : "Tekniskt namn för frågan",
+ "Technical name" : "Tekniskt namn",
+ "Copy question" : "Kopiera fråga",
+ "Delete question" : "Ta bort fråga",
"Description (formatting using Markdown is supported)" : "Beskrivning (formatering med Markdown stöds)",
"This question needs a title!" : "Frågan behöver en rubrik!",
"Shuffle options" : "Blanda alternativ",
"Add a new answer" : "Lägg till ett nytt svar",
- "There was an issue deleting this option" : "Problem uppstod vid borttagande av detta alternativ",
+ "There was an issue deleting this option" : "Fel vid borttagande av detta alternativ",
+ "Allow only specific file types" : "Tillåt endast specifika filtyper",
+ "Custom file extensions" : "Anpassade filändelser",
+ "Maximum number of files" : "Maximalt antal filer",
"Maximum file size" : "Maximal filstorlek",
"Delete" : "Radera",
- "Uploading …" : "Laddar upp ...",
+ "Uploading …" : "Laddar upp …",
+ "Add new file as answer" : "Ladda upp ny fil som svar",
+ "Allowed file types: {fileTypes}." : "Tillåtna filtyper: {fileTypes}.",
+ "All file types are allowed." : "Alla filtyper är tillåtna.",
+ "The file {fileName} is too large. The maximum file size is {maxFileSize}." : "Filen {fileName} är för stor. Maximala filstorleken är {maxFileSize}.",
+ "There was an error during submitting the file: {message}." : "Ett fel uppstod vid uppladdning av filen: {message}.",
"A long answer for the question “{text}”" : "Ett långt svar till frågan \"{text}\"",
+ "Add \"other\"" : "Lägg till \"annat\"",
+ "Require a minimum of options to be checked" : "Kräv markering av ett minsta antal alternativ ",
+ "Minimum options to be checked" : "Minsta antalet alternativ som behöver väljas",
+ "Require a maximum of options to be checked" : "Kräv markering av ett maximalt antal alternativ",
+ "Maximum options to be checked" : "Maximala antalet alternativ som får väljas",
+ "Other:" : "Annat:",
"Other" : "Annat",
+ "Upper options limit must be greater than the lower limit" : "Max antal måste vara större än minsta antalet",
+ "Lower options limit must be smaller than the upper limit" : "Minsta antalet måste vara färre än max antalet",
"A short answer for the question “{text}”" : "Ett kort svar till frågan \"{text}\"",
+ "Input types (currently: {type})" : "Svarstyper (just nu: {type})",
+ "Regular expression for input validation" : "Regular expression för svarsvalidering",
+ "Invalid regular expression" : "Ogiltigt regular expression",
"No response" : "Inget svar",
- "Delete this response" : "Ta bort svaret",
+ "Delete this response" : "Ta bort detta svar",
"Store responses anonymously" : "Lagra svar anonymt",
"Allow multiple responses per person" : "Tillåt flera svar per person",
"Set expiration date" : "Välj utgångsdatum",
"Show expiration date on form" : "Visa utgångsdatum på formuläret",
- "This can not be controlled, if the form has a public link or stores responses anonymously." : "Detta kan inte kontrolleras om formuläret har en offentlig länk eller lagrar svar anonymt.",
+ "Close form" : "Stäng formulär",
+ "Closed forms do not accept new submissions." : "Stängda formulär tar inte emot nya svar.",
+ "Archived forms do not accept new submissions and can not be modified." : "Arkiverade formulär tar inte emot nya svar och kan inte redigeras.",
+ "Custom submission message" : "Anpassat meddelande vid inskickning",
+ "Message to show after a user submitted the form (formatting using Markdown is supported)" : "Meddelande som visas när användare har skickat in sina svar (formatering med Markdown stöds)",
+ "Message to show after a user submitted the form. Please note that the message will not be translated!" : "Meddelande som visas när användare har skickat in sina svar. Obs: meddelandet kommer inte att översättas!",
+ "This can not be controlled, if the form has a public link or stores responses anonymously." : "Detta kan inte ställas in om formuläret har en offentlig länk eller lagrar svar anonymt.",
"Expired on {date}" : "Slutade gälla {date}",
"Expires on {date}" : "Slutar gälla {date}",
+ "Search for user, group or team …" : "Sök efter användare, grupper eller team …",
"Permissions" : "Behörigheter",
"View responses" : "Visa svar",
+ "Delete responses" : "Ta bort svar",
"Group" : "Grupp",
"Team" : "Team",
"Share link" : "Delningslänk",
"Add link" : "Lägg till länk",
+ "Embeddable link" : "Inbäddningsbar länk",
"Copy to clipboard" : "Kopiera till urklipp",
"Show QR code" : "Visa QR-kod",
"Copy embedding code" : "Kopiera inbäddningskod",
+ "Convert to embeddable link" : "Konvertera till inbäddningsbar länk",
"Remove link" : "Ta bort länk",
+ "Share {formTitle}" : "Dela {formTitle}",
"Internal link" : "Intern länk",
"Only works for logged in accounts with access rights" : "Fungerar endast för inloggade konton med åtkomsträttigheter",
- "Permit access to all logged in accounts" : "Tillåt åtkomst till alla inloggade konton",
+ "Permit access to all logged in accounts" : "Tillåt åtkomst för alla inloggade konton",
"Show to all accounts on sidebar" : "Visa för alla konton på sidofältet",
- "There was an error while adding the share" : "Det uppstod ett fel när delningen lades till",
- "There was an error while adding the link" : "Det uppstod ett fel när länken lades till",
- "There was an error while updating the share" : "Det uppstod ett fel när delingen skulle uppdateras",
- "There was an error while removing the share" : "Det uppstod ett fel när delningen skulle tas bort",
+ "There was an error while adding the share" : "Ett fel uppstod vid tilläggning av delningen",
+ "There was an error while adding the link" : "Ett fel uppstod vid tilläggning av länken",
+ "There was an error while updating the share" : "Ett fel uppstod vid uppdatering av delningen",
+ "There was an error while removing the share" : "Ett fel uppstod vid borttagning av delningen",
"Transfer ownership" : "Överför ägarskap",
+ "You're going to transfer the ownership of {name} to another account. Please select the account to which you want to transfer ownership." : "Du kommer att överföra ägarskap av {name} till ett annat konto. Välj vilket konto ägarskapet skall överföras till.",
+ "Search for a user" : "Sök efter användare",
+ "Type {text} to confirm." : "Fyll i {text} för att bekräfta.",
+ "Confirmation text" : "Bekräftelsetext",
+ "This can not be undone." : "Detta kan inte ångras",
+ "I understand, transfer this form" : "Jag förstår, överför formuläret",
+ "This form is now owned by" : "Detta formulär ägs nu av",
+ "An error occurred while transfering ownership" : "Ett fel uppstod vid överföring av ägarskap",
"View mode" : "Visningsläge",
"Share" : "Dela",
"Toggle settings" : "Växla inställningar",
@@ -108,7 +172,10 @@ OC.L10N.register(
"View" : "Visa",
"Edit" : "Ändra",
"Show results" : "Visa resultat",
+ "Create form" : "Skapa formulär",
"Loading {title} …" : "Läser in {title} …",
+ "Form is archived" : "Formulär arkiverat",
+ "Form '{title}' is archived and cannot be modified." : "Formulär '{title}' är arkiverat och kan inte redigeras",
"Form title" : "Rubrik",
"Description" : "Beskrivning",
"Add a question" : "Lägg till en fråga",
@@ -118,65 +185,96 @@ OC.L10N.register(
"Expired {relativeDate}." : "Upphörde {relativeDate}.",
"Expires {relativeDate}." : "Upphör {relativeDate}.",
"There was an error while adding the new question" : "Ett fel uppstod vid sparande av den nya frågan",
- "There was an error while removing the question" : "Ett fel uppstod vid borttagande av frågan",
+ "There was an error while removing the question" : "Ett fel uppstod vid borttagning av frågan",
"Error while saving form" : "Kunde inte spara formuläret",
- "Loading responses …" : "Hämtar svar ...",
+ "Linked file not available" : "Kopplad fil inte tillgänglig",
+ "Linked file is not available, would you like to link a new file?" : "Den kopplade filen är inte tillgänglig, vill du koppla en ny fil?",
+ "Loading responses …" : "Hämtar svar …",
"No responses yet" : "Inga svar ännu",
"Results of submitted forms will show up here" : "Resultat från inskickade formulär visas här",
+ "Create spreadsheet" : "Skapa kalkylblad",
+ "Open spreadsheet" : "Öppna kalkylblad",
"{amount} responses" : "{amount} svar",
+ "Re-export spreadsheet" : "Exportera kalkylblad igen",
+ "Unlink spreadsheet" : "Bryt koppling med kalkylblad",
+ "Save copy to Files" : "Spara kopia till Filer",
"Download" : "Ladda ner",
"Delete all responses" : "Ta bort alla svar",
+ "Delete submissions" : "Ta bort svar",
"Are you sure you want to delete all responses of {title}?" : "Är du säker på att du vill ta bort alla svar till {title}?",
"Summary" : "Sammanfattning",
"Responses" : "Svar",
"There was an error while loading the results" : "Ett fel uppstod vid hämtning av resultaten",
+ "File {file} successfully linked" : "Fil {file} har kopplats",
+ "There was an error while linking the file" : "Ett fel uppstod vid koppling av filen",
"Export successful to {file}" : "Export till {file} lyckades",
+ "There was an error while exporting to Files" : "Ett fel uppstod vid export till Filer",
+ "File is not linked" : "Ingen fil är kopplad",
"There was an error, while exporting to Files" : "Det inträffade ett fel, vid export till Filer",
- "There was an error while removing this response" : "Ett fel uppstod vid borttagande av detta svar",
- "There was an error while removing responses" : "Ett fel uppstod vid borttagande av svar",
+ "Submission deleted" : "Svar borttaget",
+ "There was an error while removing this response" : "Ett fel uppstod vid borttagning av detta svar",
+ "There was an error while removing responses" : "Ett fel uppstod vid borttagning av svar",
+ "Choose spreadsheet location" : "Välj plats för kalkylblad",
+ "Create XLSX" : "Skapa XLSX",
+ "Create CSV" : "Skapa CSV",
+ "Create ODS" : "Skapa ODS",
+ "Select {file}" : "Välj {file}",
"Form settings" : "Formulärinställningar",
"Sharing" : "Delning",
"Settings" : "Inställningar",
"Submit form" : "Skicka in formulär",
- "Submitting form …" : "Skickar formulär ...",
+ "Submitting form …" : "Skickar formulär …",
"Thank you for completing the form!" : "Tack för att du fyllde i formuläret!",
+ "This form was closed and is no longer taking answers" : "Formuläret har stängts och tar inte längre emot svar",
+ "Clear form" : "Rensa formulär",
"Submit" : "Skicka",
+ "Confirm submit" : "Bekräfta",
+ "Are you sure you want to submit an empty form?" : "Är du säker att du vill skicka in ett blankt formulär?",
+ "Leave form" : "Lämna formulär",
"You have unsaved changes! Do you still want to leave?" : "Du har osparade förändringar! Vill du fortfarande lämna?",
+ "Do you want to clear all answers?" : "Vill du rensa alla svar?",
+ "The form has changed since your last visit. Do you want to clear all answers?" : "Formuläret har ändrats sedan ditt senaste besök. Vill du rensa alla svar?",
"Abort" : "Avbryt",
+ "Leave" : "Lämna",
"Clear" : "Rensa",
+ "Some answers are not valid" : "Vissa svar är ogiltiga",
+ "There was an error submitting the form: {message}" : "Ett fel uppstod vid inskickning av formuläret: {message}",
"Error while saving question" : "Ett fel uppstod vid sparande av frågan",
- "Form link copied" : "Formulärlänken kopierad",
- "Cannot copy, please copy the link manually" : "Kan inte kopiera, länken måste kopieras manuellt",
+ "Error while saving question options" : "Ett fel uppstod vid sparande av frågealternativ",
+ "Form link copied" : "Länk till formuläret kopierad",
+ "Cannot copy, please copy the link manually" : "Kan inte kopiera, vänligen kopiera länken manuellt",
"No recommendations. Start typing." : "Inga rekommendationer. Börja skriva.",
"No elements found." : "Inga element hittades.",
"Checkboxes" : "Kryssfrågor",
"Checkbox question title" : "Rubrik till kryssfråga",
+ "People can submit a different answer" : "Användare kan lämna ett annat svar",
"Enter your answer" : "Ange ditt svar",
- "This question needs a title and at least one answer!" : "Denna fråga behöver rubrik och minst ett svar!",
+ "This question needs a title and at least one answer!" : "Frågan behöver en rubrik och minst ett alternativ!",
"Radio buttons" : "Radioknappar",
"Radio buttons question title" : "Rubrik till radioknappsfråga",
"Dropdown" : "Rullgardinsfråga",
"Dropdown question title" : "Rubrik till rullgardinsfråga",
- "People can pick one option" : "Användaren kan välja ett alternativ",
+ "People can pick one option" : "Användare kan välja ett alternativ",
"Pick an option" : "Välj ett alternativ",
"File" : "Fil",
+ "File question title" : "Rubrik till filfråga",
"Short answer" : "Kortsvarsfråga",
- "Short answer question title" : "Titel för kortsvarsfråga",
- "People can enter a short answer" : "Användaren kan ange ett kort svar",
+ "Short answer question title" : "Rubrik för kortsvarsfråga",
+ "People can enter a short answer" : "Användare kan ange ett kort svar",
"Long text" : "Lång text",
"Long text question title" : "Rubrik till fråga med lång text",
- "People can enter a long text" : "Användaren kan ange en lång text",
+ "People can enter a long text" : "Användare kan ange en lång text",
"Date" : "Datum",
"Date question title" : "Rubrik till datumfråga",
- "People can pick a date" : "Personer kan välja ett datum",
+ "People can pick a date" : "Användare kan välja ett datum",
"Pick a date" : "Välj ett datum",
"Datetime" : "Datum Tid",
- "Datetime question title" : "Rubrik till datum/tid - fråga",
- "People can pick a date and time" : "Personer kan välja datum och tid",
+ "Datetime question title" : "Rubrik till datum/tid-fråga",
+ "People can pick a date and time" : "Användare kan välja datum och tid",
"Pick a date and time" : "Välj datum och tid",
"Time" : "Tid",
"Time question title" : "Rubrik till tidsfråga",
- "People can pick a time" : "Personer kan välja en tid",
+ "People can pick a time" : "Användare kan välja en tid",
"Pick a time" : "Välj en tidpunkt",
"Image" : "Bild",
"Document" : "Dokument",
@@ -184,7 +282,18 @@ OC.L10N.register(
"Spreadsheet" : "Kalkylblad",
"Text" : "Text",
"Phone number" : "Telefonnummer",
+ "The input is not a valid phone number" : "Svaret är inte ett giltigt telefonnummer",
+ "People can enter a telephone number" : "Användare kan ange ett telefonnummer",
+ "Enter a telephone number" : "Fyll i ett telefonnummer",
"Email address" : "E-postadress",
- "Number" : "Nummer"
+ "The input is not a valid email address" : "Svaret är inte en giltig e-postadress",
+ "People can enter an email address" : "Användare kan ange en e-postadress",
+ "Enter an email address" : "Fyll i en e-postadress",
+ "Number" : "Nummer",
+ "The input is not a valid number" : "Svaret är inte ett giltigt tal",
+ "People can enter a number" : "Användare kan ange ett nummer",
+ "Enter a number" : "Fyll i ett tal",
+ "Custom regular expression" : "Anpassa regular expression",
+ "The input does not match the required pattern" : "Svaret passar inte det förväntade mönstret"
},
"nplurals=2; plural=(n != 1);");
diff --git a/l10n/sv.json b/l10n/sv.json
index bfaf9ce10..9e0ab85e4 100644
--- a/l10n/sv.json
+++ b/l10n/sv.json
@@ -2,103 +2,167 @@
"Forms" : "Formulär",
"{user} has shared the form {formTitle} with you" : "{user} har delat formuläret {formTitle} med dig",
"{user} has shared the form {formTitle} with group {group}" : "{user} har delat formuläret {formTitle} med gruppen {group}",
+ "{user} has shared the form {formTitle} with team {circle}" : "{user} har delat formuläret {formTitle} med teamet {circle}",
+ "Your form {formTitle} was answered by {user}" : "Ditt formulär {formTitle} besvarades av {user}",
"Anonymous user" : "Anonym användare",
"A form has been shared with you" : "Ett formulär har delats med dig",
+ "Someone answered a shared form" : "Någon besvarade ett delat formulär",
"Someone answered a form" : "Någon besvarade ett formulär",
+ "Nextcloud Forms" : "Nextcloud formulär",
+ "Select form" : "Välj formulär",
"Timestamp of data load" : "Tidstämpel för datainläsning",
"No" : "Nej",
"Yes" : "Ja",
"Question" : "Fråga",
+ "Answer" : "Svar",
+ "Count" : "Antal",
"Copy" : "Kopiera",
- "Anonymous response" : "Anonymt svar",
+ "Anonymous response" : "Anonymt svar",
"Shared by %s" : "Delad av %s",
- "Forms including questions and submissions" : "Formulär inklusive frågor och inlämningar",
+ "Forms including questions and submissions" : "Formulär inklusive frågor och svar",
"responses" : "svar",
"User ID" : "Användar-ID",
"User display name" : "Användarens visningsnamn",
"Timestamp" : "Tidsstämpel",
"📝 Simple surveys and questionnaires, self-hosted" : "📝 enkla undersökningar och formulär, egenhostade",
+ "**Simple surveys and questionnaires, self-hosted!**\n\n- **📝 Simple design:** No mass of options, only the essentials. Works well on mobile of course.\n- **📊 View & export results:** Results are visualized and can also be exported as CSV in the same format used by Google Forms.\n- **🔒 Data under your control!** Unlike in Google Forms, Typeform, Doodle and others, the survey info and responses are kept private on your instance.\n- **🧑💻 Connect to your software:** Easily integrate Forms into your service with our full-fledged [REST-API](https://github.com/nextcloud/forms/blob/main/docs/API.md).\n- **🙋 Get involved!** We have lots of stuff planned like more question types, collaboration on forms, [and much more](https://github.com/nextcloud/forms/milestones)!" : "**Enkla undersökningar och frågeformulär, självhostade!**\n\n- **📝 Enkel design:** Inte en massa alternativ, bara det väsentliga. Fungerar naturligtvis bra på mobilen.\n- **📊 Visa & exportera resultat:** Resultat visualiseras och kan även exporteras som CSV i samma format som används av Google Forms.\n- **🔒 Data under din kontroll:** Till skillnad från Google Forms, Typeform, Doodle och andra, hålls formulärdata och svar privata på din instans.\n- **🧑💻 Anslut till din mjukvara:** Integrera enkelt Formulär i din egna tjänst med vårt heltäckande [REST-API](https://github.com/nextcloud/forms/blob/main/docs/API.md)\n- **🙋 Engagera dig!** Vi planerar massor av saker, t.ex. fler frågetyper, samarbete på formulär, [och mycket mer](https://github.com/nextcloud/forms/milestones)!",
+ "Forms navigation" : "Formulärnavigation",
"New form" : "Nytt formulär",
- "Shared with you" : "Delad med dig",
- "Loading forms …" : "Laddar formulär ...",
+ "Your forms" : "Dina formulär",
+ "Shared with you" : "Delas med dig",
+ "Archived forms" : "Arkiverade formulär",
+ "Loading forms …" : "Laddar formulär …",
"No forms created yet" : "Inga formulär ännu",
"Create a form" : "Skapa ett formulär",
"Select a form or create a new one" : "Välj ett formulär eller skapa ett nytt",
"Please select a form" : "Välj ett formulär",
"Create new form" : "Skapa nytt formulär",
"An error occurred while loading the forms list" : "Kunde inte ladda listan med formulär",
- "Form not found" : "Hittade inte formuläret",
+ "Form not found" : "Formuläret hittades inte",
"Unable to create a new form" : "Kunde inte skapa ett nytt formulär",
- "Unable to copy form" : "Går ej att kopiera formulär",
+ "Unable to copy form" : "Kunde inte kopiera formulär",
"This form does not exist" : "Detta formulär finns inte",
"Form expired" : "Formuläret har upphört att gälla",
"This form has expired and is no longer taking answers" : "Detta formulär har upphört att gälla och tar inte längre emot svar",
- "Form creation" : "Skapa formulär",
+ "Form creation" : "Formulärskapande",
"Restrict form creation to selected groups" : "Begränsa skapande av formulär till valda grupper",
"Select groups" : "Välj grupper",
- "Form sharing" : "Dela formulär",
+ "Form sharing" : "Formulärdelning",
"Allow sharing by link" : "Tillåt delning via länk",
"Allow sharing to all logged in accounts" : "Tillåt delning till alla inloggade konton",
- "Error while saving configuration" : "Fel när konfigurationen skulle sparas",
+ "Allow showing form to all logged in accounts on sidebar" : "Tillåt visning i sidofältet för alla inloggade konton",
+ "Error while saving configuration" : "Fel vid sparande av konfiguration",
"Error while reloading config" : "Fel vid omladdning av konfiguration",
"Form actions" : "Formuläråtgärder",
"Edit form" : "Redigera formulär",
"Share form" : "Dela formuläret",
"Results" : "Resultat",
"Copy form" : "Kopiera formulär",
+ "Unarchive form" : "Avarkivera formulär",
+ "Archive form" : "Arkivera formulär",
"Delete form" : "Ta bort formuläret",
"Are you sure you want to delete {title}?" : "Vill du ta bort {title}?",
+ "Form closed" : "Formulär stängt",
"Expired {relativeDate}" : "Upphörde {relativeDate}",
"Expires {relativeDate}" : "Upphör {relativeDate}",
+ "Error changing archived state of form" : "Fel vid ändring av arkivstatus för formulär",
"Error while deleting {title}" : "Kunde inte ta bort {title}",
+ "Add multiple options" : "Lägg till flera alternativ",
+ "Add multiple options (one per line)" : "Lägg till flera alternativ (ett per rad)",
"Options" : "Alternativ",
"Cancel" : "Avbryt",
+ "Add options" : "Lägg till alternativ",
+ "Options should be separated by new line!" : "Alternativ måste separeras med nya rader!",
+ "QR code representation of {text}" : "QR-kod för {text}",
"Answer number {index}" : "Svar {index}",
"Delete answer" : "Ta bort svaret",
"Error while saving the answer" : "Kunde inte spara svaret",
"Question number {index}" : "Fråga {index}",
+ "Move question up" : "Flytta upp fråga",
+ "Move question down" : "Flytta ned fråga",
"Title of question number {index}" : "Titel för fråga {index}",
"Required" : "Krävs",
- "Delete question" : "Ta bort frågan",
+ "Technical name of the question" : "Tekniskt namn för frågan",
+ "Technical name" : "Tekniskt namn",
+ "Copy question" : "Kopiera fråga",
+ "Delete question" : "Ta bort fråga",
"Description (formatting using Markdown is supported)" : "Beskrivning (formatering med Markdown stöds)",
"This question needs a title!" : "Frågan behöver en rubrik!",
"Shuffle options" : "Blanda alternativ",
"Add a new answer" : "Lägg till ett nytt svar",
- "There was an issue deleting this option" : "Problem uppstod vid borttagande av detta alternativ",
+ "There was an issue deleting this option" : "Fel vid borttagande av detta alternativ",
+ "Allow only specific file types" : "Tillåt endast specifika filtyper",
+ "Custom file extensions" : "Anpassade filändelser",
+ "Maximum number of files" : "Maximalt antal filer",
"Maximum file size" : "Maximal filstorlek",
"Delete" : "Radera",
- "Uploading …" : "Laddar upp ...",
+ "Uploading …" : "Laddar upp …",
+ "Add new file as answer" : "Ladda upp ny fil som svar",
+ "Allowed file types: {fileTypes}." : "Tillåtna filtyper: {fileTypes}.",
+ "All file types are allowed." : "Alla filtyper är tillåtna.",
+ "The file {fileName} is too large. The maximum file size is {maxFileSize}." : "Filen {fileName} är för stor. Maximala filstorleken är {maxFileSize}.",
+ "There was an error during submitting the file: {message}." : "Ett fel uppstod vid uppladdning av filen: {message}.",
"A long answer for the question “{text}”" : "Ett långt svar till frågan \"{text}\"",
+ "Add \"other\"" : "Lägg till \"annat\"",
+ "Require a minimum of options to be checked" : "Kräv markering av ett minsta antal alternativ ",
+ "Minimum options to be checked" : "Minsta antalet alternativ som behöver väljas",
+ "Require a maximum of options to be checked" : "Kräv markering av ett maximalt antal alternativ",
+ "Maximum options to be checked" : "Maximala antalet alternativ som får väljas",
+ "Other:" : "Annat:",
"Other" : "Annat",
+ "Upper options limit must be greater than the lower limit" : "Max antal måste vara större än minsta antalet",
+ "Lower options limit must be smaller than the upper limit" : "Minsta antalet måste vara färre än max antalet",
"A short answer for the question “{text}”" : "Ett kort svar till frågan \"{text}\"",
+ "Input types (currently: {type})" : "Svarstyper (just nu: {type})",
+ "Regular expression for input validation" : "Regular expression för svarsvalidering",
+ "Invalid regular expression" : "Ogiltigt regular expression",
"No response" : "Inget svar",
- "Delete this response" : "Ta bort svaret",
+ "Delete this response" : "Ta bort detta svar",
"Store responses anonymously" : "Lagra svar anonymt",
"Allow multiple responses per person" : "Tillåt flera svar per person",
"Set expiration date" : "Välj utgångsdatum",
"Show expiration date on form" : "Visa utgångsdatum på formuläret",
- "This can not be controlled, if the form has a public link or stores responses anonymously." : "Detta kan inte kontrolleras om formuläret har en offentlig länk eller lagrar svar anonymt.",
+ "Close form" : "Stäng formulär",
+ "Closed forms do not accept new submissions." : "Stängda formulär tar inte emot nya svar.",
+ "Archived forms do not accept new submissions and can not be modified." : "Arkiverade formulär tar inte emot nya svar och kan inte redigeras.",
+ "Custom submission message" : "Anpassat meddelande vid inskickning",
+ "Message to show after a user submitted the form (formatting using Markdown is supported)" : "Meddelande som visas när användare har skickat in sina svar (formatering med Markdown stöds)",
+ "Message to show after a user submitted the form. Please note that the message will not be translated!" : "Meddelande som visas när användare har skickat in sina svar. Obs: meddelandet kommer inte att översättas!",
+ "This can not be controlled, if the form has a public link or stores responses anonymously." : "Detta kan inte ställas in om formuläret har en offentlig länk eller lagrar svar anonymt.",
"Expired on {date}" : "Slutade gälla {date}",
"Expires on {date}" : "Slutar gälla {date}",
+ "Search for user, group or team …" : "Sök efter användare, grupper eller team …",
"Permissions" : "Behörigheter",
"View responses" : "Visa svar",
+ "Delete responses" : "Ta bort svar",
"Group" : "Grupp",
"Team" : "Team",
"Share link" : "Delningslänk",
"Add link" : "Lägg till länk",
+ "Embeddable link" : "Inbäddningsbar länk",
"Copy to clipboard" : "Kopiera till urklipp",
"Show QR code" : "Visa QR-kod",
"Copy embedding code" : "Kopiera inbäddningskod",
+ "Convert to embeddable link" : "Konvertera till inbäddningsbar länk",
"Remove link" : "Ta bort länk",
+ "Share {formTitle}" : "Dela {formTitle}",
"Internal link" : "Intern länk",
"Only works for logged in accounts with access rights" : "Fungerar endast för inloggade konton med åtkomsträttigheter",
- "Permit access to all logged in accounts" : "Tillåt åtkomst till alla inloggade konton",
+ "Permit access to all logged in accounts" : "Tillåt åtkomst för alla inloggade konton",
"Show to all accounts on sidebar" : "Visa för alla konton på sidofältet",
- "There was an error while adding the share" : "Det uppstod ett fel när delningen lades till",
- "There was an error while adding the link" : "Det uppstod ett fel när länken lades till",
- "There was an error while updating the share" : "Det uppstod ett fel när delingen skulle uppdateras",
- "There was an error while removing the share" : "Det uppstod ett fel när delningen skulle tas bort",
+ "There was an error while adding the share" : "Ett fel uppstod vid tilläggning av delningen",
+ "There was an error while adding the link" : "Ett fel uppstod vid tilläggning av länken",
+ "There was an error while updating the share" : "Ett fel uppstod vid uppdatering av delningen",
+ "There was an error while removing the share" : "Ett fel uppstod vid borttagning av delningen",
"Transfer ownership" : "Överför ägarskap",
+ "You're going to transfer the ownership of {name} to another account. Please select the account to which you want to transfer ownership." : "Du kommer att överföra ägarskap av {name} till ett annat konto. Välj vilket konto ägarskapet skall överföras till.",
+ "Search for a user" : "Sök efter användare",
+ "Type {text} to confirm." : "Fyll i {text} för att bekräfta.",
+ "Confirmation text" : "Bekräftelsetext",
+ "This can not be undone." : "Detta kan inte ångras",
+ "I understand, transfer this form" : "Jag förstår, överför formuläret",
+ "This form is now owned by" : "Detta formulär ägs nu av",
+ "An error occurred while transfering ownership" : "Ett fel uppstod vid överföring av ägarskap",
"View mode" : "Visningsläge",
"Share" : "Dela",
"Toggle settings" : "Växla inställningar",
@@ -106,7 +170,10 @@
"View" : "Visa",
"Edit" : "Ändra",
"Show results" : "Visa resultat",
+ "Create form" : "Skapa formulär",
"Loading {title} …" : "Läser in {title} …",
+ "Form is archived" : "Formulär arkiverat",
+ "Form '{title}' is archived and cannot be modified." : "Formulär '{title}' är arkiverat och kan inte redigeras",
"Form title" : "Rubrik",
"Description" : "Beskrivning",
"Add a question" : "Lägg till en fråga",
@@ -116,65 +183,96 @@
"Expired {relativeDate}." : "Upphörde {relativeDate}.",
"Expires {relativeDate}." : "Upphör {relativeDate}.",
"There was an error while adding the new question" : "Ett fel uppstod vid sparande av den nya frågan",
- "There was an error while removing the question" : "Ett fel uppstod vid borttagande av frågan",
+ "There was an error while removing the question" : "Ett fel uppstod vid borttagning av frågan",
"Error while saving form" : "Kunde inte spara formuläret",
- "Loading responses …" : "Hämtar svar ...",
+ "Linked file not available" : "Kopplad fil inte tillgänglig",
+ "Linked file is not available, would you like to link a new file?" : "Den kopplade filen är inte tillgänglig, vill du koppla en ny fil?",
+ "Loading responses …" : "Hämtar svar …",
"No responses yet" : "Inga svar ännu",
"Results of submitted forms will show up here" : "Resultat från inskickade formulär visas här",
+ "Create spreadsheet" : "Skapa kalkylblad",
+ "Open spreadsheet" : "Öppna kalkylblad",
"{amount} responses" : "{amount} svar",
+ "Re-export spreadsheet" : "Exportera kalkylblad igen",
+ "Unlink spreadsheet" : "Bryt koppling med kalkylblad",
+ "Save copy to Files" : "Spara kopia till Filer",
"Download" : "Ladda ner",
"Delete all responses" : "Ta bort alla svar",
+ "Delete submissions" : "Ta bort svar",
"Are you sure you want to delete all responses of {title}?" : "Är du säker på att du vill ta bort alla svar till {title}?",
"Summary" : "Sammanfattning",
"Responses" : "Svar",
"There was an error while loading the results" : "Ett fel uppstod vid hämtning av resultaten",
+ "File {file} successfully linked" : "Fil {file} har kopplats",
+ "There was an error while linking the file" : "Ett fel uppstod vid koppling av filen",
"Export successful to {file}" : "Export till {file} lyckades",
+ "There was an error while exporting to Files" : "Ett fel uppstod vid export till Filer",
+ "File is not linked" : "Ingen fil är kopplad",
"There was an error, while exporting to Files" : "Det inträffade ett fel, vid export till Filer",
- "There was an error while removing this response" : "Ett fel uppstod vid borttagande av detta svar",
- "There was an error while removing responses" : "Ett fel uppstod vid borttagande av svar",
+ "Submission deleted" : "Svar borttaget",
+ "There was an error while removing this response" : "Ett fel uppstod vid borttagning av detta svar",
+ "There was an error while removing responses" : "Ett fel uppstod vid borttagning av svar",
+ "Choose spreadsheet location" : "Välj plats för kalkylblad",
+ "Create XLSX" : "Skapa XLSX",
+ "Create CSV" : "Skapa CSV",
+ "Create ODS" : "Skapa ODS",
+ "Select {file}" : "Välj {file}",
"Form settings" : "Formulärinställningar",
"Sharing" : "Delning",
"Settings" : "Inställningar",
"Submit form" : "Skicka in formulär",
- "Submitting form …" : "Skickar formulär ...",
+ "Submitting form …" : "Skickar formulär …",
"Thank you for completing the form!" : "Tack för att du fyllde i formuläret!",
+ "This form was closed and is no longer taking answers" : "Formuläret har stängts och tar inte längre emot svar",
+ "Clear form" : "Rensa formulär",
"Submit" : "Skicka",
+ "Confirm submit" : "Bekräfta",
+ "Are you sure you want to submit an empty form?" : "Är du säker att du vill skicka in ett blankt formulär?",
+ "Leave form" : "Lämna formulär",
"You have unsaved changes! Do you still want to leave?" : "Du har osparade förändringar! Vill du fortfarande lämna?",
+ "Do you want to clear all answers?" : "Vill du rensa alla svar?",
+ "The form has changed since your last visit. Do you want to clear all answers?" : "Formuläret har ändrats sedan ditt senaste besök. Vill du rensa alla svar?",
"Abort" : "Avbryt",
+ "Leave" : "Lämna",
"Clear" : "Rensa",
+ "Some answers are not valid" : "Vissa svar är ogiltiga",
+ "There was an error submitting the form: {message}" : "Ett fel uppstod vid inskickning av formuläret: {message}",
"Error while saving question" : "Ett fel uppstod vid sparande av frågan",
- "Form link copied" : "Formulärlänken kopierad",
- "Cannot copy, please copy the link manually" : "Kan inte kopiera, länken måste kopieras manuellt",
+ "Error while saving question options" : "Ett fel uppstod vid sparande av frågealternativ",
+ "Form link copied" : "Länk till formuläret kopierad",
+ "Cannot copy, please copy the link manually" : "Kan inte kopiera, vänligen kopiera länken manuellt",
"No recommendations. Start typing." : "Inga rekommendationer. Börja skriva.",
"No elements found." : "Inga element hittades.",
"Checkboxes" : "Kryssfrågor",
"Checkbox question title" : "Rubrik till kryssfråga",
+ "People can submit a different answer" : "Användare kan lämna ett annat svar",
"Enter your answer" : "Ange ditt svar",
- "This question needs a title and at least one answer!" : "Denna fråga behöver rubrik och minst ett svar!",
+ "This question needs a title and at least one answer!" : "Frågan behöver en rubrik och minst ett alternativ!",
"Radio buttons" : "Radioknappar",
"Radio buttons question title" : "Rubrik till radioknappsfråga",
"Dropdown" : "Rullgardinsfråga",
"Dropdown question title" : "Rubrik till rullgardinsfråga",
- "People can pick one option" : "Användaren kan välja ett alternativ",
+ "People can pick one option" : "Användare kan välja ett alternativ",
"Pick an option" : "Välj ett alternativ",
"File" : "Fil",
+ "File question title" : "Rubrik till filfråga",
"Short answer" : "Kortsvarsfråga",
- "Short answer question title" : "Titel för kortsvarsfråga",
- "People can enter a short answer" : "Användaren kan ange ett kort svar",
+ "Short answer question title" : "Rubrik för kortsvarsfråga",
+ "People can enter a short answer" : "Användare kan ange ett kort svar",
"Long text" : "Lång text",
"Long text question title" : "Rubrik till fråga med lång text",
- "People can enter a long text" : "Användaren kan ange en lång text",
+ "People can enter a long text" : "Användare kan ange en lång text",
"Date" : "Datum",
"Date question title" : "Rubrik till datumfråga",
- "People can pick a date" : "Personer kan välja ett datum",
+ "People can pick a date" : "Användare kan välja ett datum",
"Pick a date" : "Välj ett datum",
"Datetime" : "Datum Tid",
- "Datetime question title" : "Rubrik till datum/tid - fråga",
- "People can pick a date and time" : "Personer kan välja datum och tid",
+ "Datetime question title" : "Rubrik till datum/tid-fråga",
+ "People can pick a date and time" : "Användare kan välja datum och tid",
"Pick a date and time" : "Välj datum och tid",
"Time" : "Tid",
"Time question title" : "Rubrik till tidsfråga",
- "People can pick a time" : "Personer kan välja en tid",
+ "People can pick a time" : "Användare kan välja en tid",
"Pick a time" : "Välj en tidpunkt",
"Image" : "Bild",
"Document" : "Dokument",
@@ -182,7 +280,18 @@
"Spreadsheet" : "Kalkylblad",
"Text" : "Text",
"Phone number" : "Telefonnummer",
+ "The input is not a valid phone number" : "Svaret är inte ett giltigt telefonnummer",
+ "People can enter a telephone number" : "Användare kan ange ett telefonnummer",
+ "Enter a telephone number" : "Fyll i ett telefonnummer",
"Email address" : "E-postadress",
- "Number" : "Nummer"
+ "The input is not a valid email address" : "Svaret är inte en giltig e-postadress",
+ "People can enter an email address" : "Användare kan ange en e-postadress",
+ "Enter an email address" : "Fyll i en e-postadress",
+ "Number" : "Nummer",
+ "The input is not a valid number" : "Svaret är inte ett giltigt tal",
+ "People can enter a number" : "Användare kan ange ett nummer",
+ "Enter a number" : "Fyll i ett tal",
+ "Custom regular expression" : "Anpassa regular expression",
+ "The input does not match the required pattern" : "Svaret passar inte det förväntade mönstret"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
\ No newline at end of file
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 1dbf407bc..319e48f3e 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -14,6 +14,7 @@
use OCA\Forms\FormsMigrator;
use OCA\Forms\Listener\AnalyticsDatasourceListener;
use OCA\Forms\Listener\UserDeletedListener;
+use OCA\Forms\Search\SearchProvider;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
@@ -42,6 +43,7 @@ public function register(IRegistrationContext $context): void {
$context->registerCapability(Capabilities::class);
$context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class);
$context->registerEventListener(DatasourceEvent::class, AnalyticsDatasourceListener::class);
+ $context->registerSearchProvider(SearchProvider::class);
$context->registerUserMigrator(FormsMigrator::class);
}
diff --git a/lib/Db/FormMapper.php b/lib/Db/FormMapper.php
index 89a032f3b..8f79496a6 100644
--- a/lib/Db/FormMapper.php
+++ b/lib/Db/FormMapper.php
@@ -97,9 +97,10 @@ public function findByHash(string $hash): Form {
* @param string[] $groups IDs of groups the user is memeber of
* @param string[] $teams IDs of teams the user is memeber of
* @param bool $filterShown Set to false to also include forms shared but not visible on sidebar
+ * @param string $queryTerm optional: The search query for universal search
* @return Form[]
*/
- public function findSharedForms(string $userId, array $groups = [], array $teams = [], bool $filterShown = true): array {
+ public function findSharedForms(string $userId, array $groups = [], array $teams = [], bool $filterShown = true, ?string $queryTerm = null): array {
$qbShares = $this->db->getQueryBuilder();
$qbForms = $this->db->getQueryBuilder();
@@ -107,16 +108,16 @@ public function findSharedForms(string $userId, array $groups = [], array $teams
// share type user and share with current user
$memberships->add(
$qbShares->expr()->andX(
- $qbShares->expr()->eq('shares.share_type', $qbShares->createNamedParameter(IShare::TYPE_USER)),
- $qbShares->expr()->eq('shares.share_with', $qbShares->createNamedParameter($userId, IQueryBuilder::PARAM_STR)),
+ $qbShares->expr()->eq('shares.share_type', $qbShares->createNamedParameter(IShare::TYPE_USER, IQueryBuilder::PARAM_STR, ':share_type_user')),
+ $qbShares->expr()->eq('shares.share_with', $qbShares->createNamedParameter($userId, IQueryBuilder::PARAM_STR, ':share_with_user')),
),
);
// share type group and one of the user groups
if (!empty($groups)) {
$memberships->add(
$qbShares->expr()->andX(
- $qbShares->expr()->eq('shares.share_type', $qbShares->createNamedParameter(IShare::TYPE_GROUP)),
- $qbShares->expr()->in('shares.share_with', $qbShares->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY)),
+ $qbShares->expr()->eq('shares.share_type', $qbShares->createNamedParameter(IShare::TYPE_GROUP, IQueryBuilder::PARAM_STR, ':share_type_group')),
+ $qbShares->expr()->in('shares.share_with', $qbShares->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY, ':share_with_groups')),
),
);
}
@@ -124,19 +125,19 @@ public function findSharedForms(string $userId, array $groups = [], array $teams
if (!empty($teams)) {
$memberships->add(
$qbShares->expr()->andX(
- $qbShares->expr()->eq('shares.share_type', $qbShares->createNamedParameter(IShare::TYPE_CIRCLE)),
- $qbShares->expr()->in('shares.share_with', $qbShares->createNamedParameter($teams, IQueryBuilder::PARAM_STR_ARRAY)),
+ $qbShares->expr()->eq('shares.share_type', $qbShares->createNamedParameter(IShare::TYPE_CIRCLE, IQueryBuilder::PARAM_STR, ':share_type_team')),
+ $qbShares->expr()->in('shares.share_with', $qbShares->createNamedParameter($teams, IQueryBuilder::PARAM_STR_ARRAY, ':share_with_teams')),
),
);
}
- // build expression for publicy shared forms (default only directly shown)
+ // build expression for publicly shared forms (default only directly shown)
if ($filterShown) {
// Only shown
- $access = $qbShares->expr()->in('access_enum', $qbShares->createNamedParameter(Constants::FORM_ACCESS_ARRAY_SHOWN, IQueryBuilder::PARAM_INT_ARRAY));
+ $access = $qbShares->expr()->in('access_enum', $qbShares->createNamedParameter(Constants::FORM_ACCESS_ARRAY_SHOWN, IQueryBuilder::PARAM_INT_ARRAY, ':access_shown'));
} else {
// All
- $access = $qbShares->expr()->neq('access_enum', $qbShares->createNamedParameter(Constants::FORM_ACCESS_NOPUBLICSHARE, IQueryBuilder::PARAM_INT));
+ $access = $qbShares->expr()->neq('access_enum', $qbShares->createNamedParameter(Constants::FORM_ACCESS_NOPUBLICSHARE, IQueryBuilder::PARAM_INT, ':access_nopublicshare'));
}
// Select all DISTINCT IDs of shared forms
@@ -145,7 +146,7 @@ public function findSharedForms(string $userId, array $groups = [], array $teams
->leftJoin('forms', $this->shareMapper->getTableName(), 'shares', $qbShares->expr()->eq('forms.id', 'shares.form_id'))
->where($memberships)
->orWhere($access)
- ->andWhere($qbShares->expr()->neq('forms.owner_id', $qbShares->createNamedParameter($userId, IQueryBuilder::PARAM_STR)));
+ ->andWhere($qbShares->expr()->neq('forms.owner_id', $qbShares->createNamedParameter($userId, IQueryBuilder::PARAM_STR, ':owner_id')));
// Select the whole forms for the DISTINCT shared forms IDs
$qbForms->select('*')
@@ -156,16 +157,30 @@ public function findSharedForms(string $userId, array $groups = [], array $teams
->addOrderBy('last_updated', 'DESC')
->addOrderBy('created', 'DESC');
- // We need to add the parameters from the shared forms IDs select to the final select query
- $qbForms->setParameters($qbShares->getParameters(), $qbShares->getParameterTypes());
+ if ($queryTerm) {
+ $likeParameter = '%' . $this->db->escapeLikeParameter($queryTerm) . '%';
+ $qbForms->andWhere(
+ $qbForms->expr()->orX(
+ $qbForms->expr()->iLike('title', $qbForms->createNamedParameter($likeParameter, IQueryBuilder::PARAM_STR, ':query_term_title')),
+ $qbForms->expr()->iLike('description', $qbForms->createNamedParameter($likeParameter, IQueryBuilder::PARAM_STR, ':query_term_description'))
+ )
+ );
+ }
+
+ // Merge parameters and parameter types from $qbShares and $qbForms
+ $qbFormsParams = array_merge($qbShares->getParameters(), $qbForms->getParameters());
+ $qbFormsParamTypes = array_merge($qbShares->getParameterTypes(), $qbForms->getParameterTypes());
+
+ $qbForms->setParameters($qbFormsParams, $qbFormsParamTypes);
return $this->findEntities($qbForms);
}
/**
+ * @param string $queryTerm optional: The search query for universal search
* @return Form[]
*/
- public function findAllByOwnerId(string $ownerId): array {
+ public function findAllByOwnerId(string $ownerId, ?string $queryTerm = null): array {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
@@ -177,6 +192,16 @@ public function findAllByOwnerId(string $ownerId): array {
->addOrderBy('last_updated', 'DESC')
->addOrderBy('created', 'DESC');
+ if ($queryTerm) {
+ $likeParameter = '%' . $this->db->escapeLikeParameter($queryTerm) . '%';
+ $qb->andWhere(
+ $qb->expr()->orX(
+ $qb->expr()->iLike('title', $qb->createNamedParameter($likeParameter, IQueryBuilder::PARAM_STR, ':query_term_title')),
+ $qb->expr()->iLike('description', $qb->createNamedParameter($likeParameter, IQueryBuilder::PARAM_STR, ':query_term_description'))
+ )
+ );
+ }
+
return $this->findEntities($qb);
}
diff --git a/lib/Search/FormsSearchResultEntry.php b/lib/Search/FormsSearchResultEntry.php
new file mode 100644
index 000000000..7ddd7cbb3
--- /dev/null
+++ b/lib/Search/FormsSearchResultEntry.php
@@ -0,0 +1,22 @@
+linkToRoute('forms.page.views', ['hash' => $form->getHash(), 'view' => 'submit']);
+ $iconURL = $urlGenerator->getAbsoluteURL(($urlGenerator->imagePath(Application::APP_ID, 'forms-dark.svg')));
+ parent::__construct($iconURL, $form->getTitle(), $form->getDescription(), $formURL, 'icon-forms');
+ }
+}
diff --git a/lib/Search/SearchProvider.php b/lib/Search/SearchProvider.php
new file mode 100644
index 000000000..4b0c2e61b
--- /dev/null
+++ b/lib/Search/SearchProvider.php
@@ -0,0 +1,67 @@
+l10n->t('Forms');
+ }
+
+ public function search(IUser $user, ISearchQuery $query): SearchResult {
+ $forms = $this->formsService->search($query);
+
+ $results = array_map(function (Form $form) {
+ return [
+ 'object' => $form,
+ 'entry' => new FormsSearchResultEntry($form, $this->urlGenerator)
+ ];
+ }, $forms);
+
+ $resultEntries = array_map(function (array $result) {
+ return $result['entry'];
+ }, $results);
+
+ return SearchResult::complete(
+ $this->l10n->t('Forms'),
+ $resultEntries
+ );
+ }
+
+ public function getOrder(string $route, array $routeParameters): int {
+ if (str_contains($route, Application::APP_ID)) {
+ // Active app, prefer my results
+ return -1;
+ }
+ return 77;
+ }
+}
diff --git a/lib/Service/FormsService.php b/lib/Service/FormsService.php
index 55382fc1d..926f5d8df 100644
--- a/lib/Service/FormsService.php
+++ b/lib/Service/FormsService.php
@@ -30,6 +30,7 @@
use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
+use OCP\Search\ISearchQuery;
use OCP\Security\ISecureRandom;
use OCP\Share\IShare;
@@ -743,6 +744,33 @@ public function areExtraSettingsValid(array $extraSettings, string $questionType
return true;
}
+ /**
+ * Get list of forms
+ *
+ * @param ISearchQuery $query the query to search the forms
+ * @return Form[] list of forms that match the query
+ */
+ public function search(ISearchQuery $query): array {
+ $formsList = [];
+ $groups = $this->groupManager->getUserGroupIds($this->currentUser);
+ $teams = $this->circlesService->getUserTeamIds($this->currentUser->getUID());
+
+ try {
+ $ownedForms = $this->formMapper->findAllByOwnerId($this->currentUser->getUID(), $query->getTerm());
+ $sharedForms = $this->formMapper->findSharedForms(
+ $this->currentUser->getUID(),
+ $groups,
+ $teams,
+ true,
+ $query->getTerm()
+ );
+ $formsList = array_merge($ownedForms, $sharedForms);
+ } catch (DoesNotExistException $e) {
+ // silent catch
+ }
+ return $formsList;
+ }
+
public function getFilePath(Form $form): ?string {
$fileId = $form->getFileId();
diff --git a/playwright/support/setup.ts b/playwright/support/setup.ts
index 412d4900f..c85fd2127 100644
--- a/playwright/support/setup.ts
+++ b/playwright/support/setup.ts
@@ -4,7 +4,7 @@
*/
import { test as setup } from '@playwright/test'
-import { configureNextcloud, docker } from '@nextcloud/cypress/docker'
+import { configureNextcloud, getContainer } from '@nextcloud/cypress/docker'
/**
* We use this to ensure Nextcloud is configured correctly before running our tests
@@ -13,7 +13,5 @@ import { configureNextcloud, docker } from '@nextcloud/cypress/docker'
* as that only checks for the URL to be accessible which happens already before everything is configured.
*/
setup('Configure Nextcloud', async () => {
- const containerName = 'nextcloud-cypress-tests_forms'
- const container = docker.getContainer(containerName)
- await configureNextcloud(['forms', 'viewer'], undefined, container)
+ await configureNextcloud(['forms', 'viewer'], undefined, getContainer())
})
diff --git a/playwright/support/utils/session.ts b/playwright/support/utils/session.ts
index 483d82a3a..7038e8c2f 100644
--- a/playwright/support/utils/session.ts
+++ b/playwright/support/utils/session.ts
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-import { docker } from '@nextcloud/cypress/docker'
+import { getContainer } from '@nextcloud/cypress/docker'
import { expect, type APIRequestContext } from '@playwright/test'
/**
@@ -22,8 +22,7 @@ export async function runShell(
env?: Record
},
) {
- const containerName = 'nextcloud-cypress-tests_forms'
- const container = docker.getContainer(containerName)
+ const container = getContainer()
const exec = await container.exec({
Cmd: ['sh', '-c', command],